Add labels and animations to the tab bar

This commit is contained in:
Grishka
2024-02-24 23:03:18 +03:00
parent b3e53bc48d
commit 1e501c707c
16 changed files with 293 additions and 49 deletions

View File

@@ -0,0 +1,37 @@
package org.joinmastodon.android.ui;
import android.graphics.Typeface;
import android.os.Build;
import android.util.Property;
import android.widget.TextView;
import androidx.annotation.RequiresApi;
public class ViewProperties{
public static final Property<TextView, Integer> FONT_WEIGHT=new Property<>(Integer.class, "fontWeight"){
@RequiresApi(api = Build.VERSION_CODES.P)
@Override
public Integer get(TextView object){
return object.getTypeface().getWeight();
}
@RequiresApi(api = Build.VERSION_CODES.P)
@Override
public void set(TextView object, Integer value){
// typeface objects are cached internally, I looked at AOSP sources to confirm that
object.setTypeface(Typeface.create(null, value, false));
}
};
public static final Property<TextView, Integer> TEXT_COLOR=new Property<>(Integer.class, "textColor"){
@Override
public Integer get(TextView object){
return object.getCurrentTextColor();
}
@Override
public void set(TextView object, Integer value){
object.setTextColor(value);
}
};
}

View File

@@ -1,20 +1,35 @@
package org.joinmastodon.android.ui.views;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.ui.ViewProperties;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.util.ArrayList;
import java.util.function.IntConsumer;
import java.util.function.IntPredicate;
import androidx.annotation.IdRes;
import me.grishka.appkit.utils.CubicBezierInterpolator;
public class TabBar extends LinearLayout{
@IdRes
private int selectedTabID;
private IntConsumer listener;
private IntPredicate longClickListener;
private Typeface mediumFont=Typeface.create("sans-serif-medium", Typeface.NORMAL), boldFont=Typeface.DEFAULT_BOLD;
public TabBar(Context context){
this(context, null);
@@ -32,9 +47,14 @@ public class TabBar extends LinearLayout{
public void onViewAdded(View child){
super.onViewAdded(child);
if(child.getId()!=0){
ViewHolder holder=new ViewHolder();
holder.label=child.findViewById(R.id.label);
child.setTag(holder);
if(selectedTabID==0){
selectedTabID=child.getId();
child.setSelected(true);
setTabSelected(child, true);
}else{
holder.label.setTypeface(mediumFont);
}
child.setOnClickListener(this::onChildClick);
child.setOnLongClickListener(this::onChildLongClick);
@@ -45,8 +65,8 @@ public class TabBar extends LinearLayout{
listener.accept(v.getId());
if(v.getId()==selectedTabID)
return;
findViewById(selectedTabID).setSelected(false);
v.setSelected(true);
setTabSelected(findViewById(selectedTabID), false);
setTabSelected(v, true);
selectedTabID=v.getId();
}
@@ -60,8 +80,40 @@ public class TabBar extends LinearLayout{
}
public void selectTab(int id){
findViewById(selectedTabID).setSelected(false);
setTabSelected(findViewById(selectedTabID), false);
selectedTabID=id;
findViewById(selectedTabID).setSelected(true);
setTabSelected(findViewById(selectedTabID), true);
}
private void setTabSelected(View tab, boolean selected){
tab.setSelected(selected);
ViewHolder holder=(ViewHolder) tab.getTag();
if(holder.currentAnim!=null)
holder.currentAnim.cancel();
ArrayList<Animator> anims=new ArrayList<>();
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.P){
anims.add(ObjectAnimator.ofInt(holder.label, ViewProperties.FONT_WEIGHT, selected ? 700 : 500));
}else{
holder.label.setTypeface(selected ? boldFont : mediumFont);
}
anims.add(ObjectAnimator.ofArgb(holder.label, ViewProperties.TEXT_COLOR, UiUtils.getThemeColor(getContext(), selected ? R.attr.colorM3OnSurface : R.attr.colorM3OnSurfaceVariant)));
AnimatorSet set=new AnimatorSet();
set.playTogether(anims);
set.setDuration(400);
// set.setInterpolator(AnimationUtils.loadInterpolator(getContext(), R.interpolator.m3_sys_motion_easing_standard));
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
holder.currentAnim=set;
set.addListener(new AnimatorListenerAdapter(){
@Override
public void onAnimationEnd(Animator animation){
holder.currentAnim=null;
}
});
set.start();
}
private static class ViewHolder{
public TextView label;
public Animator currentAnim;
}
}