日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android隐藏EditText长按菜单中分享功能探索

發布時間:2024/4/13 Android 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android隐藏EditText长按菜单中分享功能探索 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

常見的EditText長按菜單如下

oppo
小米

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

最終解決方案

這里先說下最終解決方案
像華為/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)) returnsuper.startActivityForResult(intent, requestCode)}@SuppressLint("RestrictedApi")@RequiresApi(Build.VERSION_CODES.JELLY_BEAN)override fun startActivityForResult(intent: Intent?,requestCode: Int,options: Bundle?) {if (!canStart(intent)) returnsuper.startActivityForResult(intent, requestCode, options)}private fun canStart(intent: Intent?): Boolean {return intent?.let {val action = it.actionaction != Intent.ACTION_CHOOSER//分享&& action != Intent.ACTION_VIEW//跳轉到瀏覽器&& action != Intent.ACTION_SEARCH//搜索} ?: false} 復制代碼

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

解決思路(RTFSC)

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

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

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

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

Editor.javapublic 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 -> InsertionPointCursorControllerpublic 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 ->HandleViewpublic void show() {if (isShowing()) return;getPositionListener().addSubscriber(this, true );// Make sure the offset is always considered new, even when focusing at same positionmPreviousOffset = -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 @Overridepublic 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@Overridepublic 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展示

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

Editor.java ->HandleView@Overridepublic boolean onTouchEvent(MotionEvent ev) {updateFloatingToolbarVisibility(ev);···} 復制代碼

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

SelectionActionModeHelper.javapublic 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.javavoid 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@Overridepublic 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.javapublic void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {createEditorIfNeeded();mEditor.mCustomSelectionActionModeCallback = actionModeCallback;} 復制代碼

因此我們可以在自定義回調的onCreateActionMode方法中,刪除不需要的菜單項。
但該方法對小米手機無效,小米手機的菜單展示,不是通過startActionMode來展示的。不過可以對菜單中的分享等功能進行禁止跳轉,解決方法看最上面

總結

以上是生活随笔為你收集整理的Android隐藏EditText长按菜单中分享功能探索的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。