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
- android 实现自动滚动的 Banner 横幅
- android 实现自动滚动的 Banner 横幅
- viewflow实现类似淘宝,网易新闻的横幅banner,可循环自动播放
- viewflow实现类似淘宝,网易新闻的横幅banner,可循环自动播放
- HTML+CSS+JS实现banner横幅自动切换效果
- Android banner,轮播图自动滚动控件
- Android 用ViewPager实现可自动循环的Banner图
- Android实现banner自动和手动轮换
- 使用Qt Quick实现顶部横幅(Banner)效果
- Android滚动banner条
- Android开发笔记(二十一)横幅轮播页Banner
- android实现歌词的自动滚动
- 简单的banner代码,用css实现滚动banner焦点图, 不用jq也能滚动banner
- android简单实现无限滚动,自动滚动的ViewPager
- android 自动播放Banner
- Android 开发之下拉刷新+ViewPager的banner滚动
- android 实现ScrollView自动滚动
- IOS无限自动循环滚动banner(源码)
- 2009-06-16 17:27 服务器:消息 823,级别 24,状态2,行1,连接中断
- MySQL开发流程介绍
- 数据库的操作
- arm板pcb画图计划
- 程序员的出路
- android 实现自动滚动的 Banner 横幅
- 25个增强iOS应用程序性能的提示和技巧(初级篇)
- Android手机号码获取问题
- 牛b人博客 : http://www.cnblogs.com/kesalin/category/352163.html
- ARM协处理器
- 启联高并发tcp服务中间件TcpServer
- ShellExecute, WinExec, CreateProcess区别
- 算法学习与实践之归并排序
- 【辅助工具】20款优秀的移动产品原型和线框图设计工具