add ui manager & add a custom dynamic island
This commit is contained in:
parent
b9f46f6cca
commit
81816b12a2
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
package com.tungsten.fcl.ui;
|
||||
|
||||
public class ChildUIManager {
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
|
@ -7,16 +7,19 @@
|
|||
android:id="@+id/background"
|
||||
tools:context=".activity.MainActivity">
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLTitleView
|
||||
android:id="@+id/title"
|
||||
app:title="@string/app_name"
|
||||
android:layout_width="0dp"
|
||||
<com.tungsten.fcllibrary.component.view.FCLUILayout
|
||||
android:id="@+id/ui_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bottom_split"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLDynamicIsland
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="15dp"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintVertical_bias="0"
|
||||
app:layout_constraintWidth_percent="0.75"
|
||||
app:layout_constraintHeight_percent="0.10"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ public abstract class FCLCommonUI extends FCLBaseUI {
|
|||
super(context);
|
||||
setContentView(id);
|
||||
this.parent = parent;
|
||||
onCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue