首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

Android 高级UI<二>之事件分发机制&滑动冲突(2024精华版)

  • 24-04-25 17:23
  • 2973
  • 13220
juejin.cn

目录:

1.事件分发机制是怎么样的?

2.View与ViewGroup的事件分发有什么区别

3.onTouch和onTouchevent和onClick的执行顺序?

4.如何理解消费?

5.Button和ImageView有什么不一样?

6.可以达到父控件和子空间同时点击吗?

7.ListView上的button,点击button2个控件同时要有相应,应该怎么处理?

点击事件被拦截,但是相传到下面的view,如何操作?

8.请简述Android事件传递机制, ACTION_CANCEL事件何时触发?

  1. 滑动冲突源码分析

  2. 滑动冲突的几种解决方案的使用场景?什么时候用内部拦截?

11. 滑动冲突实践,实例: recleview嵌套recleview

1.事件分发机制是怎么样的?

1.1 事件分发机制分为2种:View事件的分发和[ViewGroup事件分发机制]

总结ViewGroup发现:dispathcTouchEvent开始-----disallownotIntercepter---onInterceptTouchEvent-----1.子类dispath() 2.父类TouchEvent方法

viewGroup分发.jpg

然后我们来看一下View中dispatchTouchEvent方法的源码:

csharp
复制代码
public boolean dispatchTouchEvent(MotionEvent event) { if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) { return true; } return onTouchEvent(event); }
1.2 view总结: 整个View的事件转发流程是:(原理是dispatchTouchEvent)
csharp
复制代码
public boolean dispatchTouchEvent(MotionEvent event) { if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) { return true; } return onTouchEvent(event); }
1.3 完整的总结:

1). 事件分发机制是一种责任链模式, Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View的。

2). 在ViewGroup中可以通过onInterceptTouchEvent方法对事件传递进行拦截,onInterceptTouchEvent方法返回true代表不允许事件继续向子View传递,返回false代表不对事件进行拦截,默认返回false。

3). 子View中如果将传递的事件消费掉,ViewGroup中将无法接收到任何事件。

4). .在ViewGroup中onInterceptTouchEvent方法若反回false,那么触屏事件会继续向下传递,

但如果没有子View去处理这个事件,即子view的onTouchEvent没有返回True

则最后还是由ViewGroup去处理这个事件,也就又执行了自己的onTouchEvent。

备注: ViewGroup 类中,实际是没有onTouchEvent 方法的,但是由于ViewGroup 继承自View,

1.4 深层次的总结: (从InputChannel)

在attach()方法的时候,通过上面的流程图我们知道,当我们的PhoneWindow创建完成之后,我们也在该Window上注册了InputChannel并与IMS通信,

IMS把事件写入InputChannel,WindowInputEventReceiver对事件进行处理并最终还是通过InputChannel反馈给IMS。

InputChannel最重要的!!!!!!!!

总结:兜兜转转一大圈我们神经都被绕弯了,我们在这里总结一下,当我们触摸(点击)屏幕时,

Android输入系统IMS通过对事件的加工处理再合适的Window接收者并通过InputChannel向Window派发加工后的事件,

并触发InputReceiver的onInputEvent的调用,由此产生后面一系列的调用,把事件派发给整个控件树的根DecorView

而DecorView又上演了一出偷梁换柱的把戏,先把事件交给Activity处理,在Activity中又把事件交还给了我们的DecorView。自此沿着控件树自上向下依次派发事件。

输入事件 .jpg

2.View与ViewGroup的事件分发有什么区别

ViewGruop的事件分发:

多了一个拦截事件的方法:onInterceptTouchEvent

ViewGroup的dispathcTouchEvent方法:里面有onInterceptTouchEvent方法

3.onTouch和onTouchevent和onClick的执行顺序?

csharp
复制代码
View.dispatchEvent----ontouch-----ontouchEvent(方法down,up,判断onclick时间)---onclick //子控件的ontouch方法影响子控件的函数 //onTouch====onTouchEvent====onClick; /** * 检验view的事件分发顺序,点击---dispatch- Ontouch返回值为ture 不执行---ontouchEvent---onclick */ button1.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d("TAG", "button1 on touch"+event.getAction()); return true; } }); /** * 检验view的事件分发顺序, 点击---dispatch- Ontouch返回值为false执行---ontouchEvent---onclick */ button2.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d("TAG", "button1 on touch" + event.getAction()); return false; } });

ontouch先执行,如果返回true,ontouchEvent,onClick都不执行

ontouch先执行,如果返回false,ontouchEvent,然后再是onclick方法

如果不重写onTouchListerner方法。

onTouchEvent如果返回true,不会执行onclick方法

onTouchEvent如果返回false,会执行onclick方法

onclick默认调用的是onTouchEvent。因为ontouch事件默认返回是false。那么就会响应onTochEvent。(onTouchEvent

总结:onTouch优先于onTouchEvent

1).看判断条件。如果没有mOnTouchListener ,ontouch不执行,onTouchEvent执行

2).如果有mOnTouchListener,并且onTouch =true,onTouchEvent不执行

  1. .如果有mOnTouchListener,并且onTouch =false,onTouchEvent执行

4.如何理解消费?view事件分发机制的案例

4.1 总结:

如果onTouch为true,代表消费了。不会执行onTouchevent了

如果子类的onTouchevent为true,代表消费了,父类不会执行onTouchevent

基本上就是返回true,就是消费了

4.2 案例说明

案例.jpg

当一个Touch事件(触摸事件为例)到达根节点,即Acitivty的ViewGroup时,它会依次下发,下发的过程是调用子View(ViewGroup)的dispatchTouchEvent方法实现的。

简单来说,就是ViewGroup遍历它包含着的子View,调用每个View的dispatchTouchEvent方法,而当子View为ViewGroup时,又会通过调用ViwGroup的dispatchTouchEvent方法继续调用其内部的View的dispatchTouchEvent方法。

上述例子中的消息下发顺序是这样的:①-②-⑤-⑥-⑦-③-④。

dispatchTouchEvent方法只负责事件的分发,它拥有boolean类型的返回值,当返回为true时,顺序下发会中断。

在上述例子中如果⑤的dispatchTouchEvent返回结果为true,那么⑥-⑦-③-④将都接收不到本次Touch事件

5.Button和ImageView有什么不一样?

Button和ImageView效果不一样:一个是自带点击,一个是要自己控制点击

onTouch能够得到执行需要两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。因此如果你有一个控件是非enable的,

那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。

/*
复制代码
ImageView默认是不能点击事件的,要想点击的话必须手动设置 /

typescript
复制代码
/**ImageView默认是不能点击事件的,要想点击的话必须手动设置*/ imageView.setClickable(true); imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e("TAG","imageView setOnTouchListener"); } });

6.可以达到父控件和子空间同时点击吗?

如下

7.ListView上的button,点击button2个控件同时要有相应,应该怎么处理?

7.1 具体方案:在listView的OnInterceptTouchEvent()方法里面。判断区域。是否拦截

在listView的空白区域:执行listview的onTouchEvent方法。拦截button

在button的点击区域: 不拦截,消费button的onTouchEvent事件。

当父控件是布局而子控件是控件时,如果要设置点击效果,可以在父布局里面加上android:clickable="true" ,在子控件里面设置android:clickable="false",并设置状态跟随父布局android:duplicateParentState="true",至于效果,则随自己写吧

7.2 案例分析4种情况:

1).如何让子类只有触摸事件,没有点击事件

2).如何让子类既有触摸事件又有点击事件

3).如何让父类只有触摸事件,没有点击事件

4).如何让父类既有触摸事件又有点击事件

分析总结:

  1. .onTouch为true,事件被消费了,ontouchevent不执行,点击也就不会执行
typescript
复制代码
button.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d("peng"," button.setOnTouchListener"+event.getAction()); return true; } }); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d("peng"," button.setOnClickListener"); } });

2). onTouch为false,ontouchevent会执行,这样,点击事件会执行

typescript
复制代码
button.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d("peng"," button.setOnTouchListener"+event.getAction()); return false; } }); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d("peng"," button.setOnClickListener"); } 默认情况下,子view的onTouchEvent返回true,消费 @Override public boolean onTouchEvent(MotionEvent event) { boolean pass=super.onTouchEvent(event); Log.d("peng","onTouchEvent onTouchEvent"+pass); return pass; }
  1. .父类想要响应,子类不能消费,onTouch false ,onTouchEvent 也为false,onTouch 为false
java
复制代码
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d("peng"," button.setOnClickListener"); } }); viewHead.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d("peng"," viewHead.setOnTouchListener"+event.getAction()); return true; } }); viewHead.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d("peng"," viewHead.setOnClickListener"); } }); public class Myview extends android.support.v7.widget.AppCompatButton { public Myview(Context context) { super(context); } public Myview(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public Myview(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("peng","Myview onTouchEvent onTouchEvent"+false); return false; }
  1. .父类想要响应,子类不能消费,onTouch false ,onTouchEvent 也为false,onTouch 为false .父类的onTouchEvent也要重写true,代表消费了。
typescript
复制代码
@Override public boolean onTouchEvent(MotionEvent event) { Log.d("peng","MyParentView onTouchEvent"); return true; }

子控件拿到事件之后,先判断是否设置了OnTouchListener, 如果设置了,则调用OnTouchListener的onTouch方法,如果返回true,事件已经处理到此结束,则跳过onTouchEvent方法,否则调用onTouchEvent方法

7.3 点击事件被拦截,但是想传到下面的view,如何操作?

反向制约:重写子类的requestDisallowInterceptTouchEvent()方法返回true,就不会执行父类的onInterceptTouchEvent(),即可将点击事件传到下面的View。

7.4 我想让webview在应用里面后台运行?看不到界面

2个viewGoup

1个webview和一个ViewGroup(包含4个btn)

点击btn的时候,会消费掉事件

问题:viewgroup点击空白也是会有事件的,如何给他添加监听

加入点击空白页面,Viewgroup的子View消费掉。(webview的子空间)

问题:不想让子控件消费怎么做

1).可以自己消费掉,ontouch==true。不再传递了,onclick事件就不会执行

  1. .可以让另外一个viewgourp自己消费掉。

ontouch==true,自己的onclick不会在执行,但是这个子view还是响应了

原因:因为没有拦截,走了子类的dispathevent方法。子类的dispathevent----ontouch---子类的onclick方法消费了。

所以消费是onclick和ontouch方法,但是onclick方法也是要先调用ontouch---ontouchevnet----onclick。

总结:最后的消费指的时onTouch事件

7.5 有一个布局,然后有一个textview,然后想点击整个布局有点击事件

结果发现:点击textview的区域没有响应,因为textview把焦点占用了。为了让整个区域都有效果的话,把textview设置成

ini
复制代码
android:clickable="false"

按钮视图.jpg

ini
复制代码
android:id="@+id/tv_sport_data_second_value" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="@dimen/dp_20" android:textColor="@color/color_333333" android:textStyle="bold" android:clickable="false" android:text="0" android:layout_below="@id/ll_second_title" android:layout_marginTop="@dimen/dp_6" android:id="@+id/rl_sport_data_second" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" > android:id="@+id/ll_second_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" > android:id="@+id/tv_sport_data_second_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/color_333333" android:textSize="@dimen/dp_14" android:text="@string/string_sport_rank_total_sport" >
8.请简述Android事件传递机制, ACTION_CANCEL事件何时触发?

1). 关于ACTION_CANCEL何时被触发,系统文档有这么一种使用场景:在设计设置页面的滑动开关时,如果不监听ACTION_CANCEL,在滑动到中间时,如果你手指上下移动,就是移动到开关控件之外,则此时会触发ACTION_CANCEL,而不是ACTION_UP,造成开关的按钮停顿在中间位置。
意思是当滑动的时候就会触发,不知道大家搞没搞过微信的长按录音,有一种状态是“松开手指,取消发送”,这时候就会触发ACTION_CANCEL。

2). 简单来说不是一个完整的手势响应 例如:子控件只是响应了down 而父控件把子控件的up事件拦截了 这个时候就会触发cancel事件。

详细:当控件收到前驱事件(什么叫前驱事件?一个从DOWN一直到UP的所有事件组合称为完整的手势,中间的任意一次事件对于下一个事件而言就是它的前驱事件)之后,后面的事件如果被父控件拦截,那么当前控件就会

9. 滑动冲突源码分析

10. 滑动冲突的几种解决方案的使用场景?什么时候用内部拦截?

10. 1 外部拦截法:(根据自己的业务拦截子view),重写一个方法

即父View根据需要对事件进行拦截。逻辑处理放在父View的onInterceptTouchEvent方法中。我们只需要重写父View的onInterceptTouchEvent方法,并根据逻辑需要做相应的拦截即可。

ini
复制代码
public boolean onInterceptTouchEvent(MotionEvent event) { boolean intercepted = false; int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { intercepted = false; break; } case MotionEvent.ACTION_MOVE: { if (满足父容器的拦截要求) { intercepted = true; } else { intercepted = false; } break; } case MotionEvent.ACTION_UP: { intercepted = false; break; } default: break; } mLastXIntercept = x; mLastYIntercept = y; return intercepted; }

注意点:

1). ACTION_DOWN 一定返回false,不要拦截它,否则根据View事件分发机制,后续ACTION_MOVE 与 ACTION_UP事件都将默认交给父View去处理!

2). ACTION_MOVE方法中进行判断,根据业务逻辑需要,如果需要父View处理则返回true,否则返回false,事件分发给子View去处理。

3). ACTION_UP也需要返回false,如果返回true,并且滑动事件交给子View处理,那么子View将接收不到ACTION_UP事件,子View的onClick事件也无法触发。

  • 而父View不一样,如果父View在ACTION_MOVE中开始拦截事件,那么后续ACTION_UP也将默认交给父View处理!
  • 可以直接用super。默认都是不拦截
typescript
复制代码
可以直接用super。默认都是不拦截 /*** * 如果不写整个方法的话:就会响应子类的touchEvent方法,而不响应自己viewGroup的方法 * @param * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN://0 mXDown = ev.getRawX(); mXLastMove = mXDown; break; case MotionEvent.ACTION_MOVE://2 mXMove = ev.getRawX();//获取相对于屏幕的x值 float diff = Math.abs(mXMove - mXDown); mXLastMove = mXMove; // 当手指拖动值大于TouchSlop值时,认为应该进行滚动,拦截子控件的事件 if (diff > mTouchSlop) { return true; } break; case MotionEvent.ACTION_UP://1 break; } boolean superResult = super.onInterceptTouchEvent(ev); Log.d("ScrollerLayout", "superResult" + superResult+"ev"+ev.getAction()); return superResult; }

具体:

1.down 不拦截,否则up收不到,点击事件也会没有

2.move 更加业务判定。得到子view,滑动的距离和item的位置决定

3.up 不拦截

10.1.2 具体案例写法

ini
复制代码
@Override public boolean onInterceptTouchEvent(MotionEvent event) { boolean intercepted = false; int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { nowY = y; intercepted = super.onInterceptTouchEvent(event); break; } case MotionEvent.ACTION_MOVE: { if(mListView.getFirstVisiblePosition()==0 && y>nowY){ intercepted = true; break; } else if(mListView.getLastVisiblePosition()==mListView.getCount()-1 && y intercepted = true; break; } intercepted = false; break; } case MotionEvent.ACTION_UP: { intercepted = false; break; } default: break; } return intercepted; }

10.2 内部拦截法:(拦截子view) (重写2个方法,都是事件分发的方法)

即父View不拦截任何事件,所有事件都传递给子View,子View根据需要决定是自己消费事件还是给父View处理。这需要子View使用requestDisallowInterceptTouchEvent方法才能正常工作。下面是子View的dispatchTouchEvent方法的伪代码:

1). 父View需要重写onInterceptTouchEvent方法:

为什么要重写父类的 onInterceptTouchEvent?因为默认不拦截,你需要的是拦截它

csharp
复制代码
public boolean onInterceptTouchEvent(MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) {//down不拦截,给子类 return false; } else {//拦截 return true; } }

2). 重写子类的dispatchTouchEvent()方法

csharp
复制代码
public boolean dispatchTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { parent.requestDisallowInterceptTouchEvent(true); // 父类不拦截, 子类处理 break; } case MotionEvent.ACTION_MOVE: { int deltaX = x - mLastX; int deltaY = y - mLastY; if (父容器需要此类点击事件) { parent.requestDisallowInterceptTouchEvent(false);//请求父类拦截, 父类处理 } break; } case MotionEvent.ACTION_UP: { break; } default: break; } mLastX = x; mLastY = y; return super.dispatchTouchEvent(event); }

10.2.1 内部拦截法总结:

1). 父View不能拦截ACTION_DOWN事件,由于ACTION_DOWN不受FLAG_DISALLOW_INTERCEPT标志位控制,一旦父容器拦截ACTION_DOWN那么所有的事件都不会传递给子View。

sql
复制代码
2). View的dispatchTouchEvent方法的ACTION_DOWN中, parent.requestDisallowInterceptTouchEvent(true)2). 滑动策略的逻辑放在子View的dispatchTouchEvent方法的ACTION_MOVE中,如果父容器需要获取点击事件则调用 parent.requestDisallowInterceptTouchEvent(false)方法,让父容器去拦截事件。如果不需要,则相反

10.2.2 内部拦截法原理:

1). 内部拦截法也叫View分发反向制约的方法? 2). 拦截不拦截,由2个东西决定的。一个是requestDisllowIntercepter和onInterceptTouchEvent()2个决定的。

原因:但是子元素可以通过requestDisallowInterceptTouchEvent来干预父元素的分发过程,但是down事件除外(因为down事件方法里,会清除所有的标志位)。

scss
复制代码
@Override public boolean dispatchTouchEvent(MotionEvent ev) { if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTouchEvent(ev, 1); } // If the event targets the accessibility focused view and this is it, start // normal event dispatch. Maybe a descendant is what will handle the click. if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) { ev.setTargetAccessibilityFocus(false); } if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { intercepted = onInterceptTouchEvent(ev); ev.setAction(action); // restore action in case it was changed } else { intercepted = false; }

10.3 从内容逆向思维分析

1). 有时候,我们不想去修改引入的第三方控件,或者说是无法修改时。就必须考虑从当前从Touch传递事件中最后的那个View逆向考虑。

首先,由Android中View的Touch事件传递机制,我们知道Touch事件,首先必然由最外层View拦截,如果无法更改这个最外层View,那么是不是就没辙了呢?

其实不然,Android这么高大上的系统必然考虑到了这个问题,好了废话不说,先看代码

解决方案:onTouch方法中每次进入就设定父View不拦截此次事件,然后在MOTION_MOVE时候,根据滑动的距离判断再决定是父View是否有权利拦截Touch事件(即滑动行为)。

csharp
复制代码
carouselView.setOnTouchListener( new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { carouselView.getParent().requestDisallowInterceptTouchEvent( true ); int x = ( int ) event.getRawX(); int y = ( int ) event.getRawY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = x; lastY = y; break ; case MotionEvent.ACTION_MOVE: int deltaY = y - lastY; int deltaX = x - lastX; if (Math.abs(deltaX) < Math.abs(deltaY)) { carouselView.getParent().requestDisallowInterceptTouchEvent( false ); } else { carouselView.getParent().requestDisallowInterceptTouchEvent( true ); } default : break ; } return false ; } }
2). 一个viewpager2里面放了很多图片。但是图片又可以大于屏幕,导致滑动冲突。浏览图片 ViewPager2和HorizontalScrollView滑动冲突 结果:Viewpager2不能重新怎么办?它是final类。导致内部拦截和外部拦截不适用!

重写onTouchListener();

10.4 down,move ,Up,都是否需要拦截总结?

复制代码
1). ACTION_DOWN,都不要拦截子类

在这里,首先down事件父容器必须返回false ,因为若是返回true,也就是拦截了down事件,

那么后续的move和up事件就都会传递给父容器,子元素就没有机会处理事件了。

其次是up事件也返回了false,一是因为up事件对父容器没什么意义,其次是因为若事件是子元素处理的,却没有收到up事件会让子元素的onClick事件无法

2). 要在MotionEvent.ACTION_MOVE根据情况,是父类滑动还是子类滑动

10.5 滑动冲突的几种解决方案的使用场景?什么时候用内部拦截?

主要用内部拦截,系统里面的,horscorrlview和,比如recyleview.

原因: 你只能重新你可以的, 能达到的view(主要看你哪个View是你自己的)

11. 滑动冲突实践,实例: recleview嵌套recleview

11. 1 一个ScrowView(父类)和一个RecycleView(子类)

他说重写子类的onIntecepter方法,让子类拦截,消费掉

11.2 ViewPager中嵌套ViewPager怎么处理滑动冲突?

1).重写canScroll()方法

2).自己手写
11.3 一个scorview和一个日期选择器
分析:scorllView是父类,datapinker是子类(viewGroup)

现在现象:在分辨率比较小的手机中,有时候滑动scorllView,有时候滑动dataPinker

需要实现的效果:拦截scorllView。超过1屏的时候,自己滑动

scss
复制代码
private void doMove(MotionEvent event) { mMoveLen += (event.getY() - mLastDownY); if (mMoveLen > MARGIN_ALPHA * mMinTextSize / 2) { // 往下滑超过离开距离 moveTailToHead(); mMoveLen = mMoveLen - MARGIN_ALPHA * mMinTextSize; } else if (mMoveLen < -MARGIN_ALPHA * mMinTextSize / 2) { // 往上滑超过离开距离 moveHeadToTail(); mMoveLen = mMoveLen + MARGIN_ALPHA * mMinTextSize; } mLastDownY = event.getY(); invalidate(); }
注:本文转载自juejin.cn的椰小椰的文章"https://juejin.cn/post/7361361507312500762"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

140
Android
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top