自定义ViewFlipper 实现滚动效果

来源:互联网 发布:四柱算命软件 编辑:程序博客网 时间:2024/05/21 19:38

自定义view实现了类似百度手机助手,首页评论滚动效果。

看效果:


gif做的不好,其效果就是:几个viewitem不停的向上滚动,新加入item有个淡入的效果。


说下实现思路:自定义view继承至LinearLayout,控制item数量及其动画效果,实现item复用,传入数据即可,使用方便。

代码:

/** * Jiantao.Yang * * @description 仿百度手机助手,评论滚动效果 * @time 2015/1/16 17:37 */public class ViewFlipper extends LinearLayout {    private final int MAX_SHOW_ITEM_SIZE = 5;    private IAdapter mIAdapter;    private int mCount;    //最后一个item动画    private Animation mLastOneAnimation;    //其它item动画    private Animation mCommonAnimation;    //数据下标    private int mCurrentIndex;    /**     * 这里动画时间是1600毫秒,所以间隔得大于动画时间     */    private static final int DEFAULT_INTERVAL = 2000;    private int mFlipInterval = DEFAULT_INTERVAL;    private boolean mAutoStart = false;    private boolean mRunning = false;    private boolean mStarted = false;    private boolean mVisible = false;    private boolean mUserPresent = true;    public ViewFlipper(Context context) {        super(context);        init(context);    }    public ViewFlipper(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    public ViewFlipper(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context);    }    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {        @Override        public void onReceive(Context context, Intent intent) {            final String action = intent.getAction();            if (Intent.ACTION_SCREEN_OFF.equals(action)) {                mUserPresent = false;                updateRunning();            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {                mUserPresent = true;                updateRunning(false);            }        }    };    @Override    protected void onAttachedToWindow() {        super.onAttachedToWindow();        // Listen for broadcasts related to user-presence        final IntentFilter filter = new IntentFilter();        filter.addAction(Intent.ACTION_SCREEN_OFF);        filter.addAction(Intent.ACTION_USER_PRESENT);        // OK, this is gross but needed. This class is supported by the        // remote views machanism and as a part of that the remote views        // can be inflated by a context for another user without the app        // having interact users permission - just for loading resources.        // For exmaple, when adding widgets from a user profile to the        // home screen. Therefore, we register the receiver as the current        // user not the one the context is for.        getContext().registerReceiver(mReceiver, filter);        if (mAutoStart) {            // Automatically start when requested            startFlipping();        }    }    @Override    protected void onDetachedFromWindow() {        super.onDetachedFromWindow();        mVisible = false;        getContext().unregisterReceiver(mReceiver);        updateRunning();    }    @Override    protected void onWindowVisibilityChanged(int visibility) {        super.onWindowVisibilityChanged(visibility);        mVisible = visibility == VISIBLE;        updateRunning(mVisible);//        updateRunning(false);    }    private void init(Context context) {        this.setOrientation(LinearLayout.VERTICAL);    }    public void setIAdapter(IAdapter iAdapter) {        this.mIAdapter = iAdapter;        initShowItems();    }    public void startFlipping() {        mStarted = true;        updateRunning();    }    public void stopFlipping() {        mStarted = false;        updateRunning();    }    private void updateRunning() {        updateRunning(true);    }    /**     * Returns true if the child views are flipping.     */    public boolean isFlipping() {        return mStarted;    }    /**     * Set if this view automatically calls {@link #startFlipping()} when it     * becomes attached to a window.     */    public void setAutoStart(boolean autoStart) {        mAutoStart = autoStart;    }    /**     * Returns true if this view automatically calls {@link #startFlipping()}     * when it becomes attached to a window.     */    public boolean isAutoStart() {        return mAutoStart;    }    @Override    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {        super.onInitializeAccessibilityEvent(event);        event.setClassName(ViewFlipper.class.getName());    }    @Override    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {        super.onInitializeAccessibilityNodeInfo(info);        info.setClassName(ViewFlipper.class.getName());    }    /**     * 初始化childViews     */    private void initShowItems() {        if (mIAdapter != null) {            mCount = mIAdapter.getCount();            for (int i = 0; i < mCount; i++) {                if (i == MAX_SHOW_ITEM_SIZE) {                    break;                }                View convertView = getChildAt(i);                View item = mIAdapter.getItemView(convertView, i);                addView(item, i);            }        }    }    /**     * Internal method to start or stop dispatching flip {@link android.os.Message} based     * on {@link #mRunning} and {@link #mVisible} state.     *     * @param flipNow Determines whether or not to execute the animation now, in     *                addition to queuing future flips. If omitted, defaults to     *                true.     */    private void updateRunning(boolean flipNow) {        boolean running = mVisible && mStarted && mUserPresent;        System.out.println(" updateRunning running:" + running + " mVisible " + mVisible + " userPresent " + mUserPresent);        if (running != mRunning) {            if (running && (mCount > MAX_SHOW_ITEM_SIZE)) {                showItems(mCurrentIndex++, flipNow);                Message msg = mHandler.obtainMessage(FLIP_MSG);                mHandler.sendMessageDelayed(msg, mFlipInterval);            } else {                mHandler.removeMessages(FLIP_MSG);            }            mRunning = running;        }    }    private void showItems(final int position, boolean animate) {        if (animate && (mLastOneAnimation == null || mCommonAnimation == null)) {            mLastOneAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.lastone_anim);            mCommonAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.common_anim);        }        int childCount = getChildCount();        for (int i = 0; i < childCount; i++) {            View child = getChildAt(i);            child.clearAnimation();            int index = position + i;            child = mIAdapter.getItemView(child, (index >= mIAdapter.getCount()) ? (index - mIAdapter.getCount()) : index);            if (animate) {                if (i == childCount - 1) {                    child.setAnimation(mLastOneAnimation);                } else {                    child.setAnimation(mCommonAnimation);                }            }            child.setVisibility(View.VISIBLE);        }        if (animate) {            mCommonAnimation.startNow();            mLastOneAnimation.startNow();        }        //保证传入的position小于getCount        if (mCurrentIndex >= mIAdapter.getCount()) {            mCurrentIndex = 0;        }    }    private final int FLIP_MSG = 1;    private final Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            if (msg.what == FLIP_MSG) {                if (mRunning) {                    showItems(mCurrentIndex++, true);                    msg = obtainMessage(FLIP_MSG);                    sendMessageDelayed(msg, mFlipInterval);                }            }        }    };    public interface IAdapter {        /**         * @param convertView         * @param position         * @return         */        public View getItemView(View convertView, int position);        /**         * @return 数据count         */        public int getCount();    }}

再来看看调用部分:

public class MainActivity extends ActionBarActivity implements ViewFlipper.IAdapter {    ViewFlipper viewFlipper;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        viewFlipper = (ViewFlipper) findViewById(R.id.view_flipper);        viewFlipper.setIAdapter(this);    }    @Override    protected void onResume() {        super.onResume();        viewFlipper.startFlipping();    }    @Override    public View getItemView(View convertView, int position) {        View item = null;        TextView textView;        if (convertView == null) {            item = View.inflate(this, R.layout.item, null);        } else {            item = convertView;        }        textView = (TextView) item.findViewById(R.id.textview);        textView.setText("测试数据:" + position);        return item;    }    @Override    public int getCount() {        return 8;    }}

可以看出,MainActivity实现了ViewFlipper.IAdapter接口,setAdapter后调用startFlipper即可。


这里布局文件我就不贴出来了,附上工程源码,项目里动画时间有点长,修改下就ok。


限于水平有限,不足之处难免,望各位不舍指正,与君共勉。

0 0
原创粉丝点击