Android开发首页底部tab切换图标有动画效果
主页tab切换很正常,但往往加上写动画更好看
一、思路:
用属性动画,并且事先准备多张图片,用于切换后播放动画
二、效果图:
单纯图看不出来,看下视频效果
Android开发教程实战案例源码分享-首页底部tab切换图标有动画效果
三、关键代码:
public class TabButtonGroup extends LinearLayout implements View.OnClickListener {
private TabButton[] mTabButtons;
private ViewPager mViewPager;
private int mCurPosition;
public TabButtonGroup(Context context) {
this(context, null);
}
public TabButtonGroup(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public TabButtonGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
int childCount = getChildCount();
if (childCount > 0) {
mTabButtons = new TabButton[childCount];
for (int i = 0; i < childCount; i++) {
View v = getChildAt(i);
v.setTag(i);
v.setOnClickListener(this);
mTabButtons[i] = (TabButton) v;
}
}
}
public void setCurPosition(int position) {
if (position == mCurPosition) {
return;
}
if (mClickIntercepter != null && mClickIntercepter.needIntercept(position)) {
return;
}
mTabButtons[mCurPosition].setChecked(false);
mTabButtons[position].setChecked(true);
mCurPosition = position;
if (mViewPager != null) {
mViewPager.setCurrentItem(position, false);
}
}
@Override
public void onClick(View v) {
Object tag = v.getTag();
if (tag != null) {
setCurPosition((int) tag);
}
}
public void setViewPager(ViewPager viewPager) {
mViewPager = viewPager;
}
public void cancelAnim() {
if (mTabButtons != null) {
for (TabButton tbn : mTabButtons) {
if (tbn != null) {
tbn.cancelAnim();
}
}
}
}
public ClickIntercepter mClickIntercepter;
public void setClickIntercepter(ClickIntercepter intercepter) {
mClickIntercepter = intercepter;
}
public interface ClickIntercepter {
boolean needIntercept(int position);
}
public void btnPerformClick(int position){
if (mTabButtons != null&&mTabButtons[position]!=null) {
mTabButtons[position].performClick();
}
}
}
public class TabButton extends LinearLayout {
private Context mContext;
private float mScale;
private String mTip;
private int mIconSize;
private int mTextSize;
private int mTextColorChecked;
private int mTextColorUnChecked;
private boolean mChecked;
private ImageView mImg;
private TextView mText;
private Drawable[] mDrawables;
private int mDrawaleArrayLength;
private ValueAnimator mAnimator;
private int mDrawableIndex;
public TabButton(Context context) {
this(context, null);
}
public TabButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TabButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
mScale = context.getResources().getDisplayMetrics().density;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TabButton);
int iconArrayId = ta.getResourceId(R.styleable.TabButton_tbn_icon_array_id, 0);
mTip = ta.getString(R.styleable.TabButton_tbn_tip);
mIconSize = (int) ta.getDimension(R.styleable.TabButton_tbn_icon_size, 0);
mTextSize = (int) ta.getDimension(R.styleable.TabButton_tbn_text_size, 0);
mTextColorChecked = ta.getColor(R.styleable.TabButton_tbn_text_color_checked, 0);
mTextColorUnChecked = ta.getColor(R.styleable.TabButton_tbn_text_color_unchecked, 0);
mChecked = ta.getBoolean(R.styleable.TabButton_tbn_checked, false);
ta.recycle();
if (iconArrayId != 0) {
TypedArray arr = getResources().obtainTypedArray(iconArrayId);
int len = arr.length();
int[] iconResArray = new int[len];
for (int i = 0; i < len; i++) {
iconResArray[i] = arr.getResourceId(i, 0);
}
arr.recycle();
mDrawaleArrayLength = iconResArray.length;
if (mDrawaleArrayLength > 0) {
mDrawables = new Drawable[mDrawaleArrayLength];
for (int i = 0; i < mDrawaleArrayLength; i++) {
mDrawables[i] = ContextCompat.getDrawable(context, iconResArray[i]);
}
}
}
mAnimator = ValueAnimator.ofFloat(1, mDrawaleArrayLength - 1);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float v = (float) animation.getAnimatedValue();
int index = (int) v;
if (mDrawableIndex != index) {
mDrawableIndex = index;
if (mImg != null) {
mImg.setImageDrawable(mDrawables[index]);
}
}
}
});
mAnimator.setDuration(500);
mAnimator.setInterpolator(new LinearInterpolator());
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
setOrientation(VERTICAL);
setGravity(Gravity.CENTER_HORIZONTAL);
mImg = new ImageView(mContext);
LayoutParams params1 = new LayoutParams(mIconSize, mIconSize);
params1.setMargins(0, dp2px(4), 0, 0);
mImg.setLayoutParams(params1);
if (mDrawables != null && mDrawaleArrayLength > 0) {
if (mChecked) {
mImg.setImageDrawable(mDrawables[mDrawaleArrayLength - 1]);
} else {
mImg.setImageDrawable(mDrawables[0]);
}
}
mText = new TextView(mContext);
LayoutParams params2 = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mText.setLayoutParams(params2);
mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
mText.setText(mTip);
mText.setTextColor(mChecked ? mTextColorChecked : mTextColorUnChecked);
addView(mImg);
addView(mText);
}
public void setChecked(boolean checked) {
mChecked = checked;
if (mDrawables != null && mDrawaleArrayLength > 0) {
if (mChecked) {
if (mText != null) {
mText.setTextColor(mTextColorChecked);
}
if (mAnimator != null) {
mAnimator.start();
}
} else {
if (mAnimator != null) {
mAnimator.cancel();
}
if (mImg != null) {
mImg.setImageDrawable(mDrawables[0]);
}
if (mText != null) {
mText.setTextColor(mTextColorUnChecked);
}
}
}
}
private int dp2px(int dpVal) {
return (int) (mScale * dpVal + 0.5f);
}
public void cancelAnim() {
if (mAnimator != null) {
mAnimator.cancel();
mAnimator.removeAllUpdateListeners();
}
}
}
四、项目demo源码结构图:
有问题或者需要完整源码的私信我