利用GestureDetector实现ViewPager的滑动切换效果「建议收藏」

利用GestureDetector实现ViewPager的滑动切换效果「建议收藏」利用GestureDetector实现ViewPager的滑动切换效果

大家好,又见面了,我是你们的朋友全栈君。

目    录(本篇字数:1631)

介绍

代码及实现

优化代码


  • 介绍

    学习自定义View,这个对于初学者来说确实有点难度。因为这需要你熟悉View绘制的基本流程,不仅如此,你还需要熟悉手势识别、解决事件冲突等知识。这是一系列综合性的学习,如果想在Android方面进阶,你必须攻克这个首要技能。今天,我们的目的是学习自定义ViewGroup实现ViewPager类似的滑动效果。

    先来看一下我们要实现的效果,其实这个和原生ViewPager效果一样的。

  • 效果图

利用GestureDetector实现ViewPager的滑动切换效果「建议收藏」

    此篇是为了学习自定义View为目的文章,因为处于初学阶段,我们先从简单的实现效果一步步进阶。自定义ViewGroup必须重写父类的一个方法onLayout(),我们来看一下这个方法的介绍。

onLayout

void onLayout (boolean changed, 
                int left, 
                int top, 
                int right, 
                int bottom)

Called from layout when this view should assign a size and position to each of its children. Derived classes with children should override this method and call layout on each of their children.

Parameters
changed boolean: This is a new size or position for this view
left int: Left position, relative to parent
top int: Top position, relative to parent
right int: Right position, relative to parent
bottom int: Bottom position, relative to parent

大意:这个方法用于对子视图进行布局,分配子视图大小和位置。ViewGroup必须重写这个方法,根据子视图的左上、右下角的坐标来确定其大小和位置。

  • 代码及实现

    那么,让我们继承ViewGroup来实现这样效果。先看一下我们的MyViewPager类,它简单的对子视图进行了布局。

/**
 * @Created by xww.
 * @Creation time 2018/8/13.
 */

public class MyViewPager extends ViewGroup {

    private GestureDetector mGestureDetector;

    public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        mGestureDetector = new GestureDetector(context, new GestureDetector.OnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                return false;
            }

            @Override
            public void onShowPress(MotionEvent e) {

            }

            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return false;
            }

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                scrollBy((int) distanceX, getScrollY());
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {

            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                return false;
            }
        });
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            //对于每个子View进行布局
            View childView = getChildAt(i);
            childView.layout(i * getWidth(), t, (i + 1) * getWidth(), b);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        return true;
    }
}

    对于每个子视图(图片)进行了全屏幕的占用,我们看onLayout()方法里的代码,先获取了每个子视图,对子视图进行大小和位子的设置。这里我们依照ViewPager,将子视图横向排成一排,每一张图片占一整个屏幕。下面是我们添加图片的代码,不予解释了。

    private int[] imgs = {R.drawable.bg_01, R.drawable.bg_02, R.drawable.bg_03, R.drawable.bg_04, R.drawable.bg_05, R.drawable.bg_06};

    private void initViewPager() {
        for (int img : imgs) {
            AppCompatImageView imageView = new AppCompatImageView(getContext());
            imageView.setBackgroundResource(img);
            myViewpager.addView(imageView);
        }
    }

    这里我用到了GestureDetector类,这个类指明是手势识别器,它内部封装了一些常用的手势操作的接口,比如单机、双击、长按、滚动等。因为我们用到滚动手势,所以我们在这里中断(处理)它的事件。对于scrollTo、scrollBy、Scroller有疑问的可以看我之前的一篇文章:理解scrollTo、scrollBy、Scroller的一些区别及用法,掌握视图滚动方式以及屏幕坐标系

    根据手指滑动产生的distanceX,我们进行子视图的滚动,并且在onTouchEvent中处理我们的手势识别器的事件。到了这一步,我们变可以看到它的滑动效果。

利用GestureDetector实现ViewPager的滑动切换效果「建议收藏」

  • 优化代码

    是不是和我们预想的不太一样?动是可以动了,但它不会自己动,还会卡在中间,是不是感觉很不爽。那这样子的话,我们就得借助另一个滚动视图的类Scroller类。同理,这个类的用法在上面一个快捷链接中也有说明,这里我就不讲它是如何使用了。我们看看最终修改后的MyViewPager类。

/**
 * @Created by xww.
 * @Creation time 2018/8/13.
 */

public class MyViewPager extends ViewGroup {

    private GestureDetector mGestureDetector;
    private int currentIndex;
    private int startX;
    private int endX;
    private Scroller mScroller;

    public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = new Scroller(context);
        mGestureDetector = new GestureDetector(context, new GestureDetector.OnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                return false;
            }

            @Override
            public void onShowPress(MotionEvent e) {

            }

            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return false;
            }

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                scrollBy((int) distanceX, getScrollY());
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {

            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                return false;
            }
        });
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            //对于每个子View进行布局
            View childView = getChildAt(i);
            childView.layout(i * getWidth(), t, (i + 1) * getWidth(), b);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = (int) event.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                endX = (int) event.getX();

                int tempIndex = currentIndex;
                if (startX - endX > getWidth() / 2) {    //从右往左滑动
                    tempIndex++;
                } else if (endX - startX > getWidth() / 2) {    //从左往右滑动
                    tempIndex--;
                }
                scrollIndex(tempIndex);
                break;
        }
        return true;
    }

    /**
     * 移动到指定页面
     */
    private void scrollIndex(int tempIndex) {
        //第一页,无法继续向左滑动
        if (tempIndex < 0) {
            tempIndex = 0;
        }
        //同理,最后一页无法向右滑动
        if (tempIndex > getChildCount() - 1) {
            tempIndex = getChildCount() - 1;
        }
        currentIndex = tempIndex;
        mScroller.startScroll(getScrollX(), 0, currentIndex * getWidth() - getScrollX(), 0);
        postInvalidate();
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), 0);
            postInvalidate();
        }
    }
}

    它实现的思路:我们给予每张图片一个下标,当我们将当前页面滚动的距离大于屏幕宽度的一半时,子视图将自动滚动到下一张图;同理,当前页面滚动的距离小于屏幕宽度的一半,那将自动恢复原始状态,不会滚动到下一张图。主要是在onTouchEvent()方法中,标记起始点和滑动后的最终点的坐标距离,用滑动距离比对屏幕的一半宽度,然后在处理是否要切换图片。代码实现不是很难,多于理解它实现的原理,相信你很快就会掌握自定义View。

©原文链接:https://blog.csdn.net/smile_Running/article/details/81634308

@作者博客:_Xu2WeI

@更多博文:查看作者的更多博文

转载于:https://www.cnblogs.com/xww0826/p/10359504.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/107363.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • eidos云矿机_空投挖矿

    eidos云矿机_空投挖矿eidos空投矿机虽然已经有几款网页版的了,甚至还有收费的,但并不适合长期运行,特别是需要挂在VPS里,所以就出现了这款控制台运行的,如果觉得对你有帮助就给个star吧。项目地址https://github.com/donjan-deng/eidos-miner环境需求nodejs>=10scatter>=11(网页版可在低版本运行)使用方法也有个简易的网页版…

  • Tomcat在Linux上的安装与配置「建议收藏」

    Tomcat在Linux上的安装与配置「建议收藏」Tomcat在Linux上的安装与配置  以下使用的Linux版本为:RedhatEnterpriseLinux7.0x86_64,Tomcat版本为tomcat-7.0.54.1.下载JDK与Tomcat.  jdk下载地址:  http://www.oracle.com/technetwork/java/javase/downloads/j

  • 大数据的两种处理方式是什么_大数据的基本处理模式

    大数据的两种处理方式是什么_大数据的基本处理模式大数据的处理方式有两种:基于内存的流式处理和基于硬盘的存储处理。流式处理就好象是在经过的数据面前建一道水闸。数据流过这里,经过闸门的时候,就进行筛选过滤,分析出有价值的内容,然后丢弃,以后也不再使用

  • 夫妻的对话

    夫妻的对话

  • 矩阵行列式的几何意义是什么_矩阵的几何意义和物理意义

    矩阵行列式的几何意义是什么_矩阵的几何意义和物理意义矩阵行列式的几何意义 行列式的定义: 行列式是由一些数据排列成的方阵经过规定的计算方法而得到的一个数。当然,如果行列式中含有未知数,那么行列式就是一个多项式。它本质上代表一个数值,这点请与矩阵区别开来。矩阵只是一个数表,行列式还要对这个数表按照规则进一步计算,最终得到一个实数、复数或者多项式。 一阶行列式 (注意不是绝对值) …

    2022年10月30日
  • python文件操作的相关函数_python 高级

    python文件操作的相关函数_python 高级前言:本博文主要讲解Python文件操作的写法,属于Python高级语法。基础语法见:深入浅出Python——Python基础语法全解,更多内容请访问博主的主页,谢谢!文章目录一、文件操作的作用二、文件的基本操作1.文件操作步骤1.1打开1.1.1打开文件模式1.1.2快速体验2.1文件对象方法1.2.1写1.2.2读1.2.3seek()3.1关闭三、文件备份1.步骤2.代码实现3.思考四、文件和文件夹的操作1.文件重命名2.删除文件3.创建文件夹4.删除文件夹5.获

    2022年10月17日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号