91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Androidz2如何實現EditText長按菜單中分享功能的隱藏方法

發布時間:2021-07-10 11:41:32 來源:億速云 閱讀:444 作者:小新 欄目:移動開發

小編給大家分享一下Androidz2如何實現EditText長按菜單中分享功能的隱藏方法,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

常見的EditText長按菜單如下

Androidz2如何實現EditText長按菜單中分享功能的隱藏方法

oppo

Androidz2如何實現EditText長按菜單中分享功能的隱藏方法

小米

需求是隱藏掉其中的分享/搜索功能,禁止將內容分享到其他應用。

最終解決方案

這里先說下最終解決方案

像華為/oppo等手機,該菜單實際是谷歌系統的即沒有改過源代碼,像小米的菜單則是自定義,該部分的源代碼改動過。
兩方面修改:

1.谷歌系統自帶的 通過 EditText.setCustomSelectionActionModeCallback()方法設置自定義的選中后動作模式接口,只保留需要的菜單項

代碼如下

 editText.customSelectionActionModeCallback = object : ActionMode.Callback {
 override fun onCreateActionMode(
 mode: ActionMode?,
 menu: Menu?
 ): Boolean {
 menu?.let {
 val size = menu.size()
 for (i in size - 1 downTo 0) {
 val item = menu.getItem(i)
 val itemId = item.itemId
 //只保留需要的菜單項 
 if (itemId != android.R.id.cut
 && itemId != android.R.id.copy
 && itemId != android.R.id.selectAll
 && itemId != android.R.id.paste
 ) {
 menu.removeItem(itemId)
 }
 }
 }
 return true
 }

 override fun onActionItemClicked(
 mode: ActionMode?,
 item: MenuItem?
 ): Boolean {
 return false
 }

 override fun onPrepareActionMode(
 mode: ActionMode?,
 menu: Menu?
 ): Boolean {
 return false
 }

 override fun onDestroyActionMode(mode: ActionMode?) {
 }
 }

2.小米等手機自定義菜單無法進行隱藏,可以是分享、搜索等功能失效,即在BaseActivity的startActivityForResult中進行跳轉攔截,如果是調用系統的分享/搜索功能,則不允許跳轉

 override fun startActivityForResult(
 intent: Intent?,
 requestCode: Int
 ) {
 if (!canStart(intent)) return
 super.startActivityForResult(intent, requestCode)
 }

 @SuppressLint("RestrictedApi")
 @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
 override fun startActivityForResult(
 intent: Intent?,
 requestCode: Int,
 options: Bundle?
 ) {
 if (!canStart(intent)) return
 super.startActivityForResult(intent, requestCode, options)
 }

 private fun canStart(intent: Intent?): Boolean {
 return intent?.let {
 val action = it.action
 action != Intent.ACTION_CHOOSER//分享
 && action != Intent.ACTION_VIEW//跳轉到瀏覽器
 && action != Intent.ACTION_SEARCH//搜索
 } ?: false
 }

如果以上不滿足要求,只能通過自定義長按菜單來實現自定義的菜單欄。

解決思路(RTFSC)

分析源碼菜單的創建和點擊事件

既然是長按松手后彈出的,應該在onTouchEvent中的ACTION_UP事件或者在performLongClick中,從兩方面著手
先看perfomLongEvent EditText沒有實現 去它的父類TextView中查找

TextView.java
 public boolean performLongClick() {
 ···省略部分代碼
 if (mEditor != null) {
 handled |= mEditor.performLongClick(handled);
 mEditor.mIsBeingLongClicked = false;
 }

 ···省略部分代碼
 return handled;
 }

可看到調用了 mEditor.performLongClick(handled)方法

Editor.java

 public boolean performLongClick(boolean handled) {
 if (!handled && !isPositionOnText(mLastDownPositionX, mLastDownPositionY)
 && mInsertionControllerEnabled) {
 final int offset = mTextView.getOffsetForPosition(mLastDownPositionX,
 mLastDownPositionY);//獲取當前松手時的偏移量
 Selection.setSelection((Spannable) mTextView.getText(), offset);//設置選中的內容
 getInsertionController().show();//插入控制器展示
 mIsInsertionActionModeStartPending = true;
 handled = true;
 ···
 }
 if (!handled && mTextActionMode != null) {
 if (touchPositionIsInSelection()) {
 startDragAndDrop();//開始拖動
 ···
 } else {
 stopTextActionMode();
 selectCurrentWordAndStartDrag();//選中當前單詞并且開始拖動
 ···
 }
 handled = true;
 }
 if (!handled) {
 handled = selectCurrentWordAndStartDrag();//選中當前單詞并且開始拖動
 ···
 }
 }

 return handled;
 }

從上面代碼分析

1.長按時會先選中內容 Selection.setSelection((Spannable) mTextView.getText(), offset)

2.顯示插入控制器  getInsertionController().show()

3.開始拖動/選中單詞后拖動 startDragAndDrop()/ selectCurrentWordAndStartDrag()

看著很像了

看下第二步中展示的內容

Editor.java -> InsertionPointCursorController

 public void show() {
 getHandle().show();
 if (mSelectionModifierCursorController != null) {
 mSelectionModifierCursorController.hide();
 }
 }

 ···
 private InsertionHandleView getHandle() {
 if (mSelectHandleCenter == null) {
 mSelectHandleCenter = mTextView.getContext().getDrawable(
 mTextView.mTextSelectHandleRes);
 }
 if (mHandle == null) {
 mHandle = new InsertionHandleView(mSelectHandleCenter);
 }
 return mHandle;
 }

實際是InsertionHandleView 執行了show方法。  查看其父類HandlerView的構造方法

 private HandleView(Drawable drawableLtr, Drawable drawableRtl, final int id) {
 super(mTextView.getContext());
 ···
 mContainer = new PopupWindow(mTextView.getContext(), null,
 com.android.internal.R.attr.textSelectHandleWindowStyle);
 ···
 mContainer.setContentView(this);
 ···
 }

由源碼可看出 HandlerView實際上是PopWindow的View。 即選中的圖標實際上是popwidow
看源碼可看出HandleView有兩個實現類 InsertionHandleView  和SelectionHandleView 由名字可看出一個是插入的,一個選擇的 看下HandleView的show方法

Editor.java ->HandleView

 public void show() {
 if (isShowing()) return;
 getPositionListener().addSubscriber(this, true );
 // Make sure the offset is always considered new, even when focusing at same position
 mPreviousOffset = -1;
 positionAtCursorOffset(getCurrentCursorOffset(), false, false);
 }

看下positionAtCursorOffset方法

Editor.java ->HandleView 

 protected void positionAtCursorOffset(int offset, boolean forceUpdatePosition,
 boolean fromTouchScreen) {
 ···
 if (offsetChanged || forceUpdatePosition) {
 if (offsetChanged) {
 updateSelection(offset);
 ···
 }
 ···
 }
 }

里面有一個updateSelection更新選中的位置,該方法會導致EditText重繪,再看show方法的getPositionListener().addSubscriber(this, true )

getPositionListener()返回的實際上是ViewTreeObserver.OnPreDrawListener的實現類PositionListener
重繪會調用onPreDraw的方法

Editor.java-> PositionListener 

 @Override
 public boolean onPreDraw() {
 ···
 for (int i = 0; i < MAXIMUM_NUMBER_OF_LISTENERS; i++) {
 ···
 positionListener.updatePosition(mPositionX, mPositionY,
 mPositionHasChanged, mScrollHasChanged);
 ···
 }
 ···
 return true;
 }

調用了positionListener.updatePosition方法, positionListener這個實現類對應的是HandlerView

重點在HandleView的updatePosition方法,該方法進行popWindow的顯示和更新位置

看一下該方法的實現

Editor.java ->HandleView

 @Override
 public void updatePosition(int parentPositionX, int parentPositionY,
 boolean parentPositionChanged, boolean parentScrolled) {
 ···
 if (isShowing()) {
 mContainer.update(pts[0], pts[1], -1, -1);
 } else {
 mContainer.showAtLocation(mTextView, Gravity.NO_GRAVITY, pts[0], pts[1]);
 }
 } 
 ···
 }
 }

到此我們知道選中的圖標即下面紅框內的實際上popWindow展示

Androidz2如何實現EditText長按菜單中分享功能的隱藏方法

點擊選中的圖標可以展示菜單,看下HandleView的onTouchEvent方法

Editor.java ->HandleView
 @Override
 public boolean onTouchEvent(MotionEvent ev) {
 updateFloatingToolbarVisibility(ev);
 ···
 }

updateFloatingToolbarVisibility(ev)真相在這里,該方法進行懸浮菜單欄的展示
經過進一步查找,可以看到會調用下面SelectionActionModeHelper的這個方法

SelectionActionModeHelper.java

 public void invalidateActionModeAsync() {
 cancelAsyncTask();
 if (skipTextClassification()) {
 invalidateActionMode(null);
 } else {
 resetTextClassificationHelper();
 mTextClassificationAsyncTask = new TextClassificationAsyncTask(
  mTextView,
  mTextClassificationHelper.getTimeoutDuration(),
  mTextClassificationHelper::classifyText,
  this::invalidateActionMode)
  .execute();
 }
 }

會啟動一個叫TextClassificationAsyncTask的異步任務,該異步任務最后會執行mEditor.getTextActionMode().invalidate()

 private void invalidateActionMode(@Nullable SelectionResult result) {
 ···
 final ActionMode actionMode = mEditor.getTextActionMode();
 if (actionMode != null) {
 actionMode.invalidate();
 }
 ···
 }

最后看下mTextActionMode 如何在Editor中賦值

Editor.java

 void startInsertionActionMode() {
 ···
 ActionMode.Callback actionModeCallback =
 new TextActionModeCallback(false /* hasSelection */);
 mTextActionMode = mTextView.startActionMode(
 actionModeCallback, ActionMode.TYPE_FLOATING);
 ···
 }

看下mTextView.startActionMode的注釋,在View類中,Start an action mode with the given type. 根據給的類型,開啟一個動作模式,該模式是一個TYPE_FLOATING模式,菜單的生成就在TextActionModeCallback類中
在TextActionModeCallback的onCreateActionMode方法中

Editor.java ->TextActionModeCallback

 @Override
 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
 mode.setTitle(null);
 mode.setSubtitle(null);
 mode.setTitleOptionalHint(true);
 //生成菜單
 populateMenuWithItems(menu);

 Callback customCallback = getCustomCallback();
 if (customCallback != null) {
 if (!customCallback.onCreateActionMode(mode, menu)) {
  // The custom mode can choose to cancel the action mode, dismiss selection.
  Selection.setSelection((Spannable) mTextView.getText(),
  mTextView.getSelectionEnd());
  return false;
 }
 }
 ···
 }

生成的菜單的方法populateMenuWithItems(menu)中,生成完菜單會執行自定義的回調getCustomCallback() , 看下該回調如何賦值。

在TextView中

TextView.java
 public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
 createEditorIfNeeded();
 mEditor.mCustomSelectionActionModeCallback = actionModeCallback;
 }

因此我們可以在自定義回調的onCreateActionMode方法中,刪除不需要的菜單項。

以上是“Androidz2如何實現EditText長按菜單中分享功能的隱藏方法”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

哈尔滨市| 淮安市| 洞口县| 博白县| 大竹县| 朔州市| 望都县| 平昌县| 南投县| 鹰潭市| 揭东县| 万源市| 托里县| 平泉县| 文水县| 博爱县| 治县。| 永兴县| 保康县| 洛阳市| 平邑县| 光山县| 莱芜市| 敖汉旗| 铜梁县| 咸丰县| 河东区| 宾川县| 鹤山市| 甘南县| 合阳县| 诸城市| 绍兴市| 平凉市| 桐乡市| 曲水县| 苍南县| 峨眉山市| 陆丰市| 松桃| 清徐县|