Le menu de sélection de texte Web de base d'Android est comme indiqué dans l'image ci-dessous. Il a des options comme copier, partager, sélectionner tout, recherche sur le Web.
Je veux surfer sur ces menus et les vouloir comme ma propre liste de menus comme "marquer la couleur", "marquer comme imp" etc. Je regarde autour de la plupart des questions disponibles sur le menu contextuel sur le débordement de pile. La plupart de la question concerne le menu contextuel mais ne donne pas le résultat escompté. Je veux un menu comme l'image ci-dessous
Lorsque j'effectue la sélection Android montre une vue du formulaire de création de vue comme
D/ViewRootImpl: #1 mView = Android.widget.PopupWindow$PopupDecorView{648898f V.E...... ......I. 0,0-0,0}
D/ViewRootImpl: #1 mView = Android.widget.PopupWindow$PopupDecorView{a66541c V.E...... ......I. 0,0-0,0}
D/ViewRootImpl: MSG_RESIZED_REPORT: ci=Rect(0, 0 - 0, 0) vi=Rect(0, 0 - 0, 0) or=1
D/ViewRootImpl: MSG_RESIZED_REPORT: ci=Rect(0, 0 - 0, 0) vi=Rect(0, 0 - 0, 0) or=1
Comment réaliser une telle mise en œuvre?
Je suis également passé par https://github.com/naoak/WebViewMarker mais je n'obtiens pas de résultat correct.
Qu'est-ce que j'ai encore fait?
J'étends WebView de Android et je veux prendre en charge le SDK minimum 19. Lorsque j'effectue une pression longue, j'ai un événement de pression longue mais je ne peux pas obtenir de tels appels api de création de menus.
Cette solution ne dépend pas du mode d'action de l'activité et fonctionne pour tous Android
J'ai essayé de donner une réponse mais elle dépasse les limites de caractères, donc je mets une partie du code
Lien de référence 1 pour la sélection sur la vue Web
Lien de référence 2 pour créer un marqueur d'affichage Web
Les deux liens ci-dessus jouent vraiment un rôle important et développés par des développeurs impressionnants. Tout d'abord, nous avons besoin de recherches sur la classe TextSelectionSupport à partir du lien de référence 1. J'ai personnalisé deux lignes de code dans la classe TextSelectionSupport pour obtenir le rectangle de sélection dans Listener Listener ici.
Clonez l'exemple de projet à partir d'ici https://github.com/ab-cse-2014/WebViewSelection.git
Voir L'implémentation de CustomWebView et l'utilisation de la classe TextSelectionSupport.
Ceci est ma classe d'affichage Web dans le projet
import Android.content.Context;
import Android.graphics.Rect;
import Android.os.Build;
import Android.support.annotation.RequiresApi;
import Android.support.v7.app.AppCompatActivity;
import Android.util.AttributeSet;
import Android.util.Log;
import Android.view.Gravity;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.webkit.WebView;
import Android.widget.PopupWindow;
import Android.widget.Toast;
import com.cse.webviewtextselection.R;
import com.cse.webviewtextselection.webviewmaker.TextSelectionSupport;
public class CustomWebView extends WebView {
private final String TAG = this.getClass().getSimpleName();
private Context mContext;
private TextSelectionSupport mTextSelectionSupport;
private PopupWindow mPopupWindow;
private int currentTop;
public CustomWebView(Context context) {
super(context);
mContext = context;
initSetUp();
preparePopupWindow();
}
public CustomWebView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
initSetUp();
preparePopupWindow();
}
public CustomWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
initSetUp();
preparePopupWindow();
}
@RequiresApi(api = Build.VERSION_CODES.Lollipop)
public CustomWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mContext = context;
initSetUp();
preparePopupWindow();
}
private void initSetUp() {
mTextSelectionSupport = TextSelectionSupport.support((AppCompatActivity) mContext, this);
mTextSelectionSupport.setSelectionListener(new TextSelectionSupport.SelectionListener() {
@Override
public void startSelection() {
}
@Override
public void selectionChanged(String text, Rect rect) {
Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();
showPopAtLocation(mPopupWindow, rect.left, rect.top);
}
@Override
public void endSelection() {
if (mPopupWindow != null) {
mPopupWindow.dismiss();
}
}
});
}
private void preparePopupWindow() {
LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View customPopupView = layoutInflater.inflate(R.layout.custom_popup_layout, null);
mPopupWindow = new PopupWindow(customPopupView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, true);
mPopupWindow.setAnimationStyle(Android.R.style.Animation_Dialog);
}
private void showPopAtLocation(PopupWindow mPopupWindow, int x, int y) {
if (mPopupWindow != null) {
if (currentTop != 0 || currentTop > ((AppCompatActivity)mContext).getWindow().getDecorView().getHeight()) {
if (y > currentTop) {
y -= currentTop;
}
}
Log.d("Current Top : ", String.valueOf(currentTop));
Log.d("Y : ", String.valueOf(y));
//mPopupWindow.showAtLocation(((AppCompatActivity)mContext).findViewById(R.id.parentRelativeLayout), Gravity.NO_GRAVITY, x, y);
mPopupWindow.showAtLocation(((AppCompatActivity)mContext).getWindow().getDecorView(), Gravity.NO_GRAVITY, x, y);
}
}
@Override
protected void onScrollChanged(int newLeft, int newTop, int oldLeft, int oldTop) {
currentTop = newTop;
super.onScrollChanged(newLeft, newTop, oldLeft, oldTop);
}
}
Menu contextuel personnalisé XML comme la sélection de texte intelligente androïdes (custom_popup_layout.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/myCustomMenuLinearLayout"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:orientation="horizontal"
Android:background="@Android:color/transparent">
<LinearLayout
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:orientation="horizontal"
Android:background="@Android:color/white"
Android:elevation="5dp"
Android:layout_margin="12dp">
<TextView
Android:id="@+id/menuOne"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:text="Mark With Color"
Android:textColor="@Android:color/black"
Android:padding="10dp"
Android:maxLines="1"/>
<TextView
Android:id="@+id/menuTwo"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:text="Mark As Important"
Android:textColor="@Android:color/black"
Android:padding="10dp"
Android:maxLines="1"/>
<TextView
Android:id="@+id/menuThree"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:text="Show More"
Android:textColor="@Android:color/black"
Android:padding="10dp"
Android:maxLines="1"/>
</LinearLayout>
</LinearLayout>
Captures d'écran de sortie
Vous devez remplacer les menus d'action de l'activité
plus d'informations que vous pouvez lire: https://developer.Android.com/guide/topics/ui/menus.html
COMMENT ÉCRASER:
@Override
public void onActionModeStarted(Android.view.ActionMode mode) {
mode.getMenu().clear();
Menu menus = mode.getMenu();
mode.getMenuInflater().inflate(R.menu.highlight,menus);
super.onActionModeStarted(mode);
}
surligner
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:Android="http://schemas.Android.com/apk/res/Android">
<item Android:id="@+id/impclick"
Android:title="Mark As Important"
/>
<item Android:id="@+id/colorclick"
Android:title="Mark with color" />
</menu>
ce dont vous avez besoin est mode action, en activité:
@Override
public void onActionModeStarted(ActionMode mode) {
Menu menu = mode.getMenu();
// you can remove original menu: copy, cut, select all, share ... or not
menu.clear();
// here i will get text selection by user
menu.add(R.string.action_menu_preview_card)
.setEnabled(true)
.setVisible(true)
.setOnMenuItemClickListener(item -> {
if (mWebview != null) {
mWebview.evaluateJavascript("window.getSelection().toString()", value -> {
value = StringUtil.trimToNull(value);
if (value != null) {
// do something about user select
}
});
}
mode.finish();
return true;
});
super.onActionModeStarted(mode);
}
je l'ai testé ci-dessus Android 21, cela peut gérer le clic du menu du mode action, et mode.getMenuInflater (). inflate (...) ne peut pas le faire.
je pense que ici peut vous aider.
Par souci d'exhaustivité, voici comment j'ai résolu le problème:
J'ai suivi la suggestion en fonction de cette réponse, avec un peu plus de réglages pour mieux correspondre au code remplacé:
classe publique MyWebView étend WebView {
private ActionMode mActionMode;
private mActionMode.Callback mActionModeCallback;
@Override
public ActionMode startActionMode(Callback callback) {
ViewParent parent = getParent();
if (parent == null) {
return null;
}
mActionModeCallback = new CustomActionModeCallback();
return parent.startActionModeForChild(this, mActionModeCallback);
}
}
Essentiellement, cela force votre CAB personnalisé à apparaître au lieu du Android CAB. Maintenant, vous devez modifier votre rappel pour que la surbrillance du texte disparaisse avec le CAB:
la classe publique MyWebView étend WebView {... la classe privée CustomActionModeCallback implémente ActionMode.Callback {... // Jusqu'à présent, tout est le même que dans la question
// Called when the user exits the action mode
@Override
public void onDestroyActionMode(ActionMode mode) {
clearFocus(); // This is the new code to remove the text highlight
mActionMode = null;
}
}
}
C'est tout ce qu'on peut en dire. N'oubliez pas que tant que vous utilisez MyWebView avec le startActionMode substitué, il n'y a AUCUNE FAÇON d'obtenir le CAB natif (le menu copier/coller, dans le cas d'une WebView). Il peut être possible d'implémenter ce type de comportement, mais ce n'est pas ainsi que ce code fonctionne. MISE À JOUR: Il existe un moyen beaucoup plus simple de le faire! La solution ci-dessus fonctionne bien, mais voici une alternative plus simple.
Cette solution offre moins de contrôle sur l'ActionMode, mais elle nécessite beaucoup moins de code que la solution ci-dessus.
public class MyActivity étend l'activité {
private ActionMode mActionMode = null;
@Override
public void onActionModeStarted(ActionMode mode) {
if (mActionMode == null) {
mActionMode = mode;
Menu menu = mode.getMenu();
// Remove the default menu items (select all, copy, paste, search)
menu.clear();
// If you want to keep any of the defaults,
// remove the items you don't want individually:
// menu.removeItem(Android.R.id.[id_of_item_to_remove])
// Inflate your own menu items
mode.getMenuInflater().inflate(R.menu.my_custom_menu, menu);
}
super.onActionModeStarted(mode);
}
// This method is what you should set as your item's onClick
// <item Android:onClick="onContextualMenuItemClicked" />
public void onContextualMenuItemClicked(MenuItem item) {
switch (item.getItemId()) {
case R.id.example_item_1:
// do some stuff
break;
case R.id.example_item_2:
// do some different stuff
break;
default:
// ...
break;
}
// This will likely always be true, but check it anyway, just in case
if (mActionMode != null) {
mActionMode.finish();
}
}
@Override
public void onActionModeFinished(ActionMode mode) {
mActionMode = null;
super.onActionModeFinished(mode);
}
}
Voici un exemple de menu pour vous aider à démarrer:
<item
Android:id="@+id/example_item_1"
Android:icon="@drawable/ic_menu_example_1"
Android:showAsAction="always"
Android:onClick="onContextualMenuItemClicked"
Android:title="@string/example_1">
</item>
<item
Android:id="@+id/example_item_2"
Android:icon="@drawable/ic_menu_example_2"
Android:showAsAction="ifRoom"
Android:onClick="onContextualMenuItemClicked"
Android:title="@string/example_2">
</item>
C'est tout! Vous avez terminé! Maintenant, votre menu personnalisé apparaîtra, vous n'avez pas à vous soucier de la sélection, et vous avez à peine à vous soucier du cycle de vie d'ActionMode.
Cela fonctionne presque parfaitement avec une WebView qui occupe la totalité de son activité parent. Je ne sais pas dans quelle mesure cela fonctionnera s'il y a plusieurs vues dans votre activité à la fois. Cela nécessitera probablement quelques ajustements dans ce cas.