diff --git a/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.java b/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.java
index d9f820d3..fc3eed6c 100644
--- a/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.java
+++ b/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.java
@@ -6,14 +6,20 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import com.google.android.material.tabs.TabLayout;
import com.tungsten.fcl.R;
+import com.tungsten.fcl.ui.UIManager;
import com.tungsten.fcllibrary.component.FCLActivity;
import com.tungsten.fcllibrary.component.theme.ThemeEngine;
+import com.tungsten.fcllibrary.component.view.FCLDynamicIsland;
import com.tungsten.fcllibrary.component.view.FCLTitleView;
+import com.tungsten.fcllibrary.component.view.FCLUILayout;
public class MainActivity extends FCLActivity implements TabLayout.OnTabSelectedListener {
public ConstraintLayout background;
- private FCLTitleView titleView;
+ private FCLDynamicIsland titleView;
+
+ private UIManager uiManager;
+ private FCLUILayout uiLayout;
private TabLayout tabLayout;
@@ -26,6 +32,11 @@ public class MainActivity extends FCLActivity implements TabLayout.OnTabSelected
background.setBackground(ThemeEngine.getInstance().getTheme().getBackground(this));
titleView = findViewById(R.id.title);
+
+ uiLayout = findViewById(R.id.ui_layout);
+ uiManager = new UIManager(this, uiLayout);
+ uiManager.init();
+
tabLayout = findViewById(R.id.tab_layout);
tabLayout.addOnTabSelectedListener(this);
tabLayout.selectTab(tabLayout.getTabAt(3));
@@ -38,25 +49,26 @@ public class MainActivity extends FCLActivity implements TabLayout.OnTabSelected
public void onTabSelected(TabLayout.Tab tab) {
switch (tab.getPosition()) {
case 0:
- titleView.setTitle(getString(R.string.account));
+ titleView.setTextWithAnim(getString(R.string.account));
break;
case 1:
- titleView.setTitle(getString(R.string.version));
+ titleView.setTextWithAnim(getString(R.string.version));
break;
case 2:
- titleView.setTitle(getString(R.string.install));
+ titleView.setTextWithAnim(getString(R.string.install));
break;
case 4:
- titleView.setTitle(getString(R.string.download));
+ titleView.setTextWithAnim(getString(R.string.download));
break;
case 5:
- titleView.setTitle(getString(R.string.multiplayer));
+ titleView.setTextWithAnim(getString(R.string.multiplayer));
break;
case 6:
- titleView.setTitle(getString(R.string.setting));
+ titleView.setTextWithAnim(getString(R.string.setting));
break;
default:
- titleView.setTitle(getString(R.string.app_name));
+ titleView.setTextWithAnim(getString(R.string.app_name));
+ uiManager.switchUI(uiManager.getMainUI());
break;
}
}
diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/ChildUIManager.java b/FCL/src/main/java/com/tungsten/fcl/ui/ChildUIManager.java
new file mode 100644
index 00000000..90cb3077
--- /dev/null
+++ b/FCL/src/main/java/com/tungsten/fcl/ui/ChildUIManager.java
@@ -0,0 +1,4 @@
+package com.tungsten.fcl.ui;
+
+public class ChildUIManager {
+}
diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/UIManager.java b/FCL/src/main/java/com/tungsten/fcl/ui/UIManager.java
new file mode 100644
index 00000000..da881211
--- /dev/null
+++ b/FCL/src/main/java/com/tungsten/fcl/ui/UIManager.java
@@ -0,0 +1,79 @@
+package com.tungsten.fcl.ui;
+
+import android.content.Context;
+
+import com.tungsten.fcl.R;
+import com.tungsten.fcl.ui.main.MainUI;
+import com.tungsten.fclcore.util.Logging;
+import com.tungsten.fcllibrary.component.ui.FCLBaseUI;
+import com.tungsten.fcllibrary.component.view.FCLUILayout;
+
+import java.util.logging.Level;
+
+public class UIManager {
+
+ private static UIManager instance;
+
+ public static UIManager getInstance() {
+ if (instance == null) {
+ throw new IllegalStateException("UIManager not initialized!");
+ }
+ return instance;
+ }
+
+ private final Context context;
+ private final FCLUILayout parent;
+
+ private MainUI mainUI;
+
+ private FCLBaseUI[] allUIs;
+ private FCLBaseUI currentUI;
+
+ public UIManager(Context context, FCLUILayout parent) {
+ this.context = context;
+ this.parent = parent;
+ }
+
+ public void init() {
+ if (instance != null) {
+ Logging.LOG.log(Level.WARNING, "UIManager already initialized!");
+ return;
+ }
+ instance = this;
+
+ mainUI = new MainUI(context, parent, R.layout.ui_main);
+
+ allUIs = new FCLBaseUI[] {
+ mainUI
+ };
+ }
+
+ public Context getContext() {
+ return context;
+ }
+
+ public FCLUILayout getParent() {
+ return parent;
+ }
+
+ public MainUI getMainUI() {
+ return mainUI;
+ }
+
+ public FCLBaseUI getCurrentUI() {
+ return currentUI;
+ }
+
+ public void switchUI(FCLBaseUI ui) {
+ for (FCLBaseUI baseUI : allUIs) {
+ if (ui == baseUI) {
+ if (currentUI != null) {
+ currentUI.onStop();
+ }
+ ui.onStart();
+ currentUI = ui;
+ break;
+ }
+ }
+ }
+}
diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/main/MainUI.java b/FCL/src/main/java/com/tungsten/fcl/ui/main/MainUI.java
new file mode 100644
index 00000000..02db96d7
--- /dev/null
+++ b/FCL/src/main/java/com/tungsten/fcl/ui/main/MainUI.java
@@ -0,0 +1,18 @@
+package com.tungsten.fcl.ui.main;
+
+import android.content.Context;
+
+import com.tungsten.fcllibrary.component.ui.FCLCommonUI;
+import com.tungsten.fcllibrary.component.view.FCLUILayout;
+
+public class MainUI extends FCLCommonUI {
+
+ public MainUI(Context context, FCLUILayout parent, int id) {
+ super(context, parent, id);
+ }
+
+ @Override
+ public void refresh() {
+
+ }
+}
diff --git a/FCL/src/main/res/layout/activity_main.xml b/FCL/src/main/res/layout/activity_main.xml
index 25150406..5d0abee6 100644
--- a/FCL/src/main/res/layout/activity_main.xml
+++ b/FCL/src/main/res/layout/activity_main.xml
@@ -7,16 +7,19 @@
android:id="@+id/background"
tools:context=".activity.MainActivity">
-
+
+
diff --git a/FCL/src/main/res/layout/ui_main.xml b/FCL/src/main/res/layout/ui_main.xml
new file mode 100644
index 00000000..77d9ef65
--- /dev/null
+++ b/FCL/src/main/res/layout/ui_main.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/FCLLibrary/src/main/java/com/tungsten/fcllibrary/anim/DynamicIslandAnim.java b/FCLLibrary/src/main/java/com/tungsten/fcllibrary/anim/DynamicIslandAnim.java
new file mode 100644
index 00000000..a9c3eddf
--- /dev/null
+++ b/FCLLibrary/src/main/java/com/tungsten/fcllibrary/anim/DynamicIslandAnim.java
@@ -0,0 +1,92 @@
+package com.tungsten.fcllibrary.anim;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+
+import com.tungsten.fcllibrary.component.view.FCLDynamicIsland;
+
+public class DynamicIslandAnim {
+
+ private final FCLDynamicIsland view;
+
+ private ObjectAnimator expandScaleAnimatorX;
+ private ObjectAnimator shrinkScaleAnimatorX;
+ private ObjectAnimator expandScaleAnimatorY;
+ private ObjectAnimator shrinkScaleAnimatorY;
+ private ObjectAnimator expandAdjustAnimatorX;
+ private ObjectAnimator shrinkAdjustAnimatorX;
+ private ObjectAnimator expandAdjustAnimatorY;
+ private ObjectAnimator shrinkAdjustAnimatorY;
+
+ public DynamicIslandAnim(FCLDynamicIsland view) {
+ this.view = view;
+ }
+
+ public void refresh(float scale) {
+ if (expandScaleAnimatorX != null && expandScaleAnimatorX.isRunning()) {
+ expandScaleAnimatorX.cancel();
+ }
+ if (shrinkScaleAnimatorX != null && shrinkScaleAnimatorX.isRunning()) {
+ shrinkScaleAnimatorX.cancel();
+ }
+ if (expandScaleAnimatorY != null && expandScaleAnimatorY.isRunning()) {
+ expandScaleAnimatorY.cancel();
+ }
+ if (shrinkScaleAnimatorY != null && shrinkScaleAnimatorY.isRunning()) {
+ shrinkScaleAnimatorY.cancel();
+ }
+ if (expandAdjustAnimatorX != null && expandAdjustAnimatorX.isRunning()) {
+ expandAdjustAnimatorX.cancel();
+ }
+ if (shrinkAdjustAnimatorX != null && shrinkAdjustAnimatorX.isRunning()) {
+ shrinkAdjustAnimatorX.cancel();
+ }
+ if (expandAdjustAnimatorY != null && expandAdjustAnimatorY.isRunning()) {
+ expandAdjustAnimatorY.cancel();
+ }
+ if (shrinkAdjustAnimatorY != null && shrinkAdjustAnimatorY.isRunning()) {
+ shrinkAdjustAnimatorY.cancel();
+ }
+ expandScaleAnimatorX = ObjectAnimator.ofFloat(view, "scaleX", scale, 0.95f).setDuration(200);
+ shrinkScaleAnimatorX = ObjectAnimator.ofFloat(view, "scaleX", 0.95f, scale).setDuration(200);
+ expandScaleAnimatorY = ObjectAnimator.ofFloat(view, "scaleY", 0.95f, 0.95f).setDuration(200);
+ shrinkScaleAnimatorY = ObjectAnimator.ofFloat(view, "scaleY", 0.95f, 0.95f).setDuration(200);
+ expandAdjustAnimatorX = ObjectAnimator.ofFloat(view, "scaleX", 0.95f, 1f).setDuration(200);
+ shrinkAdjustAnimatorX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.95f).setDuration(200);
+ expandAdjustAnimatorY = ObjectAnimator.ofFloat(view, "scaleY", 0.95f, 1f).setDuration(200);
+ shrinkAdjustAnimatorY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.95f).setDuration(200);
+ }
+
+ public void run(String text) {
+ shrinkScaleAnimatorX.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ view.refresh(text);
+ view.post(() -> {
+ expandScaleAnimatorX.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ expandAdjustAnimatorX.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ shrinkAdjustAnimatorX.start();
+ shrinkAdjustAnimatorY.start();
+ }
+ });
+ expandAdjustAnimatorX.start();
+ expandAdjustAnimatorY.start();
+ }
+ });
+ expandScaleAnimatorX.start();
+ expandScaleAnimatorY.start();
+ });
+ }
+ });
+ shrinkScaleAnimatorX.start();
+ shrinkScaleAnimatorY.start();
+ }
+}
diff --git a/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/ui/FCLCommonUI.java b/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/ui/FCLCommonUI.java
index 76ea0f2f..17c14d1d 100644
--- a/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/ui/FCLCommonUI.java
+++ b/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/ui/FCLCommonUI.java
@@ -18,6 +18,7 @@ public abstract class FCLCommonUI extends FCLBaseUI {
super(context);
setContentView(id);
this.parent = parent;
+ onCreate();
}
@Override
diff --git a/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/view/FCLDynamicIsland.java b/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/view/FCLDynamicIsland.java
new file mode 100644
index 00000000..a1fe4091
--- /dev/null
+++ b/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/view/FCLDynamicIsland.java
@@ -0,0 +1,116 @@
+package com.tungsten.fcllibrary.component.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.util.AttributeSet;
+import android.view.Gravity;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.widget.AppCompatTextView;
+
+import com.tungsten.fcllibrary.anim.DynamicIslandAnim;
+import com.tungsten.fcllibrary.component.theme.ThemeEngine;
+import com.tungsten.fcllibrary.util.ConvertUtils;
+
+public class FCLDynamicIsland extends AppCompatTextView {
+
+ DynamicIslandAnim anim;
+
+ private Path outlinePath;
+ private Paint outlinePaint;
+ private Paint insidePaint;
+ private Paint textPaint;
+
+ private final Runnable runnable = () -> {
+ outlinePaint.setAntiAlias(true);
+ outlinePaint.setColor(ThemeEngine.getInstance().getTheme().getDkColor());
+ outlinePaint.setStyle(Paint.Style.STROKE);
+ outlinePaint.setStrokeWidth(ConvertUtils.dip2px(getContext(), 3));
+ insidePaint.setAntiAlias(true);
+ insidePaint.setColor(ThemeEngine.getInstance().getTheme().getColor());
+ insidePaint.setStyle(Paint.Style.FILL);
+ textPaint.setAntiAlias(true);
+ textPaint.setStyle(Paint.Style.FILL);
+ textPaint.setTextSize(56);
+ textPaint.setColor(ThemeEngine.getInstance().getTheme().getAutoTint());
+ textPaint.setTextAlign(Paint.Align.CENTER);
+ invalidate();
+ setTextColor(ThemeEngine.getInstance().getTheme().getAutoTint());
+ };
+
+ private void init() {
+ anim = new DynamicIslandAnim(this);
+ setGravity(Gravity.CENTER);
+ int tb = ConvertUtils.dip2px(getContext(), 8f);
+ int lr = ConvertUtils.dip2px(getContext(), 18f);
+ setPadding(lr, tb, lr, tb);
+ outlinePath = new Path();
+ outlinePaint = new Paint();
+ insidePaint = new Paint();
+ textPaint = new Paint();
+ outlinePaint.setAntiAlias(true);
+ outlinePaint.setColor(ThemeEngine.getInstance().getTheme().getDkColor());
+ outlinePaint.setStyle(Paint.Style.STROKE);
+ outlinePaint.setStrokeWidth(ConvertUtils.dip2px(getContext(), 3));
+ insidePaint.setAntiAlias(true);
+ insidePaint.setColor(ThemeEngine.getInstance().getTheme().getColor());
+ insidePaint.setStyle(Paint.Style.FILL);
+ textPaint.setAntiAlias(true);
+ textPaint.setStyle(Paint.Style.FILL);
+ textPaint.setTextSize(56);
+ textPaint.setColor(ThemeEngine.getInstance().getTheme().getAutoTint());
+ textPaint.setTextAlign(Paint.Align.CENTER);
+ }
+
+ public FCLDynamicIsland(@NonNull Context context) {
+ super(context);
+ init();
+ ThemeEngine.getInstance().registerEvent(this, runnable);
+ }
+
+ public FCLDynamicIsland(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ ThemeEngine.getInstance().registerEvent(this, runnable);
+ }
+
+ public FCLDynamicIsland(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ ThemeEngine.getInstance().registerEvent(this, runnable);
+ }
+
+ @SuppressLint("DrawAllocation")
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ float offset = ConvertUtils.dip2px(getContext(), 1.5f);
+ float width = getMeasuredWidth() - 2 * offset;
+ float height = getMeasuredHeight() - 2 * offset;
+ outlinePath = new Path();
+ outlinePath.moveTo(offset + (height / 2), offset);
+ outlinePath.arcTo(offset, offset, offset + height, offset + height, 270, -180, false);
+ outlinePath.lineTo(offset + width - (height / 2), height + offset);
+ outlinePath.arcTo(offset + width - height, offset, width + offset, height + offset, 90, -180, false);
+ outlinePath.lineTo(offset + (height / 2), offset);
+ canvas.drawPath(outlinePath, insidePaint);
+ canvas.drawPath(outlinePath, outlinePaint);
+ canvas.drawText(getText().toString(), (int) (getWidth() / 2), (int) (getHeight() / 2) + 21, textPaint);
+ }
+
+ public void refresh(String text) {
+ setText(text);
+ invalidate();
+ }
+
+ public void setTextWithAnim(String text) {
+ post(() -> {
+ anim.refresh((float) getMeasuredHeight() / (float) getMeasuredWidth());
+ anim.run(text);
+ });
+ }
+}