自己动手写一个简单图片轮播的控件

简单图片轮播的控件的实现

本人菜鸟。
之前想找个轮播的控件,网上找了几篇文章,觉得搞的很复杂,思路也不是很清晰。所以干脆就自己写了。总的来说,是比较简单的。


思路:

图片轮播,其实就是滑动图片由手动改为自动而已。针对滑动图片,我立刻想到两个方案:

  1. horizontalScrollView
    水平scrollView,本来就是滑动的,可以在它的childView中添加要显示的视图。
  2. viewPager
    viewPager是一个很好用的视图容器,相信很多人已经用过了,添加视图、管理pager状态都很方便。

虽然两个都能用,但是使用horizontalScrollView有几个麻烦的地方:
- 要在horizontalScrollView里显示视图,需要
container.addView(childView);如果只add不remove,那么就会造成oom。所以需要我们自己去管理。
- 子视图的切换和响应需要自己捕获和定义。

使用viewPager就没有上面的问题。viewPager默认维护3个childView。后面会给出验证。


废话不多说了,直接上代码分析吧

package android.com.loopview.view;

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;

import java.lang.ref.WeakReference;

/**
 * Created by yueshaojun on 16/7/one.
 */
public class LoopViewPager extends ViewPager {
    private static int LEFTTORIGHT = 0;
    private static int RIGHTTOLEFT = 1;
    private long mtime;

    Run r =new Run(this);
    public LoopViewPager(Context context) {
        super(context);
    }

    public LoopViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    /**
     * 让子view动起来的操作
     * 默认滚动间隔时间为1s
     * 不设置默认不滚动
     * @param time 滚动间隔时间
     * */
    public void loop(long time){
        if(null == getAdapter()){
            return;
        }
        mtime = time;
        int item = getCurrentItem();
        if(time <= 0){
            time = 1000;
        }
        r.item = item;
        r.time = time;
        postDelayed(r, time);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        float oX = 0;
        float nX = 0;
        super.onTouchEvent(ev);
        switch (ev.getAction()){
            case MotionEvent.ACTION_MOVE :
                break;
            case MotionEvent.ACTION_DOWN:
                oX= ev.getX();//捕获down事件的X坐标
                break;
            case MotionEvent.ACTION_UP:
                nX = ev.getX();//捕获up事件的X坐标
                break;
        }
        //判断手势方向,以相差50为准
        if(nX == oX){
            return false;
        }
        if(nX-oX>50){
            handleGesture(LEFTTORIGHT);
        }else {
            handleGesture(RIGHTTOLEFT);
        }
        return true;
    }

    private void handleGesture(int gesture){
        if(gesture == LEFTTORIGHT){
            //TODO 处理从左到右的手势
        }
        if(gesture == RIGHTTOLEFT){
            //TODO 处理从右到左的手势
        }
        if (!looping){
            return;
        }
        //移除callBack
        removeCallbacks(r);
        r.item = getCurrentItem();
        r.time = mtime;
        postDelayed(r, mtime);
    }

    static class  Run implements Runnable{
        WeakReference<LoopViewPager> wloopView;
        int item;
        long time;
        Run(LoopViewPager lp){
            wloopView = new WeakReference<LoopViewPager>(lp);
        }
        @Override
        public void run() {
            LoopViewPager loopView = wloopView.get();
            if(item<loopView.getAdapter().getCount()-1) {
                ++item;
            }else{
                item = 0;
            }
            loopView.setCurrentItem(item);
            loopView.postDelayed(this, time);
        }
    }
}

代码并不复杂(我之前网上看到的都是好大一坨),思路也很清晰:
调用loop方法开启轮播后,postDelay一下,在runnable中设置当前子视图。重写onTouchEvent捕获手势,如果有左右滑动,就移除当前runnable,重新postDelay。(其实左右滑动的手势操作,viewpager已经帮我们做好了,在ViewPager.OnPageChangeListener中响应处理)


布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".activity.MainActivity">
    <android.com.loopview.view.LoopViewPager
        android:id="@+id/loop_view"
        android:layout_width="match_parent"
        android:layout_height="500dp">
    </android.com.loopview.view.LoopViewPager>
    <TextView
        android:id="@+id/indicator"
        android:layout_below="@id/loop_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textColor="#000000"
        android:text="0" />
</RelativeLayout>

适配器

package android.com.loopview.view;

import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by yueshaojun on 16/six/29.
 */
public class MyAdapter extends PagerAdapter {
    private Object[] objs;
    public MyAdapter(Object[] inflateObjs){
        objs = inflateObjs;
    }
    @Override
    public int getCount() {
        return objs.length;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view==object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Log.i("viewpager","instantiateItem:"+position);
        container.addView((View) objs[position]);
        return objs[position];
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        Log.i("viewpager","destroyItem:"+position);
        container.removeView((View) objs[position]);
    }

}

activity

package android.com.loopview.activity;

import android.app.Activity;
import android.com.loopview.R;
import android.com.loopview.view.LoopViewPager;
import android.com.loopview.view.MyAdapter;
import android.support.v4.view.ViewPager;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends Activity implements ViewPager.OnPageChangeListener {
    private LoopViewPager loopViewPager;
    private TextView indicator;
    private ImageView[] imageViews;
    private MyAdapter myAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();
        addListener();
    }

    private void initData() {
         int[] imgIds = new int []{
            R.drawable.one,
            R.drawable.two,
             R.drawable.three,
             R.drawable.four,
             R.drawable.five,
             R.drawable.six,
        };
        imageViews = new ImageView[imgIds.length];
        for (int i = 0;i<imgIds.length;i++){
            ImageView imageView = new ImageView(this);
            imageView.setImageResource(imgIds[i]);
            imageViews[i] = imageView;
        }
        myAdapter = new MyAdapter(imageViews);
    }

    private void initView() {
        loopViewPager = (LoopViewPager) findViewById(R.id.loop_view);
        indicator = (TextView) findViewById(R.id.indicator);
    }

    private void addListener() {
        loopViewPager.setAdapter(myAdapter);
        loopViewPager.addOnPageChangeListener(this);
        // 开启轮播并设置轮播时间间隔
        loopViewPager.loop(3000);

    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        Log.i("viewpager", "onPageSelected:" + position);
        indicator.setText(""+position);
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }

}

其实和普通viewPager的使用几本没有区别,只是需要用loop()方法开启轮播,不开启就是普通viewPager。
另外在添加子视图instantiateItem、移除子视图destroyItem和切换当前视图onPageSelected里打了日志。日志结果如下:

07-10 17:35:09.777 18715-18715/android.com.loopview I/viewpager: instantiateItem:0
07-10 17:35:09.778 18715-18715/android.com.loopview I/viewpager: instantiateItem:1
07-10 17:35:22.820 18715-18715/android.com.loopview I/viewpager: onPageSelected:1
07-10 17:35:23.345 18715-18715/android.com.loopview I/viewpager: instantiateItem:2
07-10 17:35:23.627 18715-18715/android.com.loopview I/viewpager: onPageSelected:2
07-10 17:35:24.111 18715-18715/android.com.loopview I/viewpager: destroyItem:0
07-10 17:35:24.113 18715-18715/android.com.loopview I/viewpager: instantiateItem:3
07-10 17:35:24.343 18715-18715/android.com.loopview I/viewpager: onPageSelected:3
07-10 17:35:24.844 18715-18715/android.com.loopview I/viewpager: destroyItem:1
07-10 17:35:24.844 18715-18715/android.com.loopview I/viewpager: instantiateItem:4

开始的时候添加0,1页,换到1添加2页,换到2页销毁0添加3。以此类推。说明viewpager只保存当前页和它左右两页(如果有)的视图。


改进:

之前用的是postDelay,可以用timer计时器去控制轮播。虽然timertask其实也是实现了runnable接口,但是由timer去管理线程完成调度显然要好的多。
改进以后的代码:

package android.com.loopview.view;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;

import java.lang.ref.WeakReference;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by yueshaojun on 16/7/one.
 */
public class LoopViewPager extends ViewPager {
    private Timer timer= new Timer();
    private MyHandler myHandler = new MyHandler(this);
    public LoopViewPager(Context context) {
        super(context);
    }

    public LoopViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    /**
     * 让子view动起来的操作
     * 默认滚动间隔时间为1s
     * 不设置默认不滚动
     * @param time 滚动间隔时间
     * */
    public void loop(long time){
        if(null == getAdapter()){
            return;
        }
        timer.schedule(new LooperTimerTask(this),1000,time);
    }

     class LooperTimerTask extends TimerTask{
         LoopViewPager loopViewPager;
         public LooperTimerTask(Object obj){
             loopViewPager = new WeakReference<>((LoopViewPager)obj).get();
         }
         @Override
         public void run() {
             int item = loopViewPager.getCurrentItem();
             if(item<loopViewPager.getAdapter().getCount()-1) {
                 ++item;
             }else{
                 item = 0;
             }
             Message message = new Message();
             Bundle bundle = new Bundle();
             bundle.putInt("item", item);
             message.setData(bundle);
             myHandler.sendMessage(message);
         }
     }
    class MyHandler extends Handler{
        LoopViewPager loopViewPager;
        public MyHandler(Object obj){
            loopViewPager = new WeakReference<>((LoopViewPager)obj).get();
        }
        @Override
        public void handleMessage(Message msg) {
            int item  = msg.getData().getInt("item");
            loopViewPager.setCurrentItem(item);
        }
    }
}

在timerTask中获取当前viewpager的位置,然后通知Ui更新。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值