300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Android使用viewpager实现图片轮播效果

Android使用viewpager实现图片轮播效果

时间:2021-04-21 22:48:33

相关推荐

Android使用viewpager实现图片轮播效果

自定义View实现图片轮播,实现了图片自动轮播,手动滑动,轮播标题,以及点击事件。

里面有很多注释

一、文件布局

二、代码

ImageBannerViewGroup类

/*** Created by hp on /7/31.* 这是实现图片轮播的核心类*/public class ImageBannerViewGroup extends ViewGroup{private int children;//我们ViewGroup子视图的总个数private int childwidth;//子视图的宽度private int childheight;//子视图的高度private int x;//此时的x的值 代表的是第一次按下的位置横坐标、每一次移动过程中一定之前的位置横坐标private int index = 0;//代表的是我们每张图片的索引private Scroller scroller;//.利用 Scroller 对象 完成轮播图的手动轮播/*** 要实现图片的单击事件的获取* 我们 利用一个单击变量开关进行判断,在用户离开屏幕的一瞬间* 我们用判断变量开关来判断用户的操作是点击还是移动*/private boolean isClick;//true代表的是点击事件,false代表的是不是点击事件private ImageBarnnerLister lister;public ImageBarnnerLister getLister(){return lister;}public void setLister(ImageBarnnerLister lister) {this.lister = lister;}public interface ImageBarnnerLister{void clickImageIndex(int pos);//pos代表的是我们当前图片的具体索引值}private ImageBarnnerViewGroupLisnner barnnerViewGroupLisnner;public ImageBarnnerViewGroupLisnner getBarnnerViewGroupLisnner() {return barnnerViewGroupLisnner;}public void setBarnnerViewGroupLisnner(ImageBarnnerViewGroupLisnner barnnerViewGroupLisnner) {this.barnnerViewGroupLisnner = barnnerViewGroupLisnner;}/*** 实现图片轮播底部圆点以及底部圆点切换功能步骤思路:* 1.自定义一个集成自FrameLayout的布局,利用FrameLayout布局的特性(在同一位置放置不同的iew最终显示的是最后一个view)* 利用这个特性我们就可以实现底部圆点的布局* 2.我们需要准备素材,就是底部圆点的素材,我们可以利用Drawable的功能,去实现一个圆点的展示* 3.我们需要继承FrameLayout来定义一个类,在该类的实现过程中,我们去加载我们刚才自定义的ImageBannerViewGroup核心类* 和我们需要实现的底部圆点的布局LinearLayout来实现*///---自动轮播private boolean isAuto = true;//默认开启自动轮播private Timer timer = new Timer();private TimerTask task;private Handler autoHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.what){case 0://此时我们需要图片的自动轮播if(++index >= children){//如果滑到了最后一张图片就会从第一张从新开始index = 0;}scrollTo(childwidth *index,0);barnnerViewGroupLisnner.selectImage(index);break;}}};private void startAuto(){isAuto = true;}private void stopAuto(){isAuto = false;}/*** 采用Timer,TimerTask,Handler三者相结合的方法实现自动轮播* 抽取两个方法来控制,是否启动自动轮播,称之为 startAuto(),stopAuto();* 我们在2个方法的控制过程中,我们希望能有控制自动开启轮播图的开关* 我们需要一个变量参数来作为我们自动启动轮播图的开关,为 isAuto boolean true代表开启,false代表关闭*/public ImageBannerViewGroup(Context context) {super(context);initObj();//.利用 Scroller 对象 完成轮播图的手动轮播需要用到这个方法,利用 scrollTo、scrollBy 完成轮播图的手动轮播时可以删掉}public ImageBannerViewGroup(Context context, AttributeSet attrs) {super(context, attrs);initObj();}public ImageBannerViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initObj();}private void initObj() {scroller = new Scroller(getContext());task = new TimerTask() {@Overridepublic void run() {if(isAuto) {//开启轮播图autoHandler.sendEmptyMessage(0);}}};timer.schedule(task,100,3000);}@Overridepublic void computeScroll() {//利用 Scroller 对象 完成轮播图的手动轮播需要用到这个方法puteScroll();if(puteScrollOffset()){scrollTo(scroller.getCurrX(),0);invalidate();}}/*** 我们在自定义的ViewGroop中,我们必须要实现的方法有:测量-》布局-》绘制* 那么对于来说就是:onMeasure()* 我们对于绘制来说,因为我们是自定义的ViewGroup容器,针对于容器的绘制* 其实就是容器内的子控件的绘制过程,那么我们只需要调用系统自带的绘制即可,* 也就是对于ViewGroup绘制过程我们不需要再重写该方法* 调用系统的即可*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);/*** 由于我们要实现ViewGroup的容器,* 那么我们就需要知道该容器内的所有子视图* 我们要想测量我们的ViewGroup的宽度和高度,那么我们就必须先要去测量子视图* 的宽度和高度之和,才能知道我们的ViewGroup的宽度和高度是多少*///1.求子视图的个数children = getChildCount();//我们就可以知道子视图的个数if(0 == children){setMeasuredDimension(0,0);}else{//2.测量子视图的高度measureChildren(widthMeasureSpec,heightMeasureSpec);//此时我们以第一个子视图为基准,也就是说我们的viewGroup的高度就是我们第一个子视图的高度//宽度就是我们第一个姿势图的额宽度*子视图的个数View view = getChildAt(0);//因为此时第一个视图绝对是存在的childwidth = view.getMeasuredWidth();//3.根据子视图的宽度和高度,求出改ViewGroup的宽度和高度childheight = view.getMeasuredHeight();int width = view.getMeasuredWidth() * children;setMeasuredDimension(width,childheight);}}/*** 事件传递过程中的调用方法,我们需要调用容器的拦截方法 onInterceptTouchEvent* 针对于该方法我们可以理解为 如果说该方法的返回值为true的时候,那么我们自定义的ViewGroup容器就会处理此次拦截事件* 如果说返回值为false的时候,那么我们自定义的ViewGroup容器将不会接受此次事件的处理过程,将会继续向下传递事件* 针对于我们自定义的ViewGroup 我们希望我们的ViewGroup,容器处理接受事件 那么我们的返回值就是true*/@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return true;}/*** 用2中方式来实现轮播图的手动轮播* 1.利用 scrollTo、scrollBy 完成轮播图的手动轮播* 2.利用 Scroller 对象 完成轮播图的手动轮播** 第一:我们在滑动屏幕图片的过程中,其实就是 我们自定义ViewGroup的子视图的移动过程,那么我们只需要知道* 滑动之前的横坐标和滑动之后的横坐标,此时 我们就可以 求出次过程中移动的距离,我们在利用 scrollBy方法实现* 图片的滑动,所以 此时我们需要有2个值要我们求出:移动之前、移动之后的 横坐标值** 第二:在我们第一次按下的那一瞬间,此时的移动之前和移动之后的值是相等的,也就是我们按下的那一瞬间的那一个点* 的横坐标的值。** 第三:我们在不断滑动的过程中,会不断的调用我们的ACTION_MOVE方法,那么此时我们就应该将移动之前的值* 和移动之后的进行保存,以便我们能够算出滑动的距离** 第四:在我们抬起的那一瞬间,我们需要计算出我们此时将要滑动到哪张图片的位置上。** 我们此时就需要求得将要滑动到的哪张图片的索引值。* (我们当前ViewGroup的滑动距离 + 我们的每一张图片的宽度 / 2) / 我们的每一张图片的宽度值** 此时我们就可以利用scrollTo方法。滑动到该图片的位置上**/@Overridepublic boolean onTouchEvent(MotionEvent event) {// return super.onTouchEvent(event);switch (event.getAction()){case MotionEvent.ACTION_DOWN://表示的是用户按下的一瞬间stopAuto();if(scroller.isFinished()){//.利用 Scroller 对象 完成轮播图的手动轮播scroller.abortAnimation();}isClick = true;x = (int) event.getX();break;case MotionEvent.ACTION_MOVE://表示的是用户 按下之后 在屏幕上移动的过程int moveX = (int) event.getX();int distance = moveX - x;scrollBy(-distance,0);x = moveX;isClick = false;break;case MotionEvent.ACTION_UP://表示的是用户抬起的一瞬间int scrollX = getScrollX();index = (scrollX + childwidth / 2) / childwidth;if(index < 0) {//说明了此时已经滑倒了最左边第一张图片index = 0;}else if(index > children - 1) {//说明滑到了最后一张图片index = children - 1;}if (isClick){//代表点击事件lister.clickImageIndex(index);}else {int dx = index * childwidth - scrollX;//.利用 Scroller 对象 完成轮播图的手动轮播scroller.startScroll(scrollX,0,dx,0);//.利用 Scroller 对象 完成轮播图的手动轮播postInvalidate();//.利用 Scroller 对象 完成轮播图的手动轮播//scrollTo(index * childwidth,0);//利用 scrollTo、scrollBy 完成轮播图的手动轮播barnnerViewGroupLisnner.selectImage(index);}startAuto();break;default:break;}return true;//我们该容器的父View,我们已经处理好了该事件}/*** 继承ViewGroup必须要实现布局onLayout方法* @param changed 当我们的ViewGroup布局位置发生变化的为true,没有发生改变为false* @param l* @param t* @param r* @param b ,没有发生改变为false*/@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {if(changed){int leftMargin = 0;for(int i = 0;i < children;i++){View view = getChildAt(i);view.layout(leftMargin, 0, leftMargin + childwidth, childheight);leftMargin += childwidth;}}}public interface ImageBarnnerViewGroupLisnner{void selectImage(int index);}}

ImageBarnnerFrameLayout类

/*** Created by hp on /8/2.*/public class ImageBarnnerFrameLayout extends FrameLayout implements ImageBannerViewGroup.ImageBarnnerViewGroupLisnner,ImageBannerViewGroup.ImageBarnnerLister{private ImageBannerViewGroup imageBannerViewGroup;private LinearLayout linearLayout;private FramLayoutLisenner lisenner;public FramLayoutLisenner getLisenner() {return lisenner;}public void setLisenner(FramLayoutLisenner lisenner) {this.lisenner = lisenner;}public ImageBarnnerFrameLayout(@NonNull Context context) {super(context);initImageBannerViewGroup();initDotLinearlayout();}public ImageBarnnerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);initImageBannerViewGroup();initDotLinearlayout();}public ImageBarnnerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initImageBannerViewGroup();initDotLinearlayout();}public void addBitmaps(List<Bitmap> list){for(int i = 0;i < list.size();i++){Bitmap bitmap = list.get(i);addBitmapToImageBarnnerViewGroup(bitmap);addDotToLinearlayout();}}private void addDotToLinearlayout(){ImageView iv = new ImageView(getContext());LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);lp.setMargins(5,5,5,5);iv.setLayoutParams(lp);iv.setImageResource(R.drawable.dot_normal);linearLayout.addView(iv);}private void addBitmapToImageBarnnerViewGroup(Bitmap bitmap){ImageView iv = new ImageView(getContext());iv.setScaleType(ImageView.ScaleType.CENTER_CROP);iv.setLayoutParams(new ViewGroup.LayoutParams(C.WITTH,ViewGroup.LayoutParams.WRAP_CONTENT));iv.setImageBitmap(bitmap);imageBannerViewGroup.addView(iv);}/*** 初始化我们自定义的图片轮播功能的核心*/private void initImageBannerViewGroup(){imageBannerViewGroup = new ImageBannerViewGroup(getContext());FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);imageBannerViewGroup.setLayoutParams(lp);imageBannerViewGroup.setBarnnerViewGroupLisnner(this);//这里就是将Lisnner传递给FramlayoutimageBannerViewGroup.setLister(this);addView(imageBannerViewGroup);}/*** 初始化 底部圆点 布局*/private void initDotLinearlayout(){linearLayout = new LinearLayout(getContext());FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,40);linearLayout.setLayoutParams(lp);linearLayout.setOrientation(LinearLayout.HORIZONTAL);linearLayout.setGravity(Gravity.CENTER);linearLayout.setBackgroundColor(Color.RED);addView(linearLayout);FrameLayout.LayoutParams layoutParams = (LayoutParams) linearLayout.getLayoutParams();layoutParams.gravity = Gravity.BOTTOM;linearLayout.setLayoutParams(layoutParams);/*** 设置透明度* 在3.0以后,我们使用的是setAlpha(),在3.0之前我们使用的也是setAlpha(),但是调用者不同*/if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){linearLayout.setAlpha(0.5f);}else {linearLayout.getBackground().setAlpha(100);}}@Overridepublic void selectImage(int index) {int count = linearLayout.getChildCount();for(int i = 0;i < count;i++){ImageView iv = (ImageView) linearLayout.getChildAt(i);if(i == index){iv.setImageResource(R.drawable.dot_select);}else {iv.setImageResource(R.drawable.dot_normal);}}}@Overridepublic void clickImageIndex(int pos) {lisenner.clickImageIndex(pos);}public interface FramLayoutLisenner{void clickImageIndex(int pos);}}

MainActivity类

public class MainActivity extends AppCompatActivity implements ImageBarnnerFrameLayout.FramLayoutLisenner {private ImageBarnnerFrameLayout mGroup;private int[] ids = new int[]{R.drawable.d,R.drawable.a,R.drawable.b,R.drawable.c};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//我们需要计算出我们当前手机的宽度DisplayMetrics dm = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm);C.WITTH = dm.widthPixels;mGroup = (ImageBarnnerFrameLayout)findViewById(R.id.image_group);mGroup.setLisenner(this);List<Bitmap> list = new ArrayList<>();for (int i = 0;i < ids.length;i++){Bitmap bitmap = BitmapFactory.decodeResource(getResources(),ids[i]);list.add(bitmap);}mGroup.addBitmaps(list);/* for (int i = 0;i < ids.length;i++){ImageView iv = new ImageView(this);iv.setScaleType(ImageView.ScaleType.CENTER_CROP);iv.setLayoutParams(new ViewGroup.LayoutParams(width,ViewGroup.LayoutParams.WRAP_CONTENT));iv.setImageResource(ids[i]);mGroup.addView(iv);}mGroup.setLister(this);*/}public void clickImageIndex(int pos){Toast.makeText(this,"pos = "+pos,Toast.LENGTH_SHORT).show();}}

C类

public class C {public static int WITTH = 0;}

布局文件

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.example.hp.zzdlunbo7.MainActivity"><com.example.hp.zzdlunbo7.view.ImageBarnnerFrameLayoutandroid:id="@+id/image_group"android:layout_width="match_parent"android:layout_height="200dp"></com.example.hp.zzdlunbo7.view.ImageBarnnerFrameLayout></RelativeLayout>

导包时要注意,有的包java和Android都有,出错可能就是导入了java的包

代码是根据慕课上的老师的课程写的,老师讲的很好,强烈建议大家去听,讲解的很详细,收获很大

老师课程链接/learn/793

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。