web-dev-qa-db-fra.com

Comment remplacer le menu de sélection de texte de l'affichage Web dans android

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.

enter image description here

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

enter image description here

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.

19
Abhishek

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

https://github.com/btate/BTAndroidWebViewSelection

Lien de référence 2 pour créer un marqueur d'affichage Web

https://github.com/liufsd/WebViewMarker

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

Selection One

Selection Two

Selection Three

2
Abhishek

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>
7
Damodhar Meshram

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.

3
LinWei

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.

1
White Druid