安卓banner图片轮播
之前写过一篇关于首页图片广告轮播的demo:http://blog.csdn.net/baiyuliang2013/article/details/45740091,不过图片轮播的指示器(小白点)处操作过于复杂,而且是固定的不太合理,此次对其做了优化,替换为了一个自定义的指示器控件,效果美观,代码更简洁,秒秒钟套用在自己的项目中:
指示器代码:
PageIndicator.java
package com.byl.testad; import android.support.v4.view.ViewPager; /** * A PageIndicator is responsible to show an visual indicator on the total views * number and the current visible view. */ public interface PageIndicator extends ViewPager.OnPageChangeListener { /** * Bind the indicator to a ViewPager. * * @param view */ void setViewPager(ViewPager view); /** * Bind the indicator to a ViewPager. * * @param view * @param initialPosition */ void setViewPager(ViewPager view, int initialPosition); /** * <p>Set the current page of both the ViewPager and indicator.</p> * * <p>This <strong>must</strong> be used if you need to set the page before * the views are drawn on screen (e.g., default start page).</p> * * @param item */ void setCurrentItem(int item); /** * Set a page change listener which will receive forwarded events. * * @param listener */ void setOnPageChangeListener(ViewPager.OnPageChangeListener listener); /** * Notify the indicator that the fragment list has changed. */ void notifyDataSetChanged(); }
CirclePageIndicator.java
package com.byl.testad; import static android.graphics.Paint.ANTI_ALIAS_FLAG; import static android.widget.LinearLayout.HORIZONTAL; import static android.widget.LinearLayout.VERTICAL; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.support.v4.view.MotionEventCompat; import android.support.v4.view.ViewConfigurationCompat; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; /** * Draws circles (one for each view). The current view position is filled and * others are only stroked. */ public class CirclePageIndicator extends View implements PageIndicator { private static final int INVALID_POINTER = -1; private float mRadius; private final Paint mPaintPageFill = new Paint(ANTI_ALIAS_FLAG); private final Paint mPaintStroke = new Paint(ANTI_ALIAS_FLAG); private final Paint mPaintFill = new Paint(ANTI_ALIAS_FLAG); private ViewPager mViewPager; private ViewPager.OnPageChangeListener mListener; private int mCurrentPage; private int mSnapPage; private float mPageOffset; private int mScrollState; private int mOrientation; private boolean mCentered; private boolean mSnap; private int mTouchSlop; private float mLastMotionX = -1; private int mActivePointerId = INVALID_POINTER; private boolean mIsDragging; public CirclePageIndicator(Context context) { this(context, null); } public CirclePageIndicator(Context context, AttributeSet attrs) { this(context, attrs, R.attr.vpiCirclePageIndicatorStyle); } public CirclePageIndicator(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); if (isInEditMode()) return; //Load defaults from resources final Resources res = getResources(); final int defaultPageColor = res.getColor(R.color.default_circle_indicator_page_color); final int defaultFillColor = res.getColor(R.color.default_circle_indicator_fill_color); final int defaultOrientation = res.getInteger(R.integer.default_circle_indicator_orientation); final int defaultStrokeColor = res.getColor(R.color.default_circle_indicator_stroke_color); final float defaultStrokeWidth = res.getDimension(R.dimen.default_circle_indicator_stroke_width); final float defaultRadius = res.getDimension(R.dimen.default_circle_indicator_radius); final boolean defaultCentered = res.getBoolean(R.bool.default_circle_indicator_centered); final boolean defaultSnap = res.getBoolean(R.bool.default_circle_indicator_snap); //Retrieve styles attributes TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePageIndicator, defStyle, 0); mCentered = a.getBoolean(R.styleable.CirclePageIndicator_centered, defaultCentered); mOrientation = a.getInt(R.styleable.CirclePageIndicator_android_orientation, defaultOrientation); mPaintPageFill.setStyle(Style.FILL); mPaintPageFill.setColor(a.getColor(R.styleable.CirclePageIndicator_pageColor, defaultPageColor)); mPaintStroke.setStyle(Style.STROKE); mPaintStroke.setColor(a.getColor(R.styleable.CirclePageIndicator_strokeColor, defaultStrokeColor)); mPaintStroke.setStrokeWidth(a.getDimension(R.styleable.CirclePageIndicator_strokeWidth, defaultStrokeWidth)); mPaintFill.setStyle(Style.FILL); mPaintFill.setColor(a.getColor(R.styleable.CirclePageIndicator_fillColor, defaultFillColor)); mRadius = a.getDimension(R.styleable.CirclePageIndicator_radius, defaultRadius); mSnap = a.getBoolean(R.styleable.CirclePageIndicator_snap, defaultSnap); Drawable background = a.getDrawable(R.styleable.CirclePageIndicator_android_background); if (background != null) { setBackgroundDrawable(background); } a.recycle(); final ViewConfiguration configuration = ViewConfiguration.get(context); mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); } public void setCentered(boolean centered) { mCentered = centered; invalidate(); } public boolean isCentered() { return mCentered; } public void setPageColor(int pageColor) { mPaintPageFill.setColor(pageColor); invalidate(); } public int getPageColor() { return mPaintPageFill.getColor(); } public void setFillColor(int fillColor) { mPaintFill.setColor(fillColor); invalidate(); } public int getFillColor() { return mPaintFill.getColor(); } public void setOrientation(int orientation) { switch (orientation) { case HORIZONTAL: case VERTICAL: mOrientation = orientation; requestLayout(); break; default: throw new IllegalArgumentException("Orientation must be either HORIZONTAL or VERTICAL."); } } public int getOrientation() { return mOrientation; } public void setStrokeColor(int strokeColor) { mPaintStroke.setColor(strokeColor); invalidate(); } public int getStrokeColor() { return mPaintStroke.getColor(); } public void setStrokeWidth(float strokeWidth) { mPaintStroke.setStrokeWidth(strokeWidth); invalidate(); } public float getStrokeWidth() { return mPaintStroke.getStrokeWidth(); } public void setRadius(float radius) { mRadius = radius; invalidate(); } public float getRadius() { return mRadius; } public void setSnap(boolean snap) { mSnap = snap; invalidate(); } public boolean isSnap() { return mSnap; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mViewPager == null) { return; } final int count = mViewPager.getAdapter().getCount(); if (count == 0) { return; } if (mCurrentPage >= count) { setCurrentItem(count - 1); return; } int longSize; int longPaddingBefore; int longPaddingAfter; int shortPaddingBefore; if (mOrientation == HORIZONTAL) { longSize = getWidth(); longPaddingBefore = getPaddingLeft(); longPaddingAfter = getPaddingRight(); shortPaddingBefore = getPaddingTop(); } else { longSize = getHeight(); longPaddingBefore = getPaddingTop(); longPaddingAfter = getPaddingBottom(); shortPaddingBefore = getPaddingLeft(); } final float threeRadius = mRadius * 3; final float shortOffset = shortPaddingBefore + mRadius; float longOffset = longPaddingBefore + mRadius; if (mCentered) { longOffset += ((longSize - longPaddingBefore - longPaddingAfter) / 2.0f) - ((count * threeRadius) / 2.0f); } float dX; float dY; float pageFillRadius = mRadius; if (mPaintStroke.getStrokeWidth() > 0) { pageFillRadius -= mPaintStroke.getStrokeWidth() / 2.0f; } //Draw stroked circles for (int iLoop = 0; iLoop < count; iLoop++) { float drawLong = longOffset + (iLoop * threeRadius); if (mOrientation == HORIZONTAL) { dX = drawLong; dY = shortOffset; } else { dX = shortOffset; dY = drawLong; } // Only paint fill if not completely transparent if (mPaintPageFill.getAlpha() > 0) { canvas.drawCircle(dX, dY, pageFillRadius, mPaintPageFill); } // Only paint stroke if a stroke width was non-zero if (pageFillRadius != mRadius) { canvas.drawCircle(dX, dY, mRadius, mPaintStroke); } } //Draw the filled circle according to the current scroll float cx = (mSnap ? mSnapPage : mCurrentPage) * threeRadius; if (!mSnap) { cx += mPageOffset * threeRadius; } if (mOrientation == HORIZONTAL) { dX = longOffset + cx; dY = shortOffset; } else { dX = shortOffset; dY = longOffset + cx; } canvas.drawCircle(dX, dY, mRadius, mPaintFill); } public boolean onTouchEvent(MotionEvent ev) { if (super.onTouchEvent(ev)) { return true; } if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) { return false; } final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; switch (action) { case MotionEvent.ACTION_DOWN: mActivePointerId = MotionEventCompat.getPointerId(ev, 0); mLastMotionX = ev.getX(); break; case MotionEvent.ACTION_MOVE: { final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); final float x = MotionEventCompat.getX(ev, activePointerIndex); final float deltaX = x - mLastMotionX; if (!mIsDragging) { if (Math.abs(deltaX) > mTouchSlop) { mIsDragging = true; } } if (mIsDragging) { mLastMotionX = x; if (mViewPager.isFakeDragging() || mViewPager.beginFakeDrag()) { mViewPager.fakeDragBy(deltaX); } } break; } case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: if (!mIsDragging) { final int count = mViewPager.getAdapter().getCount(); final int width = getWidth(); final float halfWidth = width / 2f; final float sixthWidth = width / 6f; if ((mCurrentPage > 0) && (ev.getX() < halfWidth - sixthWidth)) { if (action != MotionEvent.ACTION_CANCEL) { mViewPager.setCurrentItem(mCurrentPage - 1); } return true; } else if ((mCurrentPage < count - 1) && (ev.getX() > halfWidth + sixthWidth)) { if (action != MotionEvent.ACTION_CANCEL) { mViewPager.setCurrentItem(mCurrentPage + 1); } return true; } } mIsDragging = false; mActivePointerId = INVALID_POINTER; if (mViewPager.isFakeDragging()) mViewPager.endFakeDrag(); break; case MotionEventCompat.ACTION_POINTER_DOWN: { final int index = MotionEventCompat.getActionIndex(ev); mLastMotionX = MotionEventCompat.getX(ev, index); mActivePointerId = MotionEventCompat.getPointerId(ev, index); break; } case MotionEventCompat.ACTION_POINTER_UP: final int pointerIndex = MotionEventCompat.getActionIndex(ev); final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); if (pointerId == mActivePointerId) { final int newPointerIndex = pointerIndex == 0 ? 1 : 0; mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); } mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId)); break; } return true; } @Override public void setViewPager(ViewPager view) { if (mViewPager == view) { return; } if (mViewPager != null) { mViewPager.setOnPageChangeListener(null); } if (view.getAdapter() == null) { throw new IllegalStateException("ViewPager does not have adapter instance."); } mViewPager = view; mViewPager.setOnPageChangeListener(this); invalidate(); } @Override public void setViewPager(ViewPager view, int initialPosition) { setViewPager(view); setCurrentItem(initialPosition); } @Override public void setCurrentItem(int item) { if (mViewPager == null) { throw new IllegalStateException("ViewPager has not been bound."); } mViewPager.setCurrentItem(item); mCurrentPage = item; invalidate(); } @Override public void notifyDataSetChanged() { invalidate(); } @Override public void onPageScrollStateChanged(int state) { mScrollState = state; if (mListener != null) { mListener.onPageScrollStateChanged(state); } } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { mCurrentPage = position; mPageOffset = positionOffset; invalidate(); if (mListener != null) { mListener.onPageScrolled(position, positionOffset, positionOffsetPixels); } } @Override public void onPageSelected(int position) { if (mSnap || mScrollState == ViewPager.SCROLL_STATE_IDLE) { mCurrentPage = position; mSnapPage = position; invalidate(); } if (mListener != null) { mListener.onPageSelected(position); } onpageSelected.pageSelected(position); } @Override public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { mListener = listener; } /* * (non-Javadoc) * * @see android.view.View#onMeasure(int, int) */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mOrientation == HORIZONTAL) { setMeasuredDimension(measureLong(widthMeasureSpec), measureShort(heightMeasureSpec)); } else { setMeasuredDimension(measureShort(widthMeasureSpec), measureLong(heightMeasureSpec)); } } /** * Determines the width of this view * * @param measureSpec * A measureSpec packed into an int * @return The width of the view, honoring constraints from measureSpec */ private int measureLong(int measureSpec) { int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)) { //We were told how big to be result = specSize; } else { //Calculate the width according the views count final int count = mViewPager.getAdapter().getCount(); result = (int)(getPaddingLeft() + getPaddingRight() + (count * 2 * mRadius) + (count - 1) * mRadius + 1); //Respect AT_MOST value if that was what is called for by measureSpec if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } /** * Determines the height of this view * * @param measureSpec * A measureSpec packed into an int * @return The height of the view, honoring constraints from measureSpec */ private int measureShort(int measureSpec) { int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { //We were told how big to be result = specSize; } else { //Measure the height result = (int)(2 * mRadius + getPaddingTop() + getPaddingBottom() + 1); //Respect AT_MOST value if that was what is called for by measureSpec if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } @Override public void onRestoreInstanceState(Parcelable state) { SavedState savedState = (SavedState)state; super.onRestoreInstanceState(savedState.getSuperState()); mCurrentPage = savedState.currentPage; mSnapPage = savedState.currentPage; requestLayout(); } @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState savedState = new SavedState(superState); savedState.currentPage = mCurrentPage; return savedState; } static class SavedState extends BaseSavedState { int currentPage; public SavedState(Parcelable superState) { super(superState); } private SavedState(Parcel in) { super(in); currentPage = in.readInt(); } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeInt(currentPage); } @SuppressWarnings("UnusedDeclaration") public static final Creator<SavedState> CREATOR = new Creator<SavedState>() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }; } //onpageSelected private OnpageSelected onpageSelected; public void setOnpageSelected(OnpageSelected l) { onpageSelected = l; } public interface OnpageSelected { public void pageSelected(int pos); } }
使用方法:
indicator.setViewPager(vp); indicator.setOnpageSelected(new OnpageSelected() { @Override public void pageSelected(int position) { //图片切换完成事件 } });
切换的动画效果可以根据自己的实际需求选择,不需要的话则可删除此部分代码!
EclipseDemo下载地址:http://download.csdn.net/detail/baiyuliang2013/9478684
2016-04-21更新:
增加Vp触摸停留功能,原理就是对viewpaper的dispatchTouchEvent事件进行监听,当手指触摸时停止轮播,当手指抬起时继续轮播;我们可以用一个boolean值来表示手指触摸状态:
boolean isTouchVP=false;//未触摸,或手指抬起;
boolean isTouchVP=true;//手指触摸;
然后再轮播Task的run方法中进行判断:
private class ScrollTask extends TimerTask { public void run() { if(isTouchVP)return; if (imageViews != null && imageViews.size() > 0) { currentItem = (currentItem + 1) % imageViews.size(); handler.sendEmptyMessage(1); // 通过Handler切换图片 } } }
而对对viewpaper的dispatchTouchEvent事件监听需要我们重写一个Viewpaper,并定义回调接口:
MyViewPaper:
package com.byl.testad; import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; public class MyViewPaper extends ViewPager { OnMyTouchListener onMyTouchListener; public MyViewPaper(Context context) { super(context); } public MyViewPaper(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent event) { if (onMyTouchListener == null) { return super.dispatchTouchEvent(event); } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: onMyTouchListener.down(); break; case MotionEvent.ACTION_UP: onMyTouchListener.up(); break; } return super.dispatchTouchEvent(event); } /** * 设置触摸监听 */ public void setOnMyTouchListener(OnMyTouchListener onMyTouchListener) { this.onMyTouchListener = onMyTouchListener; } /** * 触摸监听接口 * @author baiyuliang */ public interface OnMyTouchListener { void down(); void up(); } }
在ManActivity中设置监听:
vp.setOnMyTouchListener(new OnMyTouchListener() { @Override public void up() { isTouchVP=false; } @Override public void down() { isTouchVP=true; } });
最后不要忘了你的xml中修改为重写后的ViewPaper:
<com.byl.testad.MyViewPaper android:id="@+id/vp" android:layout_width="fill_parent" android:layout_height="fill_parent" />
安卓banner图片轮播的更多相关文章
- banner图片轮播
html部分 版本号 <script src="http://www.jq22.com/jquery/jquery-1.10.2 ...
- 原生js+css3实现图片自动切换,图片轮播
运用CSS3transition及opacity属性 制作图片轮播动画 自己这两天根据用js来控制触发CSS3中transition属性,从而写出来的以CSS3动画为基础,js控制过程的图片轮播 运用 ...
- 网站banner无缝轮播
网站banner无缝轮播 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...
- 图片轮播图插件的使用 unslider!!!
1.百度图片轮播图unslider,第一个就会出现jquery unslider轮播图,点击进去,下载网站提供的文件,解压,内部有我们需要使用的各种js,图片等. 2.在自己的eclipse或者int ...
- 使用FlaycoBanner实现图片轮播效果(加载网络图片)
FlaycoBanner是一个开源图片轮播框架,支持android2.2及以上: git地址:https://github.com/H07000223/FlycoBanner_Master 在andr ...
- jquery图片轮播效果(unslider)
今天做网站(住建局网站)需要用到图片轮播,刚开始想借鉴DTCMS上的,查看CSS与页面代码,呵呵,不复杂,直接复制过来,结果调整半天,页面还是各种乱,没办法,网上找一个吧,于是找到了今天要说的这货un ...
- 分享jquery实现百叶窗特效的图片轮播
首先非常感谢网友嘉翼的无私分享,这是他刚在网站扣下来的特效,第一时间与大家分享,jquery实现百叶窗特效的图片轮播 使用方法: 1.引用css文件,css文件里面已经做了注释,基本只需要修改宽高就好 ...
- 图片轮播(左右切换)--JS原生和jQuery实现
图片轮播(左右切换)--js原生和jquery实现 左右切换的做法基本步骤跟 上一篇文章 淡入淡出 类似,只不过修改了一些特定的部分 (1)首先是页面的结构部分 对于我这种左右切换式 1.首先是个外 ...
- 图片轮播(淡入淡出)--JS原生和jQuery实现
图片轮播(淡入淡出)--js原生和jquery实现 图片轮播有很多种方式,这里采用其中的 淡入淡出形式 js原生和jQuery都可以实现,jquery因为封装了很多用法,所以用起来就简单许多,转换成j ...
随机推荐
- cmake 没有那个目录
问题:bash: /usr/bin/cmake: 没有那个文件或目录 因为直接使用cmake系统回到默认的/usr/bin中去寻找,但是src中安装的cmake是在/usr/local/bin中,所以 ...
- JFinal实现伪静态
JFinal 是基于 Java 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速.代码量少.学习简单.功能强大.轻量级.易扩展.Restful.在拥有Java语言所有优势的同时再拥有ru ...
- 初探nginx
nginx nginx是俄罗斯人写的轻量级http服务器,Nginx 以事件驱动的方式编写,有非常好的性能,同时也是一个非常高效的反向代理.负载均衡. Nginx 稳定性高,模块库丰富,配置灵活,系统 ...
- OpenCV环境搭建(一)
此环境搭建是OpenCV的python(一下简称py)开发环境搭建,建立在py3的环境和语法上实现的. windows系统搭建 系统环境:windows 10 + python 3.6 + OpenC ...
- Linux学习之CentOS(十七)-----释放 Linux 系统预留的硬盘空间 与Linux磁盘空间被未知资源耗尽 (转)
释放 Linux 系统预留的硬盘空间 大多数文件系统都会保留一部分空间留作紧急情况时用(比如硬盘空间满了),这样能保证有些关键应用(比如数据库)在硬盘满的时候有点余地,不致于马上就 crash,给监 ...
- 更改计算机名及使用Secure CRT ssh连接用户添加方法汇总
修改计算机名 更改/etc/sysconfig下的network文件,在提示符下输入vi /etc/sysconfig/network,然后将HOSTNAME后面的值改为想要设置的主机名. 开启SS ...
- log4j的终极封装
通用型(再也不用每个类new一个logger了) public class Log { private static Map<String,Logger> loggerMap = new ...
- 京东消息中间件JMQ
http://blog.csdn.net/javahongxi/article/details/54411464 [京东技术]京东的MQ经历了JQ->AMQ->JMQ的发展,其中JQ的基于 ...
- JVM之Java虚拟机详解
这篇文章解释了Java 虚拟机(JVM)的内部架构.下图显示了遵守Java SE 7 规范的典型的 JVM 核心内部组件. 上图显示的组件分两个章节解释.第一章讨论针对每个线程创建的组件,第二章节讨论 ...
- C#基础拾遗系列之二:C#7.0新增功能点
第一部分: C#是一种通用的,类型安全的,面向对象的编程语言.有如下特点: (1)面向对象:c# 是面向对象的范例的一个丰富实现, 它包括封装.继承和多态性.C#面向对象的行为包括: 统一的类型系统 ...