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

相关文章
|
5月前
|
Android开发 UED 计算机视觉
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
本文介绍了一款受游戏“金铲铲之战”启发的Android自定义View——线条等待动画的实现过程。通过将布局分为10份,利用`onSizeChanged`测量最小长度,并借助画笔绘制动态线条,实现渐变伸缩效果。动画逻辑通过四个变量控制线条的增长与回退,最终形成流畅的等待动画。代码中详细展示了画笔初始化、线条绘制及动画更新的核心步骤,并提供完整源码供参考。此动画适用于加载场景,提升用户体验。
454 5
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
|
5月前
|
Android开发
Android自定义view之利用PathEffect实现动态效果
本文介绍如何在Android自定义View中利用`PathEffect`实现动态效果。通过改变偏移量,结合`PathEffect`的子类(如`CornerPathEffect`、`DashPathEffect`、`PathDashPathEffect`等)实现路径绘制的动态变化。文章详细解析了各子类的功能与参数,并通过案例代码展示了如何使用`ComposePathEffect`组合效果,以及通过修改偏移量实现动画。最终效果为一个菱形图案沿路径运动,源码附于文末供参考。
|
5月前
|
Android开发 开发者
Android自定义view之利用drawArc方法实现动态效果
本文介绍了如何通过Android自定义View实现动态效果,重点使用`drawArc`方法完成圆弧动画。首先通过`onSizeChanged`进行测量,初始化画笔属性,设置圆弧相关参数。核心思路是不断改变圆弧扫过角度`sweepAngle`,并调用`invalidate()`刷新View以实现动态旋转效果。最后附上完整代码与效果图,帮助开发者快速理解并实践这一动画实现方式。
141 0
|
5月前
|
Android开发 数据安全/隐私保护 开发者
Android自定义view之模仿登录界面文本输入框(华为云APP)
本文介绍了一款自定义输入框的实现,包含静态效果、hint值浮动动画及功能扩展。通过组合多个控件完成界面布局,使用TranslateAnimation与AlphaAnimation实现hint文字上下浮动效果,支持密码加密解密显示、去除键盘回车空格输入、光标定位等功能。代码基于Android平台,提供完整源码与attrs配置,方便复用与定制。希望对开发者有所帮助。
|
5月前
|
XML Java Android开发
Android自定义view之网易云推荐歌单界面
本文详细介绍了如何通过自定义View实现网易云音乐推荐歌单界面的效果。首先,作者自定义了一个圆角图片控件`MellowImageView`,用于绘制圆角矩形图片。接着,通过将布局放入`HorizontalScrollView`中,实现了左右滑动功能,并使用`ViewFlipper`添加图片切换动画效果。文章提供了完整的代码示例,包括XML布局、动画文件和Java代码,最终展示了实现效果。此教程适合想了解自定义View和动画效果的开发者。
226 65
Android自定义view之网易云推荐歌单界面
|
5月前
|
XML 前端开发 Android开发
一篇文章带你走近Android自定义view
这是一篇关于Android自定义View的全面教程,涵盖从基础到进阶的知识点。文章首先讲解了自定义View的必要性及简单实现(如通过三个构造函数解决焦点问题),接着深入探讨Canvas绘图、自定义属性设置、动画实现等内容。还提供了具体案例,如跑马灯、折线图、太极图等。此外,文章详细解析了View绘制流程(measure、layout、draw)和事件分发机制。最后延伸至SurfaceView、GLSurfaceView、SVG动画等高级主题,并附带GitHub案例供实践。适合希望深入理解Android自定义View的开发者学习参考。
558 84
|
5月前
|
前端开发 Android开发 UED
讲讲Android为自定义view提供的SurfaceView
本文详细介绍了Android中自定义View时使用SurfaceView的必要性和实现方式。首先分析了在复杂绘制逻辑和高频界面更新场景下,传统View可能引发卡顿的问题,进而引出SurfaceView作为解决方案。文章通过Android官方Demo展示了SurfaceView的基本用法,包括实现`SurfaceHolder.Callback2`接口、与Activity生命周期绑定、子线程中使用`lockCanvas()`和`unlockCanvasAndPost()`方法完成绘图操作。
115 3
|
5月前
|
Android开发 开发者
Android自定义view之围棋动画(化繁为简)
本文介绍了Android自定义View的动画实现,通过两个案例拓展动态效果。第一个案例基于`drawArc`方法实现单次动画,借助布尔值控制动画流程。第二个案例以围棋动画为例,从简单的小球直线运动到双向变速运动,最终实现循环动画效果。代码结构清晰,逻辑简明,展示了如何化繁为简实现复杂动画,帮助读者拓展动态效果设计思路。文末提供完整源码,适合初学者和进阶开发者学习参考。
Android自定义view之围棋动画(化繁为简)
|
5月前
|
Java Android开发 开发者
Android自定义view之围棋动画
本文详细介绍了在Android中自定义View实现围棋动画的过程。从测量宽高、绘制棋盘背景,到创建固定棋子及动态棋子,最后通过属性动画实现棋子的移动效果。文章还讲解了如何通过自定义属性调整棋子和棋盘的颜色及动画时长,并优化视觉效果,如添加渐变色让白子更明显。最终效果既可作为围棋动画展示,也可用作加载等待动画。代码完整,适合进阶开发者学习参考。
105 0
|
5月前
|
传感器 Android开发 开发者
Android自定义view之3D正方体
本文介绍了如何通过手势滑动操作实现3D正方体的旋转效果,基于Android自定义View中的GLSurfaceView。相较于使用传感器控制,本文改用事件分发机制(onTouchEvent)处理用户手势输入,调整3D正方体的角度。代码中详细展示了TouchSurfaceView的实现,包括触控逻辑、OpenGL ES绘制3D正方体的核心过程,以及生命周期管理。适合对Android 3D图形开发感兴趣的开发者学习参考。

热门文章

最新文章