android 实现自动滚动的 Banner 横幅

来源:互联网 发布:中国水平知乎 编辑:程序博客网 时间:2024/04/28 20:18

很多音乐播放器如qq音乐,kugou音乐等都有一个专辑推荐的那个横幅,它扩展了软件的空间,也为用户带来了更好的交互感受。

在此,我也模仿着实现了此效果,不足之处请大家见谅,欢迎提出问题,和大家一起学习。

我给他取名叫【BannerLayout】,主要是觉得它也如其他layout特性差不多吧。

复制代码
public class BannerLayout extends ViewGroup {public BannerLayout(Context context) {        super(context);        // TODO Auto-generated constructor stub    }    public BannerLayout(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        // TODO Auto-generated constructor stub    }    public BannerLayout(Context context, AttributeSet attrs) {        super(context, attrs);        // TODO Auto-generated constructor stub    }}
复制代码
BannerLayout 继承与 ViewGroup. 
这个BannerLayout可以自动滚动,所以我们需要一个滚动器Scroller .
this.scroller = new Scroller(context, new DecelerateInterpolator(2));

我给scroller设置了一个插值器DecelerateInterpolator,就可以再滚动的时候实现滚动速度是中间快,开始和结束的时候慢的效果,个人觉得这个效果显得比较优雅。

要实现自动滚动,因此,我们可以使用handler还帮我们起到计时的作用。此外也可以使用timer等其他方式。

复制代码
private Handler handler=new Handler()    {        @Override        public void handleMessage(Message msg) {
       //autoScroll是一标志boolean亮,用来标志是否需要滚动,因此就能手动控制其滚动了,
if(autoScroll && currentWhat==msg.what) { currentScreenIndex=(currentScreenIndex+1)%getChildCount(); scrollToScreen(currentScreenIndex); Log.i("TAG","handleMessage scrollToScreen:"+currentScreenIndex); if(autoScroll)//给自身发送延时消息, handler.sendEmptyMessageDelayed(currentWhat, scrollTime); } } };
复制代码

由于BannerLayout里面的子元素如图片都是水平布局的,所以我们需要手动控制它们在此布局的位置了,

重写onMeasure函数:

复制代码
@Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int maxHeight=-1;                final int count = getChildCount();        for (int i = 0; i < count; i++) {            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);                        maxHeight=Math.max(maxHeight, getChildAt(i).getMeasuredHeight());                    }
// maxHeight
=Math.min(maxHeight, MeasureSpec.getSize(heightMeasureSpec)); Log.e("TAG","onMeasure Height:"+maxHeight); setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),maxHeight); }
复制代码
复制代码
@Override    protected void onLayout(boolean changed, int left, int top, int right,            int bottom) {        final int count = getChildCount();        int cLeft = 0;                        for (int i = 0; i < count; i++) {            View child = getChildAt(i);            if (child.getVisibility() == View.GONE)                continue;            //            child.setVisibility(View.VISIBLE);            final int childWidth = child.getMeasuredWidth();            child.layout(cLeft, 0, cLeft +childWidth, child.getMeasuredHeight());            cLeft += childWidth;        }    }
复制代码

此外,我们需要处理用户触摸事件,实现用户按下的时候停止滚动,用户拖动的时候能够随之移动,

复制代码
@Override    public boolean onTouchEvent(MotionEvent ev) {        if (getChildCount() == 0)            return false;        final int action = ev.getAction();        final float x = ev.getX();        switch (action) {        case MotionEvent.ACTION_DOWN:            autoScroll=false;                        currentWhat++;                        mLastMotionX = x;            if (!scroller.isFinished()) {                scroller.abortAnimation();            }            //            Log.i("TAG","ACTION_DOWN");                        return true;        case MotionEvent.ACTION_MOVE:            final int deltaX = (int) (mLastMotionX - x);//            boolean xMoved = Math.abs(deltaX) > mTouchSlop;            mLastMotionX = x;                        if((0==currentScreenIndex && deltaX<0) || (getChildCount()-1==currentScreenIndex && deltaX>0))                scrollBy(deltaX/4, 0);//此处实现了越界时候的阻尼效果            else//            Log.i("TAG","ACTION_MOVE");//            if (xMoved)                scrollBy(deltaX, 0);                                    final int screenWidth = getWidth();            currentScreenIndex=(getScrollX() + (screenWidth / 2))/ screenWidth;                        return true;        case MotionEvent.ACTION_UP:            snapToDestination();                        if(!autoScroll)            {                autoScroll=true;                handler.sendEmptyMessageDelayed(currentWhat, scrollTime);            }            break;        case MotionEvent.ACTION_CANCEL:            snapToDestination();            if(!autoScroll)            {                autoScroll=true;                handler.sendEmptyMessageDelayed(currentWhat, scrollTime);            }                    }        return false;    }
复制代码

接下来,我们需要实现自定滚动到某一屏的效果:

复制代码
private void scrollToScreen(int whichScreen)    {//        if (!scroller.isFinished())//            return;//        Log.e("TAG","scrollToScreen:"+whichScreen);        int delta = 0;                delta = whichScreen * getWidth() - getScrollX();        //        scroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2);        scroller.startScroll(getScrollX(), 0, delta, 0, 1500);        invalidate();                currentScreenIndex=whichScreen;    }    private void snapToDestination()    {        final int x=getScrollX();        final int screenWidth = getWidth();                scrollToScreen((x + (screenWidth / 2))/ screenWidth);    }
复制代码

差不多就这些了,其实挺简单的,哈哈

下面是全部代码:

复制代码
public class BannerLayout extends ViewGroup {    private Scroller scroller;    private float mLastMotionX;//    private int mTouchSlop;    private int currentScreenIndex=0;        private boolean autoScroll=true;        private int scrollTime=3*1000;        private int currentWhat=0;        private Handler handler=new Handler()    {        @Override        public void handleMessage(Message msg) {            if(autoScroll && currentWhat==msg.what)            {                currentScreenIndex=(currentScreenIndex+1)%getChildCount();                scrollToScreen(currentScreenIndex);                                Log.i("TAG","handleMessage scrollToScreen:"+currentScreenIndex);                                if(autoScroll)                    handler.sendEmptyMessageDelayed(currentWhat, scrollTime);            }        }    };        public BannerLayout(Context context) {        super(context);        initView(context);        // TODO Auto-generated constructor stub    }    public BannerLayout(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        // TODO Auto-generated constructor stub        initView(context);    }    public BannerLayout(Context context, AttributeSet attrs) {        super(context, attrs);        initView(context);        // TODO Auto-generated constructor stub    }    private void initView(final Context context) {        this.scroller = new Scroller(context, new DecelerateInterpolator(2));//OvershootInterpolator(1.1f)                handler.sendEmptyMessageDelayed(currentWhat, scrollTime);        //        final ViewConfiguration configuration = ViewConfiguration//                .get(getContext());//        mTouchSlop = configuration.getScaledTouchSlop();    }        @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int maxHeight=-1;                final int count = getChildCount();        for (int i = 0; i < count; i++) {            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);                        maxHeight=Math.max(maxHeight, getChildAt(i).getMeasuredHeight());                    }        maxHeight=Math.min(maxHeight, MeasureSpec.getSize(heightMeasureSpec));                Log.e("TAG","onMeasure Height:"+maxHeight);                setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),maxHeight);    }    @Override    protected void onLayout(boolean changed, int left, int top, int right,            int bottom) {        final int count = getChildCount();        int cLeft = 0;                        for (int i = 0; i < count; i++) {            View child = getChildAt(i);            if (child.getVisibility() == View.GONE)                continue;            //            child.setVisibility(View.VISIBLE);            final int childWidth = child.getMeasuredWidth();            child.layout(cLeft, 0, cLeft +childWidth, child.getMeasuredHeight());            cLeft += childWidth;        }    }    @Override    public void computeScroll() {        if (scroller.computeScrollOffset()) {            scrollTo(scroller.getCurrX(), 0);            postInvalidate();        }    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        if (getChildCount() == 0)            return false;        final int action = ev.getAction();        final float x = ev.getX();        switch (action) {        case MotionEvent.ACTION_DOWN:            autoScroll=false;                        currentWhat++;                        mLastMotionX = x;            if (!scroller.isFinished()) {                scroller.abortAnimation();            }            //            Log.i("TAG","ACTION_DOWN");                        return true;        case MotionEvent.ACTION_MOVE:            final int deltaX = (int) (mLastMotionX - x);//            boolean xMoved = Math.abs(deltaX) > mTouchSlop;            mLastMotionX = x;                        if((0==currentScreenIndex && deltaX<0) || (getChildCount()-1==currentScreenIndex && deltaX>0))                scrollBy(deltaX/4, 0);            else//            Log.i("TAG","ACTION_MOVE");//            if (xMoved)                scrollBy(deltaX, 0);                                    final int screenWidth = getWidth();            currentScreenIndex=(getScrollX() + (screenWidth / 2))/ screenWidth;                        return true;        case MotionEvent.ACTION_UP:            snapToDestination();                        if(!autoScroll)            {                autoScroll=true;                handler.sendEmptyMessageDelayed(currentWhat, scrollTime);            }            break;        case MotionEvent.ACTION_CANCEL:            snapToDestination();            if(!autoScroll)            {                autoScroll=true;                handler.sendEmptyMessageDelayed(currentWhat, scrollTime);            }                    }        return false;    }    private void scrollToScreen(int whichScreen)    {//        if (!scroller.isFinished())//            return;//        Log.e("TAG","scrollToScreen:"+whichScreen);        int delta = 0;                delta = whichScreen * getWidth() - getScrollX();        //        scroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2);        scroller.startScroll(getScrollX(), 0, delta, 0, 1500);        invalidate();                currentScreenIndex=whichScreen;    }    private void snapToDestination()    {        final int x=getScrollX();        final int screenWidth = getWidth();                scrollToScreen((x + (screenWidth / 2))/ screenWidth);    }    @Override    protected void finalize() throws Throwable {        Log.e("TAG","finalize===");        super.finalize();    }    }
复制代码

 ok,附图一张

 

 

附上源码demo:http://files.cnblogs.com/zhouchanwen/bannerDemo.7z

原创文章欢迎转载,转载请注明出处:http://www.cnblogs.com/zhouchanwen
原创粉丝点击