Android ViewDragHelper:控制子View能否拖曳及水平方向的拖曳边界(2)

简介: Android ViewDragHelper:控制子View能否拖曳及水平方向的拖曳边界(2)附录文章1简单介绍了Android ViewDragHelper的使用,注意到附录文章1的代码运行结果,附录文章1的示例有三个子view,每个子view均可拖曳,但是,它们可以拖曳越出边界超出屏幕的显示范围,被拖曳到视野看不到的地方去了。


Android ViewDragHelper:控制子View能否拖曳及水平方向的拖曳边界(2)

附录文章1简单介绍了Android ViewDragHelper的使用,注意到附录文章1的代码运行结果,附录文章1的示例有三个子view,每个子view均可拖曳,但是,它们可以拖曳越出边界超出屏幕的显示范围,被拖曳到视野看不到的地方去了。
(1)在某些情况下,也许开发者不希望子view被拖曳到不可见的区域内,允许子view可以被拖曳,但不允许拖曳到不可见找不到它们!这些需求是可以代码控制。以水平拖曳为例,意图控制子view在水平方向视野可见区域内拖曳,不允许超出边界,那么就需要在:
clampViewPositionHorizontal()
里面添加约束条件。
水平拖曳的约束条件,并不是很复杂,只是需要了解设备屏幕的坐标体系。ViewGroup进行getWidth()获得的是该ViewGroup整个占据的屏幕坐标宽度,在我写的这个例子中,因为是MATCH_PARENT,且只有一个布局铺满整个屏幕,那么getWidth()就是完整的宽度。当用户在水平左边拖曳拖曳到极限位置(超出左边屏幕),那么此时clampViewPositionHorizontal()的left值为负数,意为越界,在这里下手,如果left值超出左边的边界,直接返回一个大于0的值即可。通常在实际的布局中处于设计美观的要求会padding一些值,刚好,如果此时getPaddingLeft(),获得的就是Android系统换算后左边的宽度,那么直接返回getPaddingLeft()值即可,如果没有padding值,返回一个0也可以。
右边的情况类似但稍微复杂些,考虑一种极限情况假设子view的右边刚好拖曳到父ViewGroup的右边完全重合,此时如果哪怕再往右拖曳1个坐标单位就要越界。那么此时可以得到如下等式:
getWidth() = pos + childView.getWidth()
pos为子view的左边坐标量。
如果父布局(ViewGroup)里面再padding一些值,那么等式变形为:
getWidth() = pos + childView.getWidth()+getPaddingRight()
多一个padding值而已。
计算得到的pos值即为最右边的极限位置,入股left > pos,那么此时就表明子view要越界了,立即返回pos值,这样就控制子view无法越界了。

(2)另外,通常一个布局文件里面有很多个子view,在某些情况下,可能开发者希望特定的子view不可被拖曳,完成这一些需求,则仅仅在tryCaptureView()里面针对特定的view返回false即可,false就是告诉Android系统,这个特定的子view是不被允许拖曳的。True则允许拖曳。


按照上述原理和思路修改增强附录1文章的MyLayout(其他代码不需改动):

package zhangphil.demo;

import android.content.Context;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;


/**
 * Created by Phil on 2016/4/15.
 */
public class MyLayout extends LinearLayout {

    private ViewDragHelper mViewDragHelper;

    public MyLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        init();
    }

    private void init() {
        mViewDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelperCallback());
    }

    private class ViewDragHelperCallback extends ViewDragHelper.Callback {

        @Override
        public boolean tryCaptureView(View view, int pointerId) {
            //假设我不希望红色的子view可以被拖曳,那就加一层判断,只要是特定的view,直接返回false,false告诉Android系统,这个子view是不允许拖曳操作的。
            if (view.getId() == R.id.red)
                return false;

            return true;
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {

            //控制左边的拖曳距离,不能越界。
            //当拖曳的距离超过左边的padding值,也意味着child view越界,复位
            //默认的padding值=0
            int paddingleft = getPaddingLeft();
            if (left < paddingleft) {
                return paddingleft;
            }

            //这里是控制右边的拖曳边缘极限位置。
            //假设pos的值刚好是子view child右边边缘与父view的右边重合的情况
            //pos值即为一个极限的最右边位置,超过也即意味着拖曳越界:越出右边的界限,复位。
            //可以再加一个paddingRight值,缺省的paddingRight=0,所以即便不加也在多数情况正常可以工作
            int pos = getWidth() - child.getWidth() - getPaddingRight();
            if (left > pos) {
                return pos;
            }

            //其他情况属于在范围内的拖曳,直接返回系统计算默认的left即可
            return left;
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            return top;
        }

        @Override
        public void onViewDragStateChanged(int state) {
            /**
             switch (state) {
             case ViewDragHelper.STATE_DRAGGING:
             // 正在拖动
             break;

             case ViewDragHelper.STATE_IDLE:
             // 没有被拖拽或者正在进行fling/snap
             break;

             case ViewDragHelper.STATE_SETTLING:
             // fling完毕后被放置到一个位置
             break;
             }
             */
            super.onViewDragStateChanged(state);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return mViewDragHelper.shouldInterceptTouchEvent(event);
    }

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



代码运行结果,可以看到右上角的红色子view无法被拖到,剩余的子view控制在设计的区域范围内没有越界:



附录文章:
1,《Android ViewDragHelper(1)》链接地址:http://blog.csdn.net/zhangphil/article/details/51177588

相关文章
|
2月前
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
87 0
|
24天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
30 5
|
2月前
|
缓存 数据处理 Android开发
在 Android 中使用 RxJava 更新 View
【10月更文挑战第20天】使用 RxJava 来更新 View 可以提供更优雅、更高效的解决方案。通过合理地运用操作符和订阅机制,我们能够轻松地处理异步数据并在主线程中进行 View 的更新。在实际应用中,需要根据具体情况进行灵活运用,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在 Android 中使用 RxJava 更新 View 的技巧和方法,为开发高质量的 Android 应用提供有力支持。
|
2月前
|
缓存 调度 Android开发
Android 在子线程更新 View
【10月更文挑战第21天】在 Android 开发中,虽然不能直接在子线程更新 View,但通过使用 Handler、AsyncTask 或 RxJava 等方法,可以实现子线程操作并在主线程更新 View 的目的。在实际应用中,需要根据具体情况选择合适的方法,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在子线程更新 View 的技巧和方法,为开发高质量的 Android 应用提供支持。
32 2
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
25 2
|
2月前
|
XML 前端开发 Android开发
Android View的绘制流程和原理详细解说
Android View的绘制流程和原理详细解说
39 3
|
2月前
|
XML 前端开发 Java
安卓应用开发中的自定义View组件
【10月更文挑战第5天】自定义View是安卓应用开发的一块基石,它为开发者提供了无限的可能。通过掌握其原理和实现方法,可以创造出既美观又实用的用户界面。本文将引导你了解自定义View的创建过程,包括绘制技巧、事件处理以及性能优化等关键步骤。
|
3月前
|
缓存 搜索推荐 Android开发
安卓应用开发中的自定义View组件实践
【9月更文挑战第10天】在安卓开发领域,自定义View是提升用户体验和实现界面个性化的重要手段。本文将通过一个实际案例,展示如何在安卓项目中创建和使用自定义View组件,包括设计思路、实现步骤以及可能遇到的问题和解决方案。文章不仅提供了代码示例,还深入探讨了自定义View的性能优化技巧,旨在帮助开发者更好地掌握这一技能。
|
3月前
|
Android开发
Android中SurfaceView的双缓冲机制和普通View叠加问题解决办法
本文介绍了 Android 平台上的 SurfaceView,这是一种高效的图形渲染控件,尤其适用于视频播放、游戏和图形动画等场景。文章详细解释了其双缓冲机制,该机制通过前后缓冲区交换来减少图像闪烁,提升视觉体验。然而,SurfaceView 与普通 View 叠加时可能存在 Z-Order 不一致、同步问题及混合渲染难题。文中提供了使用 TextureView、调整 Z-Order 和创建自定义组合控件等多种解决方案。
140 9