Android——ViewPager和内部view之间的事件分发及轮播图

viewpager 在滑动的过程中是如何触发view身上的事件的,换句话说,viewpager在滑动的过程中到底是滑动的它里面的view,还是滑动的viewpager本身?

一、示例代码:

1、自定义ViewPager:MyViewPager,重新dispatchTouchEvent方法,添加一些事件处理的log信息。

package com.example.viewpagerdemo;

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

public class MyViewPager extends ViewPager {

    private String TAG = "viewpagertest";

    public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.i(TAG , "===MyViewPager MotionEvent.ACTION_DOWN===");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.i(TAG , "===MyViewPager MotionEvent.ACTION_MOVE===");
            break;
        case MotionEvent.ACTION_UP:
            Log.i(TAG , "===MyViewPager MotionEvent.ACTION_UP===");
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.i(TAG , "===MyViewPager MotionEvent.ACTION_CANCEL===");
            break;
        }
        return super.dispatchTouchEvent(ev);
    }

}

2、在activity中设置viewpager的数据适配器,给view添加touch事件监听器,添加事件处理的log信息。

package com.example.viewpagerdemo;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageView;

public class MainActivity extends Activity {

    private String TAG = "viewpagertest";

    private Integer[] imgList = {R.drawable.first,R.drawable.second,R.drawable.third,R.drawable.four};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        MyViewPager viewPager = (MyViewPager) findViewById(R.id.myviewpager);
        viewPager.setAdapter(new MyAdapter());
    }

    class MyAdapter extends PagerAdapter {

        @Override
        public int getCount() {
            return 4;
        }

        @Override
        public boolean isViewFromObject(View arg0, Object arg1) {
            return arg0 == arg1;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            View view = View.inflate(getApplicationContext(), R.layout.view_item, null);
            ImageView imageView = (ImageView) view.findViewById(R.id.iv);
            imageView.setBackgroundResource(imgList[position]);

            view.setOnTouchListener(new OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent ev) {
                    switch (ev.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        Log.d(TAG , "===view MotionEvent.ACTION_DOWN===");
                        break;
                    case MotionEvent.ACTION_MOVE:
                        Log.d(TAG , "===view MotionEvent.ACTION_MOVE===");
                        break;
                    case MotionEvent.ACTION_UP:
                        Log.d(TAG , "===view MotionEvent.ACTION_UP===");
                        break;
                    case MotionEvent.ACTION_CANCEL:
                        Log.d(TAG , "===view MotionEvent.ACTION_CANCEL===");
                        break;
                    }
                    return true;
                }
            });
            ((MyViewPager)container).addView(view);
            return view;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            ((MyViewPager)container).removeView((View) object);
        }

    }
}

二、事件分发测试:

1、点击:

logcat:

分析:

内部view的setOnTouchListener的onTouch()方法返回true,ACTION_DOWN、ACTION_UP事件都由内部view消费掉了。

2、滑动(滑一点点,ViewPager未改变):

logcat:

分析:

分析:

内部view的setOnTouchListener的onTouch()方法返回true,ACTION_DOWN、ACTION_MOVE、ACTION_UP事件都由内部view消费掉了。

3、滑动:

logcat:

分析:内部view的ACTION_CANCEL事件被触发,后续事件被外部viewpager接管。

总结:

前提:内部view的setOnTouchListener的onTouch()方法返回true。(表示该View内部消化掉了所有事件)

滑动viewpager去切换不同的item时:

当滑动的距离没有达到临界值(通常viewpager还在当前item),事件会一直作用在内部的view身上,

当滑动的距离(像素点)达到一定阀值(临界值)时(通常viewpager已滑到下一个item),会触发内部view的ACTION_CANCEL事件。后续的ACTION_MOVE、ACTION_UP都被viewpager接管,作用在外面的viewpager身上。

三、案例

图片轮播图:

效果图:

自定义轮播图viewpager代码:

package com.example.zwdzjs.view;

import java.util.List;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.logutil.LogUtil;
import com.example.zwdzjs.R;
import com.lidroid.xutils.BitmapUtils;

public class RollViewPager extends ViewPager {

    private String TAG = "RollViewPager";

    private Context context;
    private List<String> titleList;
    private List<String> urlImgList;
    private TextView top_news_title;
    private MyRollViewPagerAdapter adapter;
    private BitmapUtils bitmapUtils;
    private int currentItem = 0;
    private OnViewPagerItemClickListener onItemClickListener;

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            RollViewPager.this.setCurrentItem(currentItem);
            startRoll();
        }
    };

    public RollViewPager(Context context, final List<View> dotviewList, OnViewPagerItemClickListener onViewPagerItemClickListener) {
        super(context);
        this.context = context;
        this.onItemClickListener = onViewPagerItemClickListener;
        bitmapUtils = new BitmapUtils(context);

        this.setOnPageChangeListener(new OnPageChangeListener() {
            @Override
            public void onPageSelected(int arg0) {
                top_news_title.setText(titleList.get(arg0));
                for (int i = 0; i < dotviewList.size(); i++) {
                    if (arg0 == i) {
                        dotviewList.get(i).setBackgroundResource(R.drawable.dot_focus);
                    } else {
                        dotviewList.get(i).setBackgroundResource(R.drawable.dot_normal);
                    }
                }
            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
            }

            @Override
            public void onPageScrollStateChanged(int arg0) {
            }
        });

        this.setCurrentItem(currentItem);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        handler.removeCallbacksAndMessages(null);
    }

    private int downX;
    private int downY;
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            // 让当前viewpager的父控件不去拦截touch事件
            getParent().requestDisallowInterceptTouchEvent(true);
            downX = (int) ev.getX();
            downY = (int) ev.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            int moveX = (int) ev.getX();
            int moveY = (int) ev.getY();
            if (Math.abs(moveX - downX) >= Math.abs(moveY - downY)) {
                // 滑动轮播图
                getParent().requestDisallowInterceptTouchEvent(true);
            } else {
                // 刷新listview
                getParent().requestDisallowInterceptTouchEvent(false);
            }
            break;
        }
        return super.dispatchTouchEvent(ev);
    }

    public void initTitleLists(TextView top_news_title, List<String> titleList) {
        if (null != top_news_title && null != titleList && titleList.size() > 0) {
            top_news_title.setText(titleList.get(0));
        }
        this.titleList = titleList;
        this.top_news_title = top_news_title;
    }

    public void initUrlImgList(List<String> urlImgList) {
        this.urlImgList = urlImgList;
        LogUtil.d(TAG, "=====urlImgList size:"+urlImgList.size());
    }

    /**
     * 滚动viewpager
     */
    public void startRoll() {
        if (adapter == null) {
            adapter = new MyRollViewPagerAdapter();
            this.setAdapter(adapter);
        } else {
            adapter.notifyDataSetChanged();
        }

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                currentItem = (currentItem + 1)%urlImgList.size();
                handler.obtainMessage().sendToTarget();
            }
        }, 3000);
    }

    class MyRollViewPagerAdapter extends PagerAdapter {

        @Override
        public int getCount() {
            return urlImgList.size();
        }

        @Override
        public boolean isViewFromObject(View arg0, Object arg1) {
            return arg0 == arg1;
        }

        @Override
        public Object instantiateItem(ViewGroup container, final int position) {
            View view = View.inflate(context, R.layout.viewpager_item, null);
            ImageView imageView = (ImageView) view.findViewById(R.id.image);
            bitmapUtils.display(imageView, urlImgList.get(position));
            view.setOnTouchListener(new OnTouchListener() {
                private int downX;
                private int downY;
                private long downTime;
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        handler.removeCallbacksAndMessages(null);
                        downX = (int)event.getX();
                        downY = (int)event.getY();
                        downTime = System.currentTimeMillis();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        break;
                    case MotionEvent.ACTION_UP:
                        if (System.currentTimeMillis() - downTime < 500
                                && Math.abs(downX - event.getX()) < 5
                                && Math.abs(downY - event.getY()) < 5) {

                            LogUtil.d(TAG, "=====imageView被点击了, 跳转到对应新闻内容页面");
                            // 接口回调
                            if (onItemClickListener != null) {
                                onItemClickListener.onClick(position);
                            }
                        }
                        startRoll();
                        break;
                    case MotionEvent.ACTION_CANCEL:
                        startRoll();
                        break;
                    }
                    return true;
                }
            });
            ((RollViewPager)container).addView(imageView);
            return imageView;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            ((RollViewPager)container).removeView((View) object);
        }
    }

    /**
     * viewpager 的 item 被点击时 回调用的接口
     * @author lenovo
     *
     */
    public interface OnViewPagerItemClickListener  {
        public void onClick(int i);
    }
}

问题:

手指touch到轮播图上时,暂停轮播。手动滑动到下一轮播图后,程序不能自动轮播了

解决方法:

时间: 2024-10-12 08:41:45

Android——ViewPager和内部view之间的事件分发及轮播图的相关文章

Android 源码解析View的touch事件分发机制

概述 本篇主要分析的是touch事件的分发机制,网上关于这个知识点的分析文章非常多.但是还是想通过结合自身的总结,来加深自己的理解.对于事件分发机制,我将使用两篇文章对其进行分析,一篇是针对View的事件分发机制解析,一篇是针对ViewGroup的事件分发机制解析.本片是对View的事件分发机制进行解析,主要采用案例结合源码的方式来进行分析. 前言 在分析事件分发机制之前,我们先来学习一下基本的知识点,以便后面的理解. View中有两个关键方法参与到Touch事件分发 dispatchTouch

Android轮播图的实现

Android轮播图的实现 这几天看了<Android开发艺术探索>这本书真的是挺不错的,学了自定义View之后打算动手实践一个轮播图控件,网上有很多实现的方法,我最后实现起来跟他们也基本上都是大同小异,主要我也是为了练练动手能力.先来个效果图,图片是在百度搜的正经图片 分析 实现轮播图的方式大体上我看到了三种,一是使用安卓的Gallery控件来实现,二是使用HorizontalScrollView,三是使用ViewPager来实现,Gallery控件现在已经不推荐使用了,在源码中我们也看到了

Android查缺补漏(View篇)--事件分发机制源码分析

在上一篇博文中分析了事件分发的流程及规则,本篇会从源码的角度更进一步理解事件分发机制的原理,如果对事件分发规则还不太清楚的童鞋,建议先看一下上一篇博文 <Android查缺补漏(View篇)--事件分发机制> ,先来看一下本篇的分析思路,一会儿会按照事件传递的顺序,针对以下几点进行源码分析: Activity对点击事件的分发过程 PhoneWindow是如何处理点击事件的 顶级View对点击事件的分发过程 View对点击事件的处理过程 Activity对点击事件的分发过程 通过上一篇博文中我们

Android开发之ViewPager实现轮播图(轮播广告)效果的自定义View

最近开发中需要做一个类似京东首页那样的广告轮播效果,于是采用ViewPager自己自定义了一个轮播图效果的View. 主要原理就是利用定时任务器定时切换ViewPager的页面. 效果图如下: 主页面布局实现如下: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android&

Android ViewPager实现循环轮播图

一.原理 ViewPager是Android中使用频率相对较高的view组件,同时对滑动过程中的事件进行了处理,因此非常适合轮播图.关于轮播图的实现,有很多方法,使用HorizontalView或者RecylerView也可以实现,但是需要处理fling操作,这里我们用ViewPager避免这些工作. 网上有很多关于ViewPager轮播的轮播实现,其原理大多数给PagerAdapter的getCount 放大N倍,N大于100,1000等.这里我们使用另一种思路,数据映射. 数据映射方案:假设

android ViewPager实现的轮播图广告自定义视图,网络获取图片和数据

public class SlideShowAdView extends FrameLayout { //轮播图图片数量    private static int IMAGE_COUNT = 3;    //自动轮播的时间间隔    private final static int TIME_INTERVAL = 5;    //自动轮播启用开关    private final static boolean isAutoPlay = false;       //自定义轮播图的资源ID   

Android自己定义控件之轮播图控件

背景 近期要做一个轮播图的效果.网上看了几篇文章.基本上都能找到实现,效果还挺不错,可是在写的时候感觉每次都要单独去又一次在Activity里写一堆代码.于是自己封装了一下.这里仅仅是做了下封装成一个控件,不必每次反复写代码了. 效果图 实现分析 轮播图的功能就是实现左右滑动的广告.图片信息展示,那我们就用ViewPager来实现,由于考虑到用户体验,我们还须要在以下加一个指示器来标示滑动到了第几张轮播图.指示器我们能够用一个线性布局来依据要展示的轮播图设置显示的View,我们要做这种一个控件没

Android自定义控件之轮播图控件

背景 最近要做一个轮播图的效果,网上看了几篇文章,基本上都能找到实现,效果还挺不错,但是在写的时候感觉每次都要单独去重新在Activity里写一堆代码.于是自己封装了一下.本篇轮播图实现原理原文出处:循环广告位组件的实现,这里只是做了下封装成一个控件,不必每次重复写代码了. 效果图 实现分析 轮播图的功能就是实现左右滑动的广告.图片信息展示,那我们就用ViewPager来实现,由于考虑到用户体验,我们还需要在下面加一个指示器来标示滑动到了第几张轮播图.指示器我们可以用一个线性布局来根据要展示的轮

ViewPager轮播图

ViewPager: 轮播图 下面的ViewPager由LinearLayout,textView,点的容器组成; ViewPager 页面切换,定时页面切换 VP技术点: 1.使用第三方UI类,只需要将完整包名加入就行2.Timer和ScheduledExecutorService3.Handler+Message或者runOnUiThread(runnable)更新界面ui4.ViewPager的适配器类 VP步骤: 1.布局 ##viewpager的使用方法       注意: 1.首先在