亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁(yè) > 系統(tǒng) > Android > 正文

Android EditText長(zhǎng)按菜單中分享功能的隱藏方法

2019-10-21 21:19:27
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

常見(jiàn)的EditText長(zhǎng)按菜單如下

Android,EditText,長(zhǎng)按菜單,分享功能,隱藏

oppo

Android,EditText,長(zhǎng)按菜單,分享功能,隱藏

小米

需求是隱藏掉其中的分享/搜索功能,禁止將內(nèi)容分享到其他應(yīng)用。

最終解決方案

這里先說(shuō)下最終解決方案

像華為/oppo等手機(jī),該菜單實(shí)際是谷歌系統(tǒng)的即沒(méi)有改過(guò)源代碼,像小米的菜單則是自定義,該部分的源代碼改動(dòng)過(guò)。
兩方面修改:

1.谷歌系統(tǒng)自帶的 通過(guò) EditText.setCustomSelectionActionModeCallback()方法設(shè)置自定義的選中后動(dòng)作模式接口,只保留需要的菜單項(xiàng)

代碼如下

 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 //只保留需要的菜單項(xiàng)  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.小米等手機(jī)自定義菜單無(wú)法進(jìn)行隱藏,可以是分享、搜索等功能失效,即在BaseActivity的startActivityForResult中進(jìn)行跳轉(zhuǎn)攔截,如果是調(diào)用系統(tǒng)的分享/搜索功能,則不允許跳轉(zhuǎn)

 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//跳轉(zhuǎn)到瀏覽器 && action != Intent.ACTION_SEARCH//搜索 } ?: false }

如果以上不滿足要求,只能通過(guò)自定義長(zhǎng)按菜單來(lái)實(shí)現(xiàn)自定義的菜單欄。

解決思路(RTFSC)

分析源碼菜單的創(chuàng)建和點(diǎn)擊事件

既然是長(zhǎng)按松手后彈出的,應(yīng)該在onTouchEvent中的ACTION_UP事件或者在performLongClick中,從兩方面著手
先看perfomLongEvent EditText沒(méi)有實(shí)現(xiàn) 去它的父類TextView中查找

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

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

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

從上面代碼分析

1.長(zhǎng)按時(shí)會(huì)先選中內(nèi)容 Selection.setSelection((Spannable) mTextView.getText(), offset)

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

3.開(kāi)始拖動(dòng)/選中單詞后拖動(dòng) startDragAndDrop()/ selectCurrentWordAndStartDrag()

看著很像了

看下第二步中展示的內(nèi)容

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; }

實(shí)際是InsertionHandleView 執(zhí)行了show方法。  查看其父類HandlerView的構(gòu)造方法

 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實(shí)際上是PopWindow的View。 即選中的圖標(biāo)實(shí)際上是popwidow
看源碼可看出HandleView有兩個(gè)實(shí)現(xiàn)類 InsertionHandleView  和SelectionHandleView 由名字可看出一個(gè)是插入的,一個(gè)選擇的 看下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); ··· } ··· } }

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

getPositionListener()返回的實(shí)際上是ViewTreeObserver.OnPreDrawListener的實(shí)現(xiàn)類PositionListener
重繪會(huì)調(diào)用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; }

調(diào)用了positionListener.updatePosition方法, positionListener這個(gè)實(shí)現(xiàn)類對(duì)應(yīng)的是HandlerView

重點(diǎn)在HandleView的updatePosition方法,該方法進(jìn)行popWindow的顯示和更新位置

看一下該方法的實(shí)現(xiàn)

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]); } }  ··· } }

到此我們知道選中的圖標(biāo)即下面紅框內(nèi)的實(shí)際上popWindow展示

Android,EditText,長(zhǎng)按菜單,分享功能,隱藏

點(diǎn)擊選中的圖標(biāo)可以展示菜單,看下HandleView的onTouchEvent方法

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

updateFloatingToolbarVisibility(ev)真相在這里,該方法進(jìn)行懸浮菜單欄的展示
經(jīng)過(guò)進(jìn)一步查找,可以看到會(huì)調(diào)用下面SelectionActionModeHelper的這個(gè)方法

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

會(huì)啟動(dòng)一個(gè)叫TextClassificationAsyncTask的異步任務(wù),該異步任務(wù)最后會(huì)執(zhí)行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. 根據(jù)給的類型,開(kāi)啟一個(gè)動(dòng)作模式,該模式是一個(gè)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)中,生成完菜單會(huì)執(zhí)行自定義的回調(diào)getCustomCallback() , 看下該回調(diào)如何賦值。

在TextView中

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

因此我們可以在自定義回調(diào)的onCreateActionMode方法中,刪除不需要的菜單項(xiàng)。

但該方法對(duì)小米手機(jī)無(wú)效,小米手機(jī)的菜單展示,不是通過(guò)startActionMode來(lái)展示的。不過(guò)可以對(duì)菜單中的分享等功能進(jìn)行禁止跳轉(zhuǎn),解決方法看最上面

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)VEVB武林網(wǎng)的支持。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到Android開(kāi)發(fā)頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
亚洲精品不卡在线| 欧美日韩国产精品专区| 精品日韩在线一区| 欧美成人一二三| 亚洲欧美一区二区三区久本道91| 亚洲aⅴ乱码精品成人区| 不卡中文字幕av| 一道本在线观看| 国语对白在线播放| 欧洲成人一区| 欧美精品激情| 亚洲欧美另类小说视频| 久久精品久久综合| 亚洲人成亚洲人成在线观看图片| 91精品国产综合久久精品app| 少妇高潮惨叫久久久久| 欧美日韩成人激情| 777久久久精品一区二区三区| 国产一级片中文字幕| 91久久久久久| 成黄免费在线| 国产麻豆一级片| 九九99久久精品在免费线bt| 欧美性受极品xxxx喷水| 91精品小视频| 91精品中文字幕一区二区三区| 久久精品在线观看视频| 亚洲男人天堂2017| 成人午夜视频免费观看| 欧美一区久久| 国产成人自拍偷拍| 国产视频一区二区三区在线播放| 在线观看一区二区三区三州| 国产精品丝袜白浆摸在线| 91久久夜色精品国产网站| 亚洲精品久久嫩草网站秘色| 亚洲bbw性色大片| 久久久精品免费观看| 亚洲jizzjizz日本少妇| 91精品久久久久久久久青青| 精品中文字幕人| 丁香花高清在线观看完整版| 一级黄色大毛片| 成人小视频在线观看免费| 日韩在线中文字| 美女久久久久久久久久久| 杨幂一区二区三区免费看视频| h网站视频在线观看| 国产一区二区三区探花| 一区二区三区四区在线不卡高清| 视频一区二区在线| 高清亚洲成在人网站天堂| 精品欧美日韩精品| 日本公妇乱淫免费视频一区三区| 污片免费在线观看| 精品久久久久久久久久久久包黑料| 日韩中文字幕在线视频观看| 999精品国产| 秋霞蜜臀av久久电影网免费| 91麻豆制片厂| 国产成人一级电影| 日韩中文字幕亚洲| 亚洲精品99久久久久中文字幕| 涩视频在线观看| 欧美xo影院| 精品成人在线视频| 国色天香2019中文字幕在线观看| 欧美日韩不卡中文字幕在线| 久久av超碰| 中文字幕欧美亚洲| 曰韩不卡视频| 亚洲无线码在线一区观看| 日韩av片子| 日韩你懂的在线播放| 国产精品suv一区二区88| 色综合天天在线| 日韩三级电影网站| 久久久精品久久| 国产成人三级视频| 色综合视频一区二区三区44| 欧美女同网站| 国产成人无码aa精品一区| av在线观看地址| 久久艹国产精品| 精品视频91| 奇米一区二区| 欧美视频免费看| 国产精品流白浆视频| 国产在线不卡一卡二卡三卡四卡| 日韩一区二区福利| 亚洲精品国产精品国产自| 无码精品黑人一区二区三区| 无码人妻久久一区二区三区蜜桃| 久久成年人免费电影| 亚洲激情av| 99在线国产| 色狠狠久久av综合| 国产九九九九| 国产欧美一区二区精品仙草咪| 国产无遮挡又黄又爽在线观看| 久草中文在线| 成人动漫视频在线观看| 国产日韩高清一区二区三区在线| 久久新电视剧免费观看| www.亚洲免费| 精品视频免费在线| 97精品视频| 成人午夜电影免费在线观看| 国产一级一区二区| 日韩在线观看免费全集电视剧网站| 欧美精品乱码久久久久久| www操com| 亚洲视频精品一区| 亚洲一区在线| av高清日电影| 中日韩免费视频中文字幕| 欧美最猛性xxxx免费| 欧美日韩高清在线| 国产又爽又黄无码无遮挡在线观看| 91国在线精品国内播放| 欧美中文在线免费| 国产精品久久久久久久蜜臀| 亚洲麻豆国产自偷在线| 午夜一区在线| 婷婷综合国产| 播放灌醉水嫩大学生国内精品| 国产交换配乱淫视频免费| 国产美女三级无套内谢| 天天碰日日操| 国产精品久久久久9999爆乳| 爽爽爽爽爽爽爽成人免费观看| 久热精品在线播放| 国产精品普通话对白| 国产97在线|亚洲| 欧美精品免费在线| 人成在线免费视频| 一级片免费在线观看视频| 亚洲免费综合| 樱花草www在线| 玖玖精品在线视频| 在线国产精品视频| 俄罗斯精品一区二区三区| 日韩精品极品视频| 97视频免费观看| 韩国av永久免费| 亚洲国产欧美一区二区三区不卡| 人妻无码视频一区二区三区| 国产毛片一区二区三区va在线| 国产精品bbw一区二区三区| 狠狠操夜夜操| 久久精品一级爱片| 日本道不卡免费一区| 激情丁香久久| 50一60岁老妇女毛片| 五月天国产精品| a级片在线免费看| 久久婷婷中文字幕| 国产成人综合亚洲| 亚洲第一福利视频| 川上优av中文字幕一区二区| 人人玩人人添人人澡免费| 亚洲免费观看高清完整版在线观看| 欧美伊人影院| 黄色录像一级片| 视频一区在线| 日韩一卡二卡在线| 国产日韩欧美视频在线| 网友自拍亚洲| 中文字字幕码一二三区| 好看的中文字幕在线播放| 欧美日韩国产色站一区二区三区| 午夜视频免费在线| 原创真实夫妻啪啪av| 国产一卡二卡在线| 亚洲成人av资源网| 久久亚洲精品中文字幕| 国产精品综合| 欧美日韩成人在线视频| 九九热精彩视频| 国产欧美精品在线播放| 欧美极品视频一区二区三区| 欧美少妇另类| 亚洲精品一区二区三区不卡| 成人日韩av| 亚洲影视一区| 日本成人看片网址| 久久综合中文色婷婷| 国产伦精品一区二区三区精品视频| 免费看的国产视频网站| 亚洲国产欧美另类| 4444亚洲人成无码网在线观看| 免费亚洲视频| 影音先锋国产| 亚洲欧美国产精品va在线观看| 男插女视频久久久| 一级视频在线免费观看| 成人18视频在线播放| 男女无套免费视频网站动漫| 五月天激情婷婷| 国产成人精品久久二区二区| 中文字幕一区二区三区四区| 亚洲一区电影| 精品成人无码一区二区三区| 国产精品久久久久久久久果冻传媒| 久久视频www| 国产一级在线观看| 中文字幕一区二区精品| 黑人另类av| 手机在线成人av| 91精品91久久久久久| 成年人网站在线观看视频| 色噜噜偷拍精品综合在线| 成人毛片一区二区| 精品亚洲porn| 国产欧美三级电影| 日本高清不卡aⅴ免费网站| 香蕉综合视频| 欧美日本韩国一区二区| 久久蜜臀中文字幕| 免费视频最近日韩| av首页在线观看| 大桥未久av一区二区三区中文| 亚洲美女爱爱视频| 欧美一二三区| 亚洲欧美日韩国产| 国产丝袜视频在线播放| 日韩视频在线观看视频| 夜夜躁很很躁日日躁麻豆| 91精品国产自产在线观看永久∴| 国产 欧美 日本| 日韩高清一区在线| 久久gogo国模啪啪裸体| 国产suv精品一区二区69| 一区二区三区在线不卡| 国产成人精品视频ⅴa片软件竹菊| 国产v在线观看| 日本不卡影院| 久热综合在线亚洲精品| 欧美日韩一区二区免费在线观看| 一区二区在线高清视频| 中文av一区| 久久亚洲私人国产精品va| 国产极品视频在线观看| 一本色道久久亚洲综合精品蜜桃| 日韩欧美天堂| www.在线观看av| 一本在线高清不卡dvd| 4438国产精品一区二区| 91成人抖音| 伪装者在线观看完整版免费| 成人动漫视频在线观看| 日韩精品一区国产| 亚洲资源在线观看| 日韩欧美三级在线观看| av在线天堂网| 国产一区亚洲二区三区| 男女激情无遮挡| 欧美日韩中国免费专区在线看| 91免费精品国偷自产在线| 精品日韩欧美一区二区| 天堂网www在线资源中文| 亚洲国产欧美在线成人app| 成人一级片在线观看| 欧美日韩美女| 1区2区3区在线| 91大神福利视频在线| 蜜臀久久99精品久久一区二区| 欧美主播一区二区三区美女 久久精品人| 国产女主播在线写真| 高清不卡亚洲| 国产精品伦一区二区三级视频| 久久久久五月天| 亚洲天堂男人天堂女人天堂| 欧美影院一区二区| 色婷婷精品久久二区二区蜜臂av| 国产成人精品视频| 日韩免费在线看| 亚洲精品久久久久久一区二区| 男女啪啪免费观看| 日本一区二区三区视频在线| 欧美视频一区在线观看| 992kp免费看片| 毛片一区二区三区| 亚洲成人精选| 国产91亚洲精品久久久| 欧美激情一级片一区二区| 亚洲午夜激情| 青青在线视频观看| 日韩av无码一区二区三区不卡| 国产精欧美一区二区三区| 亚洲一线二线三线久久久| 亚洲国产日韩在线人成电影| 大地资源高清在线视频观看| 特级毛片在线观看| 亚洲国产日韩在线| 国产精品久久一区| 亚洲va电影大全| 在线国产福利| 久久久夜色精品亚洲| 欧美影院精品一区| 中文字幕第88页| xx欧美xxx| 国产成人在线一区| 精品国产乱码久久久久久1区2区| 久久视频精品在线| 污污网站免费观看| 11024精品一区二区三区日韩| 国产www视频| 一个人看的免费视频色| 成人羞羞视频免费看看| 久久精品第一页| 亚洲免费不卡视频| 国内精品免费一区二区三区| 亚洲欧洲日产国产综合网| 欧美一区二区三区四| 成人精品网站在线观看| 中文字幕日韩三级| 37pao成人国产永久免费视频| 国产免费高清av| av成人影院在线| 人人爱人人干婷婷丁香亚洲| 亚洲国产成人av在线| 真实国产乱子伦精品一区二区三区| 黄网站在线观看永久免费| 日韩视频免费观看高清完整版在线观看| 日韩字幕在线观看| 国产中文字幕免费观看| 欧美高清不卡|