仿网易快讯栏目滑动TAB效果
仿网易新闻栏目滑动TAB效果
网易新闻这种滑动TAB效果,在android软件中还是比较常见的(是不是原创我不清楚,仅当学习研究之用~~~)。
比较常见的做法是:在FrameLayout里包装TAB bar,再在FrameLayout加一个虚拟的tab,切换tab时用虚拟tab在之前选中和当前选中的tab距离之间做一个移动动画。
用此种方法的十之八九,但在复杂的布局中FrameLayout不是你想加就能加滴,加了很容易崩溃滴^_^,此法的劣势大家明了吧?不明那就慢慢明吧。
今天我采用一种更加高效、灵活的方法来实现这种大家喜欢的花样--自画控件+Drawable动画。
大体原理跟FrameLayout加虚拟tab类似,以下是基本的实现方法:在切换tab时在之前选中的tab和当前选中的tab,做一个drawable移动动画。这个 drawable 就是当前选中tab的画面。
下面是我重载RadioGoup做的tab bar并实现了滑动效果的类
public class NewsRadioGroup extends RadioGroup implements OnCheckedChangeListener { private final Transformation mTransformation = new Transformation(); private Animation mAnimation; private OnCheckedChangeListener mOnCheckedChangeListener; private int mLastCheckedId = -1; private Drawable mDummy; private Drawable mDrawableNormal,mDrawableChecked; private boolean mAminDoing=false; public NewsRadioGroup(Context context) { super(context); init(); } public NewsRadioGroup(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { super.setOnCheckedChangeListener(this); mLastCheckedId = super.getCheckedRadioButtonId(); mDummy = getResources().getDrawable(R.drawable.rb_checked); mDrawableNormal = getResources().getDrawable(android.R.color.transparent); } public void onCheckedChanged(RadioGroup group, int checkedId) { if (mLastCheckedId != -1) { doAmin(checkedId); }else{ mLastCheckedId = checkedId; } if (mOnCheckedChangeListener != null) { mOnCheckedChangeListener.onCheckedChanged(group, checkedId); } } private void doAmin( int checkedId){ RadioButton rbCurChecked = (RadioButton) super.findViewById(checkedId), rbLastChecked = (RadioButton) super.findViewById(mLastCheckedId); if(rbCurChecked==null||rbLastChecked==null){ mLastCheckedId=checkedId; return; } int X1=rbLastChecked.getLeft(),X2=rbCurChecked.getLeft(); if (X1 <= 0 && X2 <= 0) { mLastCheckedId=checkedId; return; } if (mDrawableChecked == null) { mDrawableChecked = rbCurChecked.getBackground(); mDummy.setBounds(0, 0, rbCurChecked.getWidth(), rbCurChecked.getHeight()); } rbCurChecked.setBackgroundDrawable(mDrawableNormal); if(mAminDoing && mAnimation!=null){ mAnimation.reset(); } mAnimation = new TranslateAnimation(X1,X2, rbCurChecked.getTop(), rbCurChecked.getTop()); mAnimation.setDuration(300); mAnimation.initialize(0, 0, 0, 0); mAminDoing=true; mAnimation.startNow(); invalidate(); } public void setOnCheckedChangeListener(OnCheckedChangeListener listener) { mOnCheckedChangeListener = listener; } protected void onDraw(Canvas canvas) { if (mAnimation == null || !mAminDoing) { return; } if (!mAnimation.hasEnded()) { int sc = canvas.save(); mAnimation.getTransformation( AnimationUtils.currentAnimationTimeMillis(), mTransformation); canvas.concat(mTransformation.getMatrix()); mDummy.draw(canvas); canvas.restoreToCount(sc); invalidate(); } else { mAminDoing=false; setReallyCheck(); } } private void setReallyCheck() { if (mLastCheckedId != -1) { super.findViewById(mLastCheckedId).setBackgroundDrawable(mDrawableNormal); } mLastCheckedId = super.getCheckedRadioButtonId(); if (mLastCheckedId != -1) { super.findViewById(mLastCheckedId).setBackgroundDrawable(mDrawableChecked); } } }// end class NesRadioGroup
之前以为只要重写RadioGroup的check方法就可以拦截选中,没想到RadioGroup把实际的选中执行实现在setCheckxx里面,而这个函数是私有方法,最后绕了不小的圈子。
代码在上,具体的效果请见demo~~