View.OnDragListener, ViewDragHelper, GestureDetector --- 拖放滑动

ViewDragHelper移动效果动画 ViewDrawHelper能够更好的帮助我们处理程序中的滑动效果,但是也比较复杂,需要开发者对事件拦截,滑动处理都要比较清楚的认知,才能实现更好丰富的滑动效果。 阅读详情

【记录】记录点滴

【场景】学习官方文档和sample时,实验的内容以及遇到的小坑

【需求】简单实现,基于View.OnDragListener, ViewDragHelper以及GestureDetector(或OnTouchEvent,OnTouchListener)实现拖放View滑动的效果

1. View.OnDragListener

官方文档提供了示例demo,包括实现拖放,自定义拖放时阴影的样式。

如果要实现拖放功能,需要1)创建View.OnDragListener,它是拖放事件的监听器;2)某些View过ViewGroup需要监听拖放事件,并根据操作状态实现需要的效果,因此对这些View设置创建好的View.OnDragListener监听器;3)创建一个View被拖放时的影子,并调用方法表明开始拖放操作。顺序不是固定的,感觉这个顺序比较好理解。

    //自定义的拖放监听器,未实现任何操作
    class DragerListener implements View.OnDragListener {
        @Override
        public boolean onDrag(View v, DragEvent event) {
            int action = event.getAction();
            switch (event.getAction()) {
                case DragEvent.ACTION_DRAG_STARTED:
                    /** 拖拽开始时 */
                    break;
                case DragEvent.ACTION_DRAG_ENTERED:
                    /** 拖拽进入区域时 */
                    break;
                case DragEvent.ACTION_DRAG_Location:
                    /** 拖拽进入区域后,仍在区域内拖动时 */
                    break;
                case DragEvent.ACTION_DRAG_EXITED:
                    /** 离开区域时 */
                    break;
                case DragEvent.ACTION_DROP:
                    /** 在区域内放开时 */
                    break;
                case DragEvent.ACTION_DRAG_ENDED:
                    /** 结束时 */
                default:
                    break;
            }
            return true;
        }
    }

 画一个简单的图说明,假设这是个手机屏幕,黑色圆是需要我们拖拽的View,红色矩形就是需要监听拖放事件并进行响应的区域。 首先创建拖放的监听器,随后仅仅对红色矩形(实际的应用场景中可能是View,也可能是ViewGroup)设置监听器,最后设置黑色圆的拖放阴影,并在适当的场景(如touch,longclick等)下告诉系统,我们开始了拖放操作。

开始拖拽圆时,触发START操作

DragEvent.ACTION_DRAG_STARTED

 当拖拽的点(通常是被拖拽的View的中心点)进入到红色的矩形区域后,触发ENTERED操作

DragEvent.ACTION_DRAG_ENTERED

 当拖拽的点一直在红色区域内移动时,会不断地触发LOCATION操作

DragEvent.ACTION_DRAG_LOCATION

 如果拖拽的点仍在红色区域内时,释放了被拖拽的View,则会触发DROP。因为DROP可以理解为是与区域绑定的,所以一次DROP只会交给一个对象来处理。脑补下,如果左下角还有个蓝色区域也监听了拖放事件,但是我们在红色区域内释放了View,那么只有红色区域的监听器会触发DROP操作

DragEvent.ACTION_DROP

并且在释放后,会触发ENDED操作

DragEvent.ACTION_DRAG_ENDED

另一种情况,如果拖拽的点移动出了区域,那么会触发EXITED操作

DragEvent.ACTION_DRAG_EXITED

到这里,应该可以弄清楚监听器的各操作类型的触发条件了。实现简单的拖拽

按照之前的描述,先自定义监听器,处理各种类型的操作

class DragListener implements View.OnDragListener {

        @Override
        public boolean onDrag(View v, DragEvent event) {
            int action = event.getAction();
            switch (event.getAction()) {
                case DragEvent.ACTION_DRAG_STARTED:
                    break;
                case DragEvent.ACTION_DRAG_ENTERED:
                    Log.e("lxy", "ACTION_DRAG_ENTERED");
                    //这个v就是监听拖拽事件的View,对照上面的图就是红色矩形区域
                    //拖拽进入区域后,变成蓝色背景
                    v.setBackgroundColor(Color.BLUE);
                    break;
                case DragEvent.ACTION_DRAG_LOCATION:
                    Log.e("lxy", "ACTION_DRAG_LOCATION");
                    break;
                case DragEvent.ACTION_DRAG_EXITED:
                    Log.e("lxy", "ACTION_DRAG_EXITED");
                    //拖拽出区域后,恢复成红色背景
                    v.setBackgroundColor(Color.RED);
                    break;
                case DragEvent.ACTION_DROP:
                    //释放后,v变成灰色背景
                    //也可以根据需求,做处理,比如“展示拖拽进来的图片”
                    v.setBackgroundColor(Color.GRAY);
                    break;
                case DragEvent.ACTION_DRAG_ENDED:
                default:
                    break;
            }
            return true;
        }
    }

随后,对View设置监听器

//layout1对应为上述内容中的红色区域
FrameLayout layout1 = findViewById(R.id.layout1);
layout1.setOnDragListener(mDragListen);

 最后创建默认的拖拽阴影,并在适当的情况下告诉系统我们开始拖拽了

    mDrag1.setOnLongClickListener(v -> {
            //创建拖拽阴影
            View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(mDrag1);
            //告诉系统开始拖拽了
            v.startDrag(null, shadowBuilder, v, 0);
            return true;
        });

 至此,就可以简单实现拖放功能了,这里去除了其他博客中都会有的ClipData,因为我没有要传的数据。

不过这种实现还是有些局限,比如我们拖拽的是生成的阴影,拖拽过程中View本身不会移动,释放后View也不会改变位置。

附上另一个demo的截图来说明,拖拽第一个View时,以及执行DROP后。

                        

如果希望改变View改变位置,觉得(因为没试过,假如有坑呢)可以让父布局监听拖拽事件,并在LOCATION或DROP/ENDED这些操作中来改变View的位置等等。

PS:如果希望修改拖拽的阴影,可以参考官方的示例,自定义个View.DragShadowBuilder

private static class MyDragShadowBuilder extends View.DragShadowBuilder {
 
// The drag shadow image, defined as a drawable thing
private static Drawable shadow;
 
    // Defines the constructor for myDragShadowBuilder
    public MyDragShadowBuilder(View v) {
 
        // Stores the View parameter passed to myDragShadowBuilder.
        super(v);
 
        // Creates a draggable image that will fill the Canvas provided by the system.
        shadow = new ColorDrawable(Color.LTGRAY);
    }
 
    // Defines a callback that sends the drag shadow dimensions and touch point back to the
    // system.
    @Override
    public void onProvideShadowMetrics (Point size, Point touch)
        // Defines local variables
        private int width, height;
 
        // Sets the width of the shadow to half the width of the original View
        width = getView().getWidth() / 2;
 
        // Sets the height of the shadow to half the height of the original View
        height = getView().getHeight() / 2;
 
        // The drag shadow is a ColorDrawable. This sets its dimensions to be the same as the
        // Canvas that the system will provide. As a result, the drag shadow will fill the
        // Canvas.
        shadow.setBounds(0, 0, width, height);
 
        // Sets the size parameter's width and height values. These get back to the system
        // through the size parameter.
        size.set(width, height);
 
        // Sets the touch point's position to be in the middle of the drag shadow
        touch.set(width / 2, height / 2);
    }
 
    // Defines a callback that draws the drag shadow in a Canvas that the system constructs
    // from the dimensions passed in onProvideShadowMetrics().
    @Override
    public void onDrawShadow(Canvas canvas) {
 
        // Draws the ColorDrawable in the Canvas passed in from the system.
        shadow.draw(canvas);
    }
}

2. ViewDragHelper

另一中简单实现拖拽的方式就是借助于ViewDragHelper,为了研究OnDragListener而查看官方sample时,竟发现sample是用这个实现的。

首先ViewDragHelper必须结合ViewGroup使用。1)自定义ViewGroup,创建ViewDragHelper;2)ViewGroup中让ViewDragHelper来处理事件拦截(onInterceptTouchEvent)和事件消费(onTouchEvent)。

首先,创建ViewDragHelper

//this是ViewGroup,1f代表灵敏度,越大越灵敏,DragCallback是ViewDragHelper.Callback,提供触摸过程中回调的相关方法
mViewDragHelper = ViewDragHelper.create(this, 1f, new DragCallback());

 然后让ViewDragHelper来处理事件拦截和事件消费

 @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getActionMasked();
        if (action == MotionEvent.ACTION_CANCEL
                || action == MotionEvent.ACTION_UP) {
            mViewDragHelper.cancel();
            return false;
        }
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }
@Override
    public boolean onTouchEvent(MotionEvent event) {
        mViewDragHelper.processTouchEvent(event);
        return true;
    }

 ViewDragHelper的使用只需要这几步,很简单。接下来,分析记录下之前的DragCallback。DragCallback继承了ViewDrag.Callback,主要包含以下几个回调方法,先学习最简单和常用的几个,写了注释的。

//child水平方向上的坐标,left是child要移动过去的位置,dx是相对于上次的偏移量
int clampViewPositionHorizontal(View child, int left, int dx)

//child垂直方向上的坐标,top是child要移动过去的位置,dy是相对于上次的偏移量
int clampViewPositionVertical(View child, int top, int dy)

int getOrderedChildIndex(int index)

int getViewHorizontalDragRange(View child)

int getViewVerticalDragRange(View child)

void onEdgeDragStarted(int edgeFlags, int pointerId)

boolean onEdgeLock(int edgeFlags)

void onEdgeTouched(int edgeFlags, int pointerId)

//捕获时,即tryCaptureView返回true时触发
void onViewCaptured(View capturedChild, int activePointerId)

void onViewDragStateChanged(int state)

void onViewPositionChanged(View changedView, int left, int top, int dx, int dy)

//释放时触发
void onViewReleased(View releasedChild, float xvel, float yvel)

//能否捕获child,如果能捕获(返回true),才可以执行后续的拖拽
abstract boolean tryCaptureView(View child, int pointerId)

那么基于tryCaptureView,clampViewPositionHorizontal,clampViewPositionVertical,onViewCaptured以及onViewReleased就可以简单实现拖拽效果了。如下,自定义的DragCallback最后长这样,参考Google sample

    dragViews = new ArrayList<View>();
    public void addDragView(View view){
        dragViews.add(view);
    }


    class DragCallback extends ViewDragHelper.Callback{
        @Override
        public boolean tryCaptureView(@NonNull View child, int pointerId) {
            //可以拖拽的View,事先会通过addDragView方法添加到dragViews中
            if(dragViews.contains(child)){
                return true;
            }
            return false;
        }

        @Override
        public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
            return left;
        }

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

        @Override
        public void onViewCaptured(@NonNull View capturedChild, int activePointerId) {
            super.onViewCaptured(capturedChild, activePointerId);
            //捕获时,可以做些处理
        }

        @Override
        public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
            //释放时,可以做些处理,如下做了释放后回弹至某个位置的处理
            //这两个方法实际是基于Scroller实现的,最终会调用startScroll方法,所以回弹效果要结合computeScroll()来实现
            //如果不做处理,释放后View会停留在释放的位置
//            mViewDragHelper.settleCapturedViewAt(0, 0);
            mViewDragHelper.smoothSlideViewTo(releasedChild, 0, 0);
            invalidate();
        }
    }


    @Override
    public void computeScroll() {
        if(mViewDragHelper.continueSettling(true)){
            invalidate();
        }
    }

 在onViewReleased中,有settleCapturedViewAt和smoothSlideviewTo两个方法,他们的区别在于回弹时的起始速度。这里还必须使用invalidate()之类的强制重绘方法,用来触发computeScroll

相较于OnDragListener,ViewDragHelper更简单,更适用于单纯的拖拽。

补充:介绍下其他的回调方法。

1)边缘滑动:实现边缘滑动,要先代码设置,下面列举了多种实用方式

//可以多重组合使用
//可以滑动左边缘 和 右边缘
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT | ViewDragHelper.EDGE_RIGHT);
//可以单侧边缘
//可以滑动上边缘
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_TOP);
//可以滑动下边缘
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_BOTTOM);
//可以滑动所有边缘
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_ALL);

对应边缘滑动的几个回调方法是


//边缘被点击
void onEdgeTouched(int edgeFlags, int pointerId)

//边缘拖拽开始,可以手动调用captureChildView触发从边缘拖动View的效果
void onEdgeDragStarted(int edgeFlags, int pointerId)

//返回true,表示锁定指定的边缘,锁定后即使设置了setTrackingEnabled,滑动也不会触发onEdgeDragStared
//返回false,不锁定指定的边缘
boolean onEdgeLock(int edgeFlags)

实现边缘滑动,通常重写onEdgeDragStarted方法,调用captureChildView指定滑动的View,如下

@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
    super.onEdgeDragStarted(edgeFlags, pointerId);
    //dragViews.get(0)是基于上面内容的View,指定随边缘滑动的View
    mViewDragHelper.captureChildView(dragViews.get(0),pointerId);
}

那为什么,只需要调用captureChildView就可以实现边缘滑动?

在使用ViewDragHelper时,我们会让ViewDragHelper来处理事件拦截和事件消费。简单分析下这两部分的代码

首先是事件拦截,onInterceptTouchEvent中的shouldInterceptTouchEvent

点击时,toCapture是findTopChildUnder根据(x, y)触摸点计算得到的View,而此时mCapturedView为null,mDragState为STATE_IDLE。所以无论在什么情况下(触摸点(x, y)在View上或(x, y) 没在View上),都不会执行tryCaptureViewForDrag。

PS,这里还牵扯到了比较复杂的事件分发机制,暂时不在这里记录了。

public boolean shouldInterceptTouchEvent(@NonNull MotionEvent ev) {
        ...
        ...
        ...
        switch (action) {
            case MotionEvent.ACTION_DOWN: {
                final float x = ev.getX();
                final float y = ev.getY();
                final int pointerId = ev.getPointerId(0);
                saveInitialMotion(x, y, pointerId);

                final View toCapture = findTopChildUnder((int) x, (int) y);

                // Catch a settling view if possible.
                if (toCapture == mCapturedView && mDragState == STATE_SETTLING) {
                    tryCaptureViewForDrag(toCapture, pointerId);
                }

                final int edgesTouched = mInitialEdgesTouched[pointerId];
                if ((edgesTouched & mTrackingEdges) != 0) {
                    mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
                }
                break;
            }
            ...
            ...
            ...
        }
        ...
        ...
        ...
        return mDragState == STATE_DRAGGING;    
    }

接着是事件消费,onTouchEvent中的processTouchEvent。

因为Touch不会再走onInterceptTouchEvent,所以接着分析processTouchEvent,里面关键的是tryCaptureViewForDrag方法。

public void processTouchEvent(@NonNull MotionEvent ev) {
        ...
        ...
        ...
        switch (action) {
            case MotionEvent.ACTION_DOWN: {
                final float x = ev.getX();
                final float y = ev.getY();
                final int pointerId = ev.getPointerId(0);
                final View toCapture = findTopChildUnder((int) x, (int) y);

                saveInitialMotion(x, y, pointerId);

                // Since the parent is already directly processing this touch event,
                // there is no reason to delay for a slop before dragging.
                // Start immediately if possible.
                tryCaptureViewForDrag(toCapture, pointerId);

                final int edgesTouched = mInitialEdgesTouched[pointerId];
                if ((edgesTouched & mTrackingEdges) != 0) {
                    mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
                }
                break;
            }
            ...
            ...
            ...
        }
    }

 在tryCaptureViewForDrag方法中,如果tryCaptureView如果返回true,就会执行captureChildView。这个captureChildView就是最开始提到的,实现边缘滑动的关键。也就是它指定了要滑动的View,mCapturedView,并设置STATE_DRAGGING状态。然后在processTouchEvent处理ACTION_MOVE时,就会对mCapturedView处理滑动。

所以在重写onEdgeDragStarted方法时,调用captureChildView来指定要滑动的View就能实现边缘滑动了。

 

 

 参考了

 https://blog.youkuaiyun.com/briblue/article/details/73730386

 https://www.cnblogs.com/liemng/p/4997427.html

3. GestureDetector(或OnTouchEvent,OnTouchListener)

其实,想到拖拽,我们一般第一反应就是重写Touch相关的处理方法,比如对View设置setOnTouchListener,重写ViewGroup中的OnTouchEvent等。所以借这个机会,简单记录下GestureDetector。

使用的话,包括:1)创建手势监听器;2)创建手势类;3)让手势类处理Touch事件。

这个是第一次写的代码,貌似逻辑很正确,distanceX与distanceY是最近两次Touch的差值,可以利用getX与getY验证,lastX - e2.getX的值一致的。

mGestureDetector = new GestureDetector(this, new DragGestureListener);

//为了看着舒服,去除了部分必要的方法
class DragGestureListener extends GestureDetector.OnGestureListener{
    @Override
            public boolean onDown(MotionEvent e) {

                return true;
            }

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                if(Math.abs(distanceX) > ViewConfiguration.getWindowTouchSlop() 
                    || Math.abs(distanceY) > ViewConfiguration.getWindowTouchSlop()){
                    ViewCompat.offsetLeftAndRight(mDrag3, (int) -distanceX);
                    ViewCompat.offsetTopAndBottom(mDrag3, (int) -distanceY);
                }
                return true;
            }


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

 情况一:对View使用

用它来处理View的Touch事件。但是!拖动的过程中抖动很大(单向滑动时,distanceX与distanceY的值抖动),不顺畅。

//Activity中,对View设置
mDrag3.setOnTouchListener((v, event) -> {
    mGestureDetector.onTouchEvent(event);
    return true;
})

情况二:在ViewGroup中使用

简单修改onScroll后,将这部分代码放到ViewGroup中,就不会发生抖动的问题,虽然还是有点顿顿的(把TouchSlop的判断去掉就好了)。

    //自定义ViewGrup中,修改
    //修改监听器的onScroll,拖拽的是ViewGroup中的子View,dragV
    ...
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        if(Math.abs(distanceX) > ViewConfiguration.getWindowTouchSlop() 
            || Math.abs(distanceY) > ViewConfiguration.getWindowTouchSlop()){
            ViewCompat.offsetLeftAndRight(dragV, (int) -distanceX);
            ViewCompat.offsetTopAndBottom(dragV, (int) -distanceY);
        }
        return true;
    }
    ...


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
       return true;
    }


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

GestureDetectore的内部源码还没有研究,针对于第一种情况,先只重写Touch事件消费来实现试试,利用getX与getY方法计算得到move的dx距离后,会发生抖动,那么用getRawX与getRawY计算得到dx后就不会。原来是这样,忘记了getX与getRawX的区别,他们的参考点是不同。借用其他博客的一张图,

对View使用时,View自身会移动,也就是说getX方法的参考点也发生了移动,那么dx当然会产生抖动的情况。虽然还没看GestureDetectore的相关源码,但是估计onScroll中的distanceX,distanceY是基于getX,getY方法计算得到的,然后通过getRawX验证下了猜测,这里就不粘贴内容了。想想,对于情况一,我的使用思路可能就存在问题。

PS,示例想简单点,所以很多内容需要根据实际的需求来完善,如,应该完善事件拦截onInterceptTouchEvent,判断哪些情况应该拦截;判断Down事件是否落在子View上;限制拖拽的边界等

参考

https://blog.youkuaiyun.com/dmk877/article/details/51550031

 

两个Recyclerview之间利用View.onDragListener相互拖放item交换数据(Drag-on-Drop) 两个Recyclerview之间利用View.onDragListener相互拖放item交换数据(Drag-on-Drop),并且可以拖放排序,同一个Recyclerview之间利用ItemTouchHelper进行拖放排序. 立即下载

相关推荐

LBS之五:时空索引--空间邻域搜索的高效实践

时空索引的原理及最佳实践

whascj的博客 1367

拖放 Drag and drop

拖放 Drag and drop android11-release Android Developers > Docs > Guides Drag and drop Android 开发者 > 文档 > 指南 拖放 View.OnDragListener 实现 View.OnDragListener 的拖动事件监听器或其 onDragEvent(DragEvent) 回调方法来接收拖动事件 拖放过程中四种状态:开始、继续、放下、结束 Drag and drop 监听拖拽事件D

许浑的博客 1257

硬全桥副边钳位管Vds电压凸台揭秘——寄生参数引发的导通异常

本文深入分析了硬全桥副边钳位管Vds电压凸台现象,揭示了寄生参数如何引发导通异常。通过波形分析和工程实践,详细解析了走线电感的蓄能效应和体二极管的接力作用,并提供了PCB布局优化、元件选型和驱动电路调整等解决方案,帮助工程师有效应对这一常见问题。

weixin_30825581的博客 430

Android 拖拽滑动(OnDragListener和ViewDragHelper)

文章目录1 ViewDragHelper2 OnDragListener 两个都是Google提供的,为什么要提供两种拖拽工具?各自的使用场景有什么不同? 1 ViewDragHelper 2 OnDragListener

Vincent的博客 9704

CANOCO5.0实现冗余分析(RDA)最详细步骤

在地理及生态领域会常使用RDA分析,RDA的实现路径也有很多,今天介绍一下CANOCO软件的实现方法。1.不同样点和环境因子之间夹角是锐角 是正相关,是钝角是负相关。2.夹角越大 说明相关性较小,夹角越小,相关性越大。得有不同的物种或者样点数值,再加上环境因子数据。3.箭头越长 相关性越大。时间调整到2010年。

Along6的博客 1万+

DIY玩家必备:用SSS1623芯片打造高性价比USB麦克风(附完整电路图)

本文详细介绍了如何利用SSS1623芯片DIY高性价比USB麦克风,包括元件选型、电路设计、PCB布局及调试技巧。通过完整的电路参考设计和实用建议,帮助电子爱好者打造专业级录音设备,实现免驱动即插即用功能。

weixin_29166013的博客 239

ViewDragHelper简单使用

首先扯点别的:感觉保护好身体真的很重要,前几天膝盖又拉伤了,今天跑了会步感觉有点疼,看样最近一个月是不能跑步了。今天看了看鸿洋大神的ViewDrawHelper感觉写的不错,学习一下。ViewDrawHelper的类定义如下/** * ViewDragHelper is a utility class for writing custom ViewGroups. It offers a numbe

leilifengxingmw的博客 1366

FPGA开发者必看:手把手教你用Xilinx ERNIC IP实现RoCE v2网络加速(附PG332文档解读)

本文详细解析了Xilinx ERNIC IP在FPGA平台上实现RoCE v2网络加速的全流程,包括架构设计、Vivado工程配置、驱动开发与性能调优。通过PG332技术文档的实践指导,帮助开发者快速构建低延迟、高性能的网络加速方案,适用于数据中心和边缘计算场景。

weixin_29168813的博客 670

ViewDragHelper解析

ViewDragHelper 它主要用于处理ViewGroup中对子View的拖拽处理,本质是对触摸事件的解析类。 ViewDrager是简化view拖拽操作的帮助类,ViewDragHelper解决了android中手势处理过于复杂的问题。 1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中 2.它主要用于处理ViewGroup中对子Vie...

qq_36699930的博客 1108

执行HDevelop项目

这一节,我们讲述的是如何用HDevEngine加载和执行一个HDevelop项目。代码部分来源于示例程序exec_program(源文件exec_program.cpp),检测塑料零件边界上的毛刺。1.Step 1:初始化首先,我们包含HALCON/C++和HDevEngine头文件以及命名空间。注意到在这个示例程序中,HDevEngine头文件已经包含在my_hdevoperatorimpl中,所

Z's Palace 2997

基于Termux的Android平台OpenClaw部署:移动端AI助理实现

本文介绍了在Android设备上通过Termux部署OpenClaw AI助理的方案。Android设备的便携性、Termux提供的完整Linux环境以及多样化的硬件配置使其成为理想的部署平台。文章详细分析了不同级别Android设备的硬件规格(从入门级到旗舰级),并提供了最低/推荐配置要求。部署步骤包括Termux安装初始化、Python环境配置以及性能优化建议。该方案充分利用Android设备的传感器和电池供电优势,为移动办公、学习等场景提供了低成本、高便携性的AI助理解决方案。

博客 3015

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

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

Zhang Phil 3382

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Android ViewDragHelper使用总结

Android中的ViewDragHelper类(2013年出来的),使用的人算是比较少的把,但是它也是有一些特殊效果能实现,一般应用场合是拖动效果的设计。

wenzhi的博客 3174

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Android ViewDragHelper及移动处理总结

概述2013年谷歌i/o大会上介绍了两个新的layout: SlidingPaneLayout和DrawerLayout,现在这俩个类被广泛的运用。我们知道在我们实际的开发中往往会涉及到很多的拖动效果,而ViewDragHelper解决了android中手势处理过于复杂的问题。 其实ViewDragHelper并不是第一个用于分析手势处理的类,gesturedetector也是,但是在和拖动相关的

xiangzhihong8的专栏 8039

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Android单页面,Android实现单页面浮层可拖动view的示例代码

需求是需要在一个已经存在的页面添加一个可拖动的浮层广告。使用到的技术:ViewDragHelper效果如图:封装好的类(继承自FrameLayout)import android.content.Context;import android.support.annotation.AttrRes;import android.support.annotation.NonNull;import and...

weixin_27037521的博客 284

Android 拖动滑出滑入的布局 自定义ViewDragHelper详解

先给大家看效果图吧、需求:将复杂的内容布局 通过向右拖拽或者是快速向右滑动将其移动到最右边 当在向左拖动或者是快速向左滑动会将移除的布局恢复到原位使用方法github源码 欢迎star fork https://github.com/shf981862482/SunMultiLibcompile 'com.slidelayout:slipe_layout_library:0.0.3'//

qq_28195645的博客 4688

ViewDragHelper 的使用及源码分析

ViewDragHelper 是一个关于拖动view的辅助类,一般view的位移有几种方法,一般都是监听view的 onTouchEvent() 事件,我们需要作出一系列判断,如果再加上边界值的判断,比如滑到父控件左边时提示用户到了边缘,滑到了右边时要结束当前Activity,这种情况我们需要进一步判断,添加回调,这样写下来,一方面是麻烦,另外一方面是代码繁琐,不利于扩展并不利于复用,为了解决这些...

Deaht_Huimie的博客 414

ViewDragHelper详解

文章转自:   http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0911/1680.html 2013年谷歌i/o大会上介绍了两个新的layout: SlidingPaneLayout和DrawerLayout,现在这俩个类被广泛的运用,其实研究他们的源码你会发现这两个类都运用了ViewDragHelp

qq_25962525的博客 246

重写ViewGroup并借助ViewDragHelper实现各种拖拽交互效果(一)

一般实现比较复杂的交互效果,都会选择重写ViewGroup,并通过onTouchEvent和onInterceptTouchEvent等实现对各种事件的处理,但对事件的处理是很不容易的一个事情。 本文主要是借助v4包中的ViewDragHelper这个帮助类,来重写ViewGroup,把事件完全交给帮助类去完成,并借助帮助类的几个回调方法来完成各种复杂交互效果,完全避开了事件处理。 对View

Dway 2759

使用 ViewDragHelper 实现沿三个方向拖动的例子

1. 需求 先看一下效果图: 效果图 2. 需求分析 当手指拖动中间的原形图标(称为 home)时,只能向左,向右,向上三个方向拖动; 当 home 向左,向右,向上拖动时,home 的中心不能超过左,右,上三个图标的中心; 当 home 向左,向右,向上拖动时,若 home 的中心,和左,右,上三个图标的中心重合,就触发一定的操作,这里使用 toast 代替; 当...

willwaywang6 3161

ViewDragHelper详解,简化拖动操作

没想到还有这么个家伙,简直是滑动必备啊! 2013年谷歌i/o大会上介绍了两个新的layout: SlidingPaneLayout和DrawerLayout,现在这俩个类被广泛的运用,其实研究他们的源码你会发现这两个类都运用了ViewDragHelper来处理拖动。ViewDragHelper是framework中不为人知却非常有用的一个工具。 ViewDragHelper解决了

heinika的专栏 1345

Android 控件拖拽系列 ViewDragHelper

坐标,自动贴边,参考大佬的 一个Demo https://github.com/zhangqifan1/DragFloatView ViewDragHelper 1.首先是一个自定义View public class MyDragView extends LinearLayout { private ViewDragHelper viewDragHelper; pub...

FlyPig_Vip的博客 510

Android 神器ViewDragHelper(实战二)

前言: 很久以前就在以前前辈的项目中用到一个控件叫BounceScrollView,那个时候觉得有点高大上的感觉,就是可以上下弹性拉动的ScrollView,也就是仿ios那种效果,一直想去研究一下,苦逼老说自己没时间,所以就一直搁在那里,这几天刚好在研究VDH,于是想用VDH做一下. 代码不要太简单啊,我直接贴代码了,因为比较少package com.yqy.canvasdemo.back.de

vv_bug 2198
上一篇: Keyboard与KeyboardView --- 自定义键盘
下一篇: 定时任务 --- Timer, AlarmManager
FeiLaughing
博客等级 码龄11年 1粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值