利用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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Java BigDecimal类型的 加减乘除运算[通俗易懂]

    Java BigDecimal类型的 加减乘除运算[通俗易懂]JavaBigDecimal类型的加减乘除运算不能像C#一样简单,需要调用方法:加法:add减法:subtract乘法:multiply除法:divide 可参考下面代码:BigDecimalbignum1=newBigDecimal("10"); BigDecimalbignum2=newBigDecimal("5"); BigDeci…

    2022年5月2日
    71
  • SOP是什么?SOP的作用是什么?如何编写SOP?

    SOP是什么?SOP的作用是什么?如何编写SOP?SOP是由StandardOperationProcedure这三个英文单词的首个字母组合而成。也就是以统一化的标准将操作流程的步骤和要求罗列出来,用于指导和规范日常工作。SOP的核心,就是把特定流程的关键问题细化及量化。SOP是以文件的方式归纳总结操作人员在实际生产过程中的具体操作步骤和应当要注意的事项,它是车间现场操作人员的作业指导模板,也是质量检验人员用于检测指导工作的依据。SOP的作用:1、把企业长期累积的经验技术记录归纳,汇总成简单易懂的标准化文件,即使出现操作人员变动也不会使已有的技

    2022年5月9日
    56
  • Docker 零基础从入门到使用

    Docker 零基础从入门到使用

    2022年2月11日
    43
  • CSS 相邻兄弟选择器

    相邻兄弟选择器(Adjacentsiblingselector)可选择紧接在另一元素后的元素,且二者有相同父元素。选择相邻兄弟如果需要选择紧接在另一个元素后的元素,而且二者有相同的父元素,可以使用

    2021年12月20日
    58
  • ifstream seekg 问题

    ifstream seekg 问题文件输入流(ifstream)读到文件尾之后,调用seekg重定向读pos类似于以下代码片段://readwholefilewhile(ifs.readline(str,strLen)){std::cout&lt;&lt;line++&lt;&lt;":"&lt;&lt;str&lt;&lt;std::endl;}ifs.seekg(0,std:…

    2022年4月29日
    59
  • 钱包地址 私钥_eth私钥就是收款地址吗

    钱包地址 私钥_eth私钥就是收款地址吗网上看到一个对比,很形象,可以用来加强理解:地址=银行卡卡号密码=银行卡密码keystore=银行卡助记词=私钥=银行卡+银行卡密码Keystore+密码=银

    2022年8月1日
    6

发表回复

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

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