利用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

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Pygame学习笔记 6 —— 3D游戏

    Pygame学习笔记 6 —— 3D游戏    pygame是是上世纪的产品,虽然不适合最3D游戏,但我可以使用pygame来绘制简单的3D图形,就像在白纸上画立体图形一样。主要内容:视觉上的远近、3D空间基本知识、绘制一个空间图形…

    2022年5月26日
    49
  • 织梦程序做的网站,会员下载的弹窗问题

    织梦程序做的网站,会员下载的弹窗问题

    2021年9月25日
    39
  • 模型剪枝学习笔记 — EagleEye: Fast Sub-net Evaluation for Efficient Neural Network Pruning

    模型剪枝学习笔记 — EagleEye: Fast Sub-net Evaluation for Efficient Neural Network Pruning论文:https://arxiv.org/abs/2007.02491代码:https://github.com/anonymous47823493/EagleEye这篇论文一定要好好研究下,提出该剪枝方法的是暗物智能科技&中山大学,当初去面试过该公司,聊了将近一小时,大部分是关于剪枝的内容。。。。。。。可惜自己真实菜如狗。。。。。…

    2022年8月16日
    9
  • Vue(renren-fast_vue_master)项目目录结构[通俗易懂]

    Vue(renren-fast_vue_master)项目目录结构[通俗易懂]打算做一个请假管理OA项目Demo,后端采用renren-fast框架,后台管理系统采用renren-fast_vue_master项目,打算利用renren-fast-vue-master改造成一个简单的请假管理系统,包含注册、登陆、请假流程查看等等简单的展示即可,由于之前没做过Vue,现简单地介绍下项目目录结构:├──build/#Webpack配…

    2025年7月6日
    4
  • coredns_coredns配置域名

    coredns_coredns配置域名网上的coredns.yaml文档都是粘贴复制的,不知所以然,授人以鱼不如授人以渔,官方corednsyaml文件下载地址:https://github.com/kubernetes/kubernetes/blob/master/cluster/addons/dns/coredns/coredns.yaml.base1.下载corednsyamlwget不下来的手动去复制吧root@master01:mkdir/data/work/yaml/coredns/root@master01:~#c

    2025年8月19日
    2
  • 4.4.2分类模型评判指标(一) – 混淆矩阵(Confusion Matrix)

    4.4.2分类模型评判指标(一) – 混淆矩阵(Confusion Matrix)简介混淆矩阵是ROC曲线绘制的基础,同时它也是衡量分类型模型准确度中最基本,最直观,计算最简单的方法。一句话解释版本:混淆矩阵就是分别统计分类模型归错类,归对类的观测值个数,然后把结果放在一个表里展示出来。这个表就是混淆矩阵。数据分析与挖掘体系位置混淆矩阵是评判模型结果的指标,属于模型评估的一部分。此外,混淆矩阵多用于判断分类器(Classifier)的优劣,适用于…

    2022年5月14日
    55

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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