xml地图|网站地图|网站标签 [设为首页] [加入收藏]

澳门皇家网上娱乐View的Touch事件分发,事件传递

来源:http://www.ccidsi.com 作者:最新解决方案 人气:51 发布时间:2020-03-15
摘要:IOS的AssistiveTouch效果很炫目,能够专断拖拽,同不常间点击后博览会开菜单栏。然则,那不只是IOS的特权,Android也得以完成。不过出于悬浮窗要求提请权限,所以本文仅在app内落成,能

IOS的Assistive Touch效果很炫目,能够专断拖拽,同不常间点击后博览会开菜单栏。然则,那不只是IOS的特权,Android也得以完成。不过出于悬浮窗要求提请权限,所以本文仅在app内落成,能够放肆拖拽,并得以响应点击事件。

操纵事件分发传递机制的利用情形,分析各个意况下的事件冲突(表未来点击滑动失效等),开拓与扩大自定义控件的效果与利益,相同的时间也是面试中的首要根基知识点。

1. 说明


这节课大家就来解析系View的Touch事件分发的顺序。

一、效果图

澳门皇家网上娱乐 1

作用依然不错的。上海体育场面来看固然从未像IOS同样弹出菜单栏,仅仅以Toast和旋转动漫的效果取代了(因为太懒了,更光彩夺目的效用交给你们的想象了)。不过真正支撑点击事件,何况和拖拽事件不冲突。

Github地址:FloatingDragButton

根基知识

2. 分析

public class MainActivity extends AppCompatActivity {

    private TouchView touch_view;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        touch_view = (TouchView) findViewById(R.id.touch_view);

        touch_view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("TAG" , "触摸onTouch() -> "   event.getAction()) ;
                return true;
            }
        });


        touch_view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("TAG" , "点击onClick -> ") ;
            }
        });
    }
}

public class TouchView extends View {

    public TouchView(Context context) {
        super(context);
    }

    public TouchView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public TouchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("TAG" , "onTouchEvent -> "   event.getAction()) ;
        return super.onTouchEvent(event);
    }
}

地方一:onTouchListener、onTouch、onClick多个皆有个别意况下,而且onTouchListener重返false

03-25 08:18:36.589 3344-3344/com.jackchen.view_day010_2 E/TAG: 触摸onTouch() -> 0
03-25 08:18:36.589 3344-3344/com.jackchen.view_day010_2 E/TAG: onTouchEvent -> 0
03-25 08:18:36.672 3344-3344/com.jackchen.view_day010_2 E/TAG: 触摸onTouch() -> 2
03-25 08:18:36.672 3344-3344/com.jackchen.view_day010_2 E/TAG: onTouchEvent -> 2
03-25 08:18:36.851 3344-3344/com.jackchen.view_day010_2 E/TAG: 触摸onTouch() -> 1
03-25 08:18:36.851 3344-3344/com.jackchen.view_day010_2 E/TAG: onTouchEvent -> 1
03-25 08:18:36.852 3344-3344/com.jackchen.view_day010_2 E/TAG: 点击onClick -> 

由上述可以知道:0代表DOWN、2表示MOVE、1表示UP,实行顺序如下:
onTouchListener的DOMN -> onTouch的DOWN ->
onTouchListener的MOVE -> onTouch的MOVE ->
onTouchListener的UP -> onTouch的UP ->
onClick

场景二:onTouchListener、onTouch、onClick七个皆有些景况下,而且onTouchListener再次来到true

03-25 08:25:30.493 23991-23991/? E/TAG: 触摸onTouch() -> 0
03-25 08:25:30.625 23991-23991/? E/TAG: 触摸onTouch() -> 2
03-25 08:25:30.625 23991-23991/? E/TAG: 触摸onTouch() -> 1

施行各种如下:
onTouchListener的DOWN -> onTouchListener的MOVE -> onTouchListener的UP

现象三:只有 onTouchEvent()、onClickListener(),前提是onTouchEvent返回true;

03-25 09:19:11.648 3005-3005/? E/TAG: onTouchEvent -> 0
03-25 09:19:11.752 3005-3005/? E/TAG: onTouchEvent -> 2
03-25 09:19:11.752 3005-3005/? E/TAG: onTouchEvent -> 1

推行各种如下:
onTouch伊夫nt的DOWN -> onTouch伊夫nt的MOVE -> onTouchEvent的UP,不会推行onClick事件

二、完毕原理

很简单,设置TouchListener监听,实现onTouch方法,在ACTION_MOVE的历程中随着x,y坐标的移位更新退换按键的职位。上边具体介绍重写onTouch方法的现实贯彻。

监听ACTION_DOWN事件

case MotionEvent.ACTION_DOWN:{ mDownPointerId = MotionEventCompat.getPointerId; mPreviousX = event.getRawX(); mPreviousY = event.getRawY(); break; }

记录伊始的坐标以致触摸点。

监听ACTION_MOVE事件

case MotionEvent.ACTION_MOVE:{ if (mDownPointerId >= 0) { int index = MotionEventCompat.getActionIndex; int id = MotionEventCompat.getPointerId(event, index); if (id == mDownPointerId) { boolean update = adjustMarginParams(view, event); if  { break; } mFloatView.requestLayout(); mHasMoved = true; result = true; } } break; }

此中最器重的是adjustMarginParams(view, event卡塔尔国方法,来更新更换按钮的周旋地方。

private boolean adjustMarginParams(View v, MotionEvent event) { float x = event.getRawX(); float y = event.getRawY(); float deltaX = x - mPreviousX; float deltaY = y - mPreviousY; if (!mHasMoved) { if (Math.abs < mTouchSlop && Math.abs < mTouchSlop) { return false; } } //左上角位置 int newX = x - mFloatView.getWidth() / 2; int newY = y - mFloatView.getHeight() / 2; newX = Math.max(newX, mBoundsInScreen.left   mEdgePaddingLeft); newX = Math.min(newX, mBoundsInScreen.right - mEdgePaddingRight - mFloatView.getWidth; newY = Math.max(newY, mBoundsInScreen.top   mEdgePaddingTop); newY = Math.min(newY, mBoundsInScreen.bottom - mEdgePaddingBottom - mFloatView.getHeight; mFloatViewWindowParam.x = newX; mFloatViewWindowParam.y = newY - mParentMarginTop; return true; }

里头mBoundsInScreen代表浮动开关可活动的矩形范围。

据书上说近日event内的坐标与mBoundsInScreen范围相比,选拔最后拖拽到达的地点,设置给浮动开关的构造参数mFloatViewWindowParam,然后调用requestLayout更新布局。

监听ACTION_UP/ACTION_CANCEL

case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL:{ if (mDownPointerId >= 0 && mHasMoved) { event.setAction(MotionEvent.ACTION_CANCEL); adjustMarginParams(view, event); mFloatView.requestLayout(); int center = (mBoundsInScreen.width() - mFloatView.getWidth / 2; int x = mFloatViewWindowParam.x; int destX = 0; int posX = Gravity.LEFT; //抬起时 根据位置强制把浮动按钮归于左边或右边 if (x < center) { // 左边 destX = mBoundsInScreen.left   mEdgePaddingLeft; } else { posX = Gravity.RIGHT; destX = mBoundsInScreen.right - mEdgePaddingRight - mFloatView.getWidth(); } if (mFloatButtonCallback != null) { float posY = 0; if (mBoundsInScreen.height() - mFloatView.getHeight { posY = 1f * (mFloatViewWindowParam.y - mBoundsInScreen.top) / (mBoundsInScreen.height() - mFloatView.getHeight; } mFloatButtonCallback.onPositionChanged(destX, mFloatViewWindowParam.y, posX, posY); } int deltaHorizon = destX - x; //小于100直接移动 否则开启动画 if (Math.abs(deltaHorizon) < 100) { mFloatViewWindowParam.x = destX; mFloatView.requestLayout(); } else { ValueAnimator animator = ValueAnimator.ofInt; animator.setInterpolator(mInterpolator); if (mUpdateListener == null) { mUpdateListener = new FloatAnimatorUpdateListener(); mUpdateListener.setUpdateView(FloatTouchListener.this); } animator.addUpdateListener(mUpdateListener); animator.setDuration; animator.start(); } } resetStatus(); break; } }

兑现当抬起的瞬,依照当下所处坐标靠左依然靠右,把变化开关置于左侧缘只怕左侧缘。同期,调用回调,把运动相对地点传给回调函数,达成拖拽监听。

当从这段日子地方移动到左/侧面缘的偏离小于100时,直接移动,不然达成动画减速移动作效果果。

那般总结便可达成自由拖拽的效果与利益了,具体有个别细节要细看源码达成。

Event

在不停的接受场景下伊夫nt可以分成Key伊芙nt, TouchEvent, HoverEvent。

Key伊夫nt:针对遥控或能够按动的按键

事件流:
dispatchKeyEventPreIme、dispatchKeyEvent、onKeyDown、view.onKeyListener、view.onClickListener
KeyEvent.ACTION_DOWN
KeyEvent.ACTION_UP

TouchEvent:针对扶植触摸的荧屏

Android中的事件首要有一些按,长按,拖拽,滑动等,全体的那一个事件响应都有以下多少个事件捕捉作为底子
ACTION_DOWN
ACTION_MOVE
ACTION_UP

我们能够在上述多个状态下去依据现实的自定义控件的思想政治工作场景去动态的测算,拆解深入分析事件

Hover伊夫nt:针对鼠标的平地风波

在ViewGroup中多四个 onInterceptHoverEvent
ACTION_HOVER_ENTEWrangler 指针悬浮在view上
ACTION_HOVER_MOVE 指针在view上移动
ACTION_HOVER_EXIT 指针离开view边界

3. View和Touch相关的有2个十三分重要的方法

2.点击达成

或是有人会以为点击事件很好贯彻啊,setOnClickListener(卡塔尔(قطر‎设置个监听就足以兑现了。不相信你去探求,没用。

澳门皇家网上娱乐 2

事实上点击完成才是本篇作品的精髓,因为灵活运用到了事件分发机制。

从事件分发机制中大家知道,就优先级来讲:onTouchListener>onClickListenr。

上边包车型客车拖拽事件早就开销了onTouchListener(即onTouch方法中回到true卡塔尔国,那么就不会发出到onClickListenr,自然就不会发生点击事件。

莫不你想让onTouchListener不开支,然后不就下发到onClickListenr了么?

真的那样能够实现点击事件,可是拖拽效能又完成持续了。

澳门皇家网上娱乐 3

因为onTouch方法中回到false,确实onClickListenr选拔到了轩然大波,然后花销掉。可是因为onTouch方法中回到false,所以接下去的百分百事件不可能担负,不可能响应拖拽效果了。

透过地点的解析,最后的淹不能够正是:onTouch方法中,在选取到ACTION_DOWN后,返回false,交给onClickListenr处理。剩下的ACTION_MOVE/ACTION_UP等事件,再次回到true,交给onTouchListener管理,那样自然就能够既完结拖拽效果又达成点击效果了。

具体达成以上面伪代码为例

 public boolean onTouch(View view, MotionEvent event) { int action = MotionEventCompat.getActionMasked; if (mFloatButtonCallback != null) { mFloatButtonCallback.onTouch(); } boolean result = false; switch  { case MotionEvent.ACTION_DOWN:{ .................................................... break; } case MotionEvent.ACTION_MOVE:{ .................................................... result = true; break; } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL:{ ................................................ break; } } return result; }

规律正是那般轻便,特别炫目的功效可自定义实现,向往就点个star扶植下吧!

Github地址:

Android中触摸事件首要设计的四个办法

public boolean dispatchTouchEvent(MotionEvent event)

用以事件的分发,Android中颇有事件都首先通过那几个主意的散发,然后决定是自己花销当前事变大概三回九转往下分发给子控件。
归来true表示事件部分发,事件被花费;
回到false则持续往下分发。

public boolean onInterceptTouchEvent(MotionEvent event)

那是ViewGroup特有的必定要经过的道路,因为ViewGroup中可能还会有子View,而在Android中View中是不可能再饱含子View的(iOS能够)。它的作用是担任事件的阻碍
回到true表示拦截当前事变,结束往下分发,接着交给笔者的onTouchEvent(卡塔尔举办拍卖。
回去false则不阻碍,继续往下传。

public boolean onTouchEvent(MotionEvent event)

用来本级事件的管理
回去true表示开支管理当下事变
归来false则不管理,交给子控件实行三回九转分发。

3.1>:dispatchTouch伊芙nt(State of Qatar事件分发:

源码剖析:
在View源码中的 dispatchTouchEvent(卡塔尔(قطر‎方法中:

/**
     * Pass the touch screen motion event down to the target view, or this
     * view if it is the target.
     *
     * @param event The motion event to be dispatched.
     * @return True if the event was handled by the view, false otherwise.
     */
    public boolean dispatchTouchEvent(MotionEvent event) {
        // If the event should be handled by accessibility focus first.
        if (event.isTargetAccessibilityFocus()) {
            // We don't have focus or no virtual descendant has it, do not handle the event.
            if (!isAccessibilityFocusedViewOrHost()) {
                return false;
            }
            // We have focus and got the event, then use normal event dispatch.
            event.setTargetAccessibilityFocus(false);
        }

        boolean result = false;

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);
        }

        final int actionMasked = event.getActionMasked();
        if (actionMasked == MotionEvent.ACTION_DOWN) {
            // Defensive cleanup for new gesture
            stopNestedScroll();
        }

        if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }

        if (!result && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }

        // Clean up after nested scrolls if this is the end of a gesture;
        // also cancel it if we tried an ACTION_DOWN but we didn't want the rest
        // of the gesture.
        if (actionMasked == MotionEvent.ACTION_UP ||
                actionMasked == MotionEvent.ACTION_CANCEL ||
                (actionMasked == MotionEvent.ACTION_DOWN && !result)) {
            stopNestedScroll();
        }

        return result;
    }

以上中:
boolean result = false;
ListenerInfo 很要紧,它在那之中存放了View的富有的Listener消息,举例:onTouchListener、onClickListener

ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null               
   && (mViewFlags & ENABLED_MASK) == ENABLED
   && li.mOnTouchListener.onTouch(this, event)) {
       result = true;
}

本文由68399皇家赌场发布于最新解决方案,转载请注明出处:澳门皇家网上娱乐View的Touch事件分发,事件传递

关键词: 68399皇家赌场 按钮 and 拖拽 FloatingDrag

上一篇:皇家娱乐平台登陆:卡片式布局

下一篇:没有了

最火资讯