如何重写的机器人的WebView OS 4.1+默认的文本选择?重写、机器人、文本、WebView

2023-09-03 20:34:25 作者:说等却又走

在发布这个问题我搜索了很多,但找不到任何关于此问题明确的答案。

Before posting this question I've searched a lot but could not find any clear answers on this issue.

我要重写的Andr​​oid的WebView与放大器的默认文本选择;显示我的自定义文本选择对话框中的选项。我已经试过此示例code 项目。

I have to override default text selection of android webview & show my custom text selection dialog options. I have tried this sample code project.

此示例项目适用于下列设备及放大器;仿真器:

在宏碁Iconia A500平板电脑:10寸:Android操作系统 - 3.0 在宏碁Iconia A500平板电脑:10寸:Android操作系统 - 3.2 三星Galaxy Tab:10寸:Android操作系统 - 4.0 三星Galaxy Tab 7英寸:Android操作系统 - 4.0 模拟器:皮肤-WVGA800:Android操作系统 - 4.1.2

不工作的下列设备:

三星Galaxy Tab:10寸:Android操作系统 - 4.1.2 三星Galaxy Tab 7英寸:Android操作系统 - 4.1.2

在Android操作系统版本4.1和放大器;而不是显示我的自定义文本选择选项对话框4.1+,它显示为文本选择Android系统的默认操作吧。

On android os version 4.1 & 4.1+ instead of showing my custom text selection option dialog, it shows android system's default action bar for text selection.

我已经搜索了很多关于这一点,许多建议使用 onLongClick()的方法interface

I have searched a lot on this, many suggested to use onLongClick() method of the interface

我已经问在这个论坛的问题,请参见本link,有回答这个问题,我能够克隆onLongClick()事件,但我不能停止默认的文本选择操作栏。

I have already asked a question on this forum please see this link, with answers to this questions I am able to clone onLongClick() event but I can't stop default text selection action bar.

对于这种情况我有几个问题。

For this scenario I have few questions.

1.为什么onLongClick()方法停止工作的设备上的Andr​​oid操作系统版本上运行4.1+?

1.Why onLongClick() method stops working for device running on android os version 4.1+ ?

2.How停在长pressing默认的文本选择操作栏上的web视图的文字​​?

2.How to stop default text selection action bar on long pressing on the text from webview ?

这是我的自定义web视图类。

This is my custom webview class.

  package com.epubreader.ebook;
  import org.json.JSONException;
  import org.json.JSONObject;
  import android.app.Activity;
  import android.content.Context;
  import android.graphics.Rect;
  import android.graphics.Region;
  import android.os.Handler;
  import android.os.Message;
  import android.util.AttributeSet;
  import android.util.DisplayMetrics;
  import android.util.Log;
  import android.view.ContextMenu;
  import android.view.Display;
  import android.view.GestureDetector;
  import android.view.LayoutInflater;
  import android.view.MotionEvent;
  import android.view.View;
  import android.view.View.OnLongClickListener;
  import android.view.View.OnTouchListener;
  import android.view.ViewGroup;
  import android.view.WindowManager;
  import android.webkit.WebView;
  import android.widget.ImageView;
  import android.widget.LinearLayout;
  import android.widget.Toast;

  import com.epubreader.R;
  import com.epubreader.drag.DragController;
  import com.epubreader.drag.DragLayer;
  import com.epubreader.drag.DragListener;
  import com.epubreader.drag.DragSource;
  import com.epubreader.drag.MyAbsoluteLayout;
  import com.epubreader.menu.menuAnimationHelper;
  import com.epubreader.textselection.WebTextSelectionJSInterface;
  import com.epubreader.textselectionoverlay.ActionItem;
  import com.epubreader.textselectionoverlay.QuickAction;
  import com.epubreader.textselectionoverlay.QuickAction.OnDismissListener;



public class CustomWebView extends WebView implements WebTextSelectionJSInterface,
OnTouchListener , OnLongClickListener, OnDismissListener, DragListener{

/** The logging tag. */
private static final String TAG = "CustomWebView";

/** Context. */
protected   Context ctx;

/** The context menu. */
private QuickAction mContextMenu;

/** The drag layer for selection. */
private DragLayer mSelectionDragLayer;

/** The drag controller for selection. */
private DragController mDragController;

/** The start selection handle. */
private ImageView mStartSelectionHandle;

/** the end selection handle. */
private ImageView mEndSelectionHandle;

/** The selection bounds. */
private Rect mSelectionBounds = null;

/** The previously selected region. */
protected Region lastSelectedRegion = null;

/** The selected range. */
protected String selectedRange = "";

/** The selected text. */
protected String selectedText = "";

/** Javascript interface for catching text selection. */


/** Selection mode flag. */
protected boolean inSelectionMode = false;

/** Flag to stop from showing context menu twice. */
protected boolean contextMenuVisible = false;

/** The current content width. */
protected int contentWidth = 0;


/** Identifier for the selection start handle. */
private final int SELECTION_START_HANDLE = 0;

/** Identifier for the selection end handle. */
private final int SELECTION_END_HANDLE = 1;

/** Last touched selection handle. */
private int mLastTouchedSelectionHandle = -1;

/** Variables for Left & Right Menu ***/
private View menuView;
private LinearLayout toiLay;
private menuAnimationHelper _menuAnimationHelper;
private TocTranslateAnimation _tocTranslateAnimation;

private CustomWebView _customWebView;



public CustomWebView(Context context) {
    super(context);

    this.ctx = context;
    this.setup(context);
}

public CustomWebView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    this.ctx = context;
    this.setup(context);

}

public CustomWebView(Context context, AttributeSet attrs) {
    super(context, attrs);

    this.ctx = context;
    this.setup(context);

}


//*****************************************************
//*
//*     Touch Listeners
//*
//*****************************************************

private boolean mScrolling = false;
private float mScrollDiffY = 0;
private float mLastTouchY = 0;
private float mScrollDiffX = 0;
private float mLastTouchX = 0;

@Override
public boolean onTouch(View v, MotionEvent event) {


    float xPoint = getDensityIndependentValue(event.getX(), ctx) / getDensityIndependentValue(this.getScale(), ctx);
    float yPoint = getDensityIndependentValue(event.getY(), ctx) / getDensityIndependentValue(this.getScale(), ctx);

    // TODO: Need to update this to use this.getScale() as a factor.

    //Log.d(TAG, "onTouch " + xPoint + " , " + yPoint);

    closeMenu();
   if(event.getAction() == MotionEvent.ACTION_DOWN){

        final String startTouchUrl = String.format("javascript:android.selection.startTouch(%f, %f);", 
                xPoint, yPoint);

        mLastTouchX = xPoint;
        mLastTouchY = yPoint;

        ((Activity)this.ctx).runOnUiThread(new Runnable() {

            @Override
            public void run() {
                loadUrl(startTouchUrl);
            }
        });

         // This two line clones the onLongClick()
         longClickHandler.removeCallbacks(longClickRunnable);
         longClickHandler.postDelayed(longClickRunnable,300);


    }
    else if(event.getAction() == MotionEvent.ACTION_UP){
        // Check for scrolling flag
        if(!mScrolling){
            this.endSelectionMode();
        }

         // This line clones the onLongClick()
        longClickHandler.removeCallbacks(longClickRunnable);

        mScrollDiffX = 0;
        mScrollDiffY = 0;
        mScrolling = false;



    }else if(event.getAction() == MotionEvent.ACTION_MOVE){

        mScrollDiffX += (xPoint - mLastTouchX);
        mScrollDiffY += (yPoint - mLastTouchY);

        mLastTouchX = xPoint;
        mLastTouchY = yPoint;


        // Only account for legitimate movement.
        if(Math.abs(mScrollDiffX) > 10 || Math.abs(mScrollDiffY) > 10){
            mScrolling = true;

        }
         // This line clones the onLongClick()
        longClickHandler.removeCallbacks(longClickRunnable);

    }

    // If this is in selection mode, then nothing else should handle this touch
    return false;
}

/**
 * Pass References of Left & Right Menu
 */

public void initMenu(LinearLayout _toiLay,View _menuView,menuAnimationHelper menuAnimationHelper,
        TocTranslateAnimation tocTranslateAnimation){
    toiLay = _toiLay;
    menuView = _menuView;
    _menuAnimationHelper = menuAnimationHelper;
    _tocTranslateAnimation = tocTranslateAnimation;
}

private void closeMenu(){

    if(_menuAnimationHelper != null && _menuAnimationHelper.isMenuOpenBool){
        _menuAnimationHelper.close(menuView);
        _menuAnimationHelper.isMenuOpenBool = false;
    }

    if(_tocTranslateAnimation != null && _tocTranslateAnimation.isTocListOpenBool){
        _tocTranslateAnimation.close(toiLay);
        _tocTranslateAnimation.isTocListOpenBool = false;
    }
}

      public void removeOverlay(){
    Log.d("JsHandler", "in java removeOverlay" + mScrolling);


    this.endSelectionMode();
    mScrollDiffX = 0;
    mScrollDiffY = 0;
    mScrolling = false;
}

@Override 
public boolean onLongClick(View v){

    Log.d(TAG, "from webView onLongClick ");
    mScrolling = true;
    ((Activity)this.ctx).runOnUiThread(new Runnable() {

        @Override
        public void run() {
            loadUrl("javascript:android.selection.longTouch()");
        }
    });

    Toast.makeText(ctx, "Long click is clicked ", Toast.LENGTH_LONG).show();
    // Don't let the webview handle it
    return true;
}





//*****************************************************
//*
//*     Setup
//*
//*****************************************************

ContextMenu.ContextMenuInfo contextMenuInfo;

/**
 * Setups up the web view.
 * @param context
 */
protected void setup(Context context){


    // On Touch Listener

    this.setOnTouchListener(this);

    this.setClickable(false);
    this.setLongClickable(true);
    this.setOnLongClickListener(this);

    contextMenuInfo = this.getContextMenuInfo();
    // Webview setup
    this.getSettings().setJavaScriptEnabled(true);
    this.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);

    // Create the selection handles
    createSelectionLayer(context);

    // Set to the empty region
    Region region = new Region();
    region.setEmpty();

    _customWebView = this;

    this.lastSelectedRegion = region;


}

/**
 * To clone OnLongClick Listener because its not responding for version 4.1
 */
public Runnable longClickRunnable = new Runnable() {
    public void run() {
        longClickHandler.sendEmptyMessage(0);

    }
};


public Handler longClickHandler = new Handler(){

    public void handleMessage(Message m){
        _customWebView.loadUrl("javascript:android.selection.longTouch();");
        mScrolling = true;
    }
};


public WebTextSelectionJSInterface getTextSelectionJsInterface(){
    return this;
}

//*****************************************************
//*
//*     Selection Layer Handling
//*
//*****************************************************

/**
 * Creates the selection layer.
 * 
 * @param context
 */
protected void createSelectionLayer(Context context){

    LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    this.mSelectionDragLayer = (DragLayer) inflater.inflate(R.layout.selection_drag_layer, null);


    // Make sure it's filling parent
    this.mDragController = new DragController(context);
    this.mDragController.setDragListener(this);
    this.mDragController.addDropTarget(mSelectionDragLayer);
    this.mSelectionDragLayer.setDragController(mDragController);


    this.mStartSelectionHandle = (ImageView) this.mSelectionDragLayer.findViewById(R.id.startHandle);
    this.mStartSelectionHandle.setTag(new Integer(SELECTION_START_HANDLE));
    this.mEndSelectionHandle = (ImageView) this.mSelectionDragLayer.findViewById(R.id.endHandle);
    this.mEndSelectionHandle.setTag(new Integer(SELECTION_END_HANDLE));

    OnTouchListener handleTouchListener = new OnTouchListener(){

        @Override
        public boolean onTouch(View v, MotionEvent event) {

            boolean handledHere = false;
            final int action = event.getAction();
            // Down event starts drag for handle.
            if (action == MotionEvent.ACTION_DOWN) {
               handledHere = startDrag (v);
               mLastTouchedSelectionHandle = (Integer) v.getTag();
            }
            return handledHere;
        }
    };

    this.mStartSelectionHandle.setOnTouchListener(handleTouchListener);
    this.mEndSelectionHandle.setOnTouchListener(handleTouchListener);


}

/**
 * Starts selection mode on the UI thread
 */
private Handler startSelectionModeHandler = new Handler(){

    public void handleMessage(Message m){

        if(mSelectionBounds == null)
            return;

        addView(mSelectionDragLayer);

        drawSelectionHandles();


        int contentHeight = (int) Math.ceil(getDensityDependentValue(getContentHeight(), ctx));

        // Update Layout Params
        ViewGroup.LayoutParams layerParams = mSelectionDragLayer.getLayoutParams();
        layerParams.height = contentHeight;
        layerParams.width = contentWidth;
        mSelectionDragLayer.setLayoutParams(layerParams);

    }

};

/**
 * Starts selection mode.
 * 
 * @param   selectionBounds
 */
public void startSelectionMode(){

    this.startSelectionModeHandler.sendEmptyMessage(0);

}

// Ends selection mode on the UI thread
private Handler endSelectionModeHandler = new Handler(){
    public void handleMessage(Message m){

        //Log.d("TableContentsWithDisplay", "in endSelectionModeHandler");

        removeView(mSelectionDragLayer);
        if(getParent() != null && mContextMenu != null && contextMenuVisible){
            // This will throw an error if the webview is being redrawn.
            // No error handling needed, just need to stop the crash.
            try{
                mContextMenu.dismiss();
            }
            catch(Exception e){

            }
        }
        mSelectionBounds = null;
        mLastTouchedSelectionHandle = -1;
        try {
            ((Activity)ctx).runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    loadUrl("javascript: android.selection.clearSelection();");
                }
            });

        } catch (Exception e) {
            // TODO: handle exception
        }

    }
};

/**
 * Ends selection mode.
 */
public void endSelectionMode(){

    this.endSelectionModeHandler.sendEmptyMessage(0);

}

/**
 * Calls the handler for drawing the selection handles.
 */
private void drawSelectionHandles(){
    this.drawSelectionHandlesHandler.sendEmptyMessage(0);
}

/**
 * Handler for drawing the selection handles on the UI thread.
 */
private Handler drawSelectionHandlesHandler = new Handler(){
    public void handleMessage(Message m){

        MyAbsoluteLayout.LayoutParams startParams = (com.epubreader.drag.MyAbsoluteLayout.LayoutParams) mStartSelectionHandle.getLayoutParams();
        startParams.x = (int) (mSelectionBounds.left - mStartSelectionHandle.getDrawable().getIntrinsicWidth());
        startParams.y = (int) (mSelectionBounds.top - mStartSelectionHandle.getDrawable().getIntrinsicHeight());

        // Stay on screen.
        startParams.x = (startParams.x < 0) ? 0 : startParams.x;
        startParams.y = (startParams.y < 0) ? 0 : startParams.y;


        mStartSelectionHandle.setLayoutParams(startParams);

        MyAbsoluteLayout.LayoutParams endParams = (com.epubreader.drag.MyAbsoluteLayout.LayoutParams) mEndSelectionHandle.getLayoutParams();
        endParams.x = (int) mSelectionBounds.right;
        endParams.y = (int) mSelectionBounds.bottom;
        endParams.x = (endParams.x < 0) ? 0 : endParams.x;
        endParams.y = (endParams.y < 0) ? 0 : endParams.y;

        mEndSelectionHandle.setLayoutParams(endParams);

    }
};

/**
 * Checks to see if this view is in selection mode.
 * @return
 */
public boolean isInSelectionMode(){

    return this.mSelectionDragLayer.getParent() != null;


}

//*****************************************************
//*
//*     DragListener Methods
//*
//*****************************************************

/**
 * Start dragging a view.
 *
 */    
private boolean startDrag (View v)
{
    // Let the DragController initiate a drag-drop sequence.
    // I use the dragInfo to pass along the object being dragged.
    // I'm not sure how the Launcher designers do this.
    Object dragInfo = v;
    mDragController.startDrag (v, mSelectionDragLayer, dragInfo, DragController.DRAG_ACTION_MOVE);
    return true;
}


@Override
public void onDragStart(DragSource source, Object info, int dragAction) {
    // TODO Auto-generated method stub

}

@Override@SuppressWarnings("deprecation")
public void onDragEnd() {
    // TODO Auto-generated method stub

    MyAbsoluteLayout.LayoutParams startHandleParams = (MyAbsoluteLayout.LayoutParams) this.mStartSelectionHandle.getLayoutParams();
    MyAbsoluteLayout.LayoutParams endHandleParams = (MyAbsoluteLayout.LayoutParams) this.mEndSelectionHandle.getLayoutParams();

    float scale = getDensityIndependentValue(this.getScale(), ctx);

    float startX = startHandleParams.x - this.getScrollX();
    float startY = startHandleParams.y - this.getScrollY();
    float endX = endHandleParams.x - this.getScrollX();
    float endY = endHandleParams.y - this.getScrollY();

    startX = getDensityIndependentValue(startX, ctx) / scale;
    startY = getDensityIndependentValue(startY, ctx) / scale;
    endX = getDensityIndependentValue(endX, ctx) / scale;
    endY = getDensityIndependentValue(endY, ctx) / scale;


    if(mLastTouchedSelectionHandle == SELECTION_START_HANDLE && startX > 0 && startY > 0){
        final String saveStartString = String.format("javascript: android.selection.setStartPos(%f, %f);", startX, startY);

        ((Activity)ctx).runOnUiThread(new Runnable() {

            @Override
            public void run() {
                loadUrl(saveStartString);
            }
        });

    }


    if(mLastTouchedSelectionHandle == SELECTION_END_HANDLE && endX > 0 && endY > 0){
        final String saveEndString = String.format("javascript: android.selection.setEndPos(%f, %f);", endX, endY);

        ((Activity)ctx).runOnUiThread(new Runnable() {

            @Override
            public void run() {
                loadUrl(saveEndString);
            }
        });

    }



}


//*****************************************************
//*
//*     Context Menu Creation
//*
//*****************************************************

/**
 * Shows the context menu using the given region as an anchor point.
 * @param region
 */
private void showContextMenu(Rect displayRect){

    // Don't show this twice
    if(this.contextMenuVisible){
        return;
    }

    // Don't use empty rect
    //if(displayRect.isEmpty()){
    if(displayRect.right <= displayRect.left){
        return;
    }

    //Copy action item
    ActionItem buttonOne = new ActionItem();

    buttonOne.setTitle("HighLight");
    buttonOne.setActionId(1);
    //buttonOne.setIcon(getResources().getDrawable(R.drawable.menu_search));


    //Highlight action item
    ActionItem buttonTwo = new ActionItem();

    buttonTwo.setTitle("Note");
    buttonTwo.setActionId(2);
    //buttonTwo.setIcon(getResources().getDrawable(R.drawable.menu_info));

    ActionItem buttonThree = new ActionItem();

    buttonThree.setTitle("Help");
    buttonThree.setActionId(3);
    //buttonThree.setIcon(getResources().getDrawable(R.drawable.menu_eraser));



    // The action menu
    mContextMenu  = new QuickAction(this.getContext());
    mContextMenu.setOnDismissListener(this);

    // Add buttons
    mContextMenu.addActionItem(buttonOne);

    mContextMenu.addActionItem(buttonTwo);

    mContextMenu.addActionItem(buttonThree);



    //setup the action item click listener
    mContextMenu.setOnActionItemClickListener(new QuickAction.OnActionItemClickListener() {

        @Override
        public void onItemClick(QuickAction source, int pos,
            int actionId) {

            if (actionId == 1) { 

                callHighLight();
            } 
            else if (actionId == 2) { 

                callNote();
            } 
            else if (actionId == 3) { 
                // Do Button 3 stuff
                Log.i(TAG, "Hit Button 3");
            }

            contextMenuVisible = false;

        }

    });

    this.contextMenuVisible = true;
    mContextMenu.show(this, displayRect);
}

private void callHighLight(){

    ((Activity)this.ctx).runOnUiThread(new Runnable() {

        @Override
        public void run() {
            loadUrl("javascript:init_txt_selection_event()");
            loadUrl("javascript:highlightme_("+0+")");
        }
    });

}

private void callNote(){

    ((Activity)this.ctx).runOnUiThread(new Runnable() {

        @Override
        public void run() {
            loadUrl("javascript:init_txt_selection_event()");
            loadUrl("javascript:fnGetUserAddedNote('1')");
        }
    });

}


//*****************************************************
//*
//*     OnDismiss Listener
//*
//*****************************************************
/**
 * Clears the selection when the context menu is dismissed.
 */
public void onDismiss(){
    //clearSelection();
    this.contextMenuVisible = false;
}

//*****************************************************
//*
//*     Text Selection Javascript Interface Listener
//*
//*****************************************************
/**
 * The user has started dragging the selection handles.
 */
public void tsjiStartSelectionMode(){

    this.startSelectionMode();


}

/**
 * The user has stopped dragging the selection handles.
 */
public void tsjiEndSelectionMode(){

    this.endSelectionMode();
}

/**
 * The selection has changed
 * @param range
 * @param text
 * @param handleBounds
 * @param menuBounds
 * @param showHighlight
 * @param showUnHighlight
 */@SuppressWarnings("deprecation")
public void tsjiSelectionChanged(String range, String text, String handleBounds, String menuBounds){
    try {

        //Log.d(TAG, "tsjiSelectionChanged :- handleBounds " + handleBounds);
        JSONObject selectionBoundsObject = new JSONObject(handleBounds);

        float scale = getDensityIndependentValue(this.getScale(), ctx);

        Rect handleRect = new Rect();
        handleRect.left = (int) (getDensityDependentValue(selectionBoundsObject.getInt("left"), getContext()) * scale);
        handleRect.top = (int) (getDensityDependentValue(selectionBoundsObject.getInt("top"), getContext()) * scale);
        handleRect.right = (int) (getDensityDependentValue(selectionBoundsObject.getInt("right"), getContext()) * scale);
        handleRect.bottom = (int) (getDensityDependentValue(selectionBoundsObject.getInt("bottom"), getContext()) * scale);

        this.mSelectionBounds = handleRect;
        this.selectedRange = range;
        this.selectedText = text;

        JSONObject menuBoundsObject = new JSONObject(menuBounds);

        Rect displayRect = new Rect();
        displayRect.left = (int) (getDensityDependentValue(menuBoundsObject.getInt("left"), getContext()) * scale);
        displayRect.top = (int) (getDensityDependentValue(menuBoundsObject.getInt("top") - 25, getContext()) * scale);
        displayRect.right = (int) (getDensityDependentValue(menuBoundsObject.getInt("right"), getContext()) * scale);
        displayRect.bottom = (int) (getDensityDependentValue(menuBoundsObject.getInt("bottom") + 25, getContext()) * scale);

        if(!this.isInSelectionMode()){
            this.startSelectionMode();
        }

        // This will send the menu rect
        this.showContextMenu(displayRect);

        drawSelectionHandles();


    } catch (JSONException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


}


/**
 * Receives the content width for the page.
 */
public void tsjiSetContentWidth(float contentWidth){
    this.contentWidth = (int) this.getDensityDependentValue(contentWidth, ctx);
}


//*****************************************************
//*
//*     Density Conversion
//*
//*****************************************************
/**
 * Returns the density dependent value of the given float
 * @param val
 * @param ctx
 * @return
 */
public float getDensityDependentValue(float val, Context ctx){
    // Get display from context
    Display display = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    // Calculate min bound based on metrics
    DisplayMetrics metrics = new DisplayMetrics();
    display.getMetrics(metrics);
    return val * (metrics.densityDpi / 160f);
}

/**
 * Returns the density independent value of the given float
 * @param val
 * @param ctx
 * @return
 */
public float getDensityIndependentValue(float val, Context ctx){

    // Get display from context
    Display display = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    // Calculate min bound based on metrics
    DisplayMetrics metrics = new DisplayMetrics();
    display.getMetrics(metrics);
    return val / (metrics.densityDpi / 160f);
}

}

在此先感谢!

推荐答案

我意识到这是一个老问题,但还没有一个公认的答案,并没有提供答案有很多票。

I realize this is an old question, but there is not an accepted answer, and none of the provided answers have many votes.

我已经实现了,你要完成创建一个自定义操作模式回调是什么。这允许创建一个自定义的上下文操作栏(CAB)的时候(在的WebView的情况下)的用户长点击查看。 注意:此在4.0+只有作品和一件只适用于4.4

I have achieved what you are trying to accomplish by creating a custom action mode callback. This allows the creation of a custom contextual action bar (CAB) when (in the case of a WebView) a user long-clicks the view. NOTE: This only works in 4.0+ and one piece only works in 4.4.

创建包含您的自定义菜单的布局一个新的Andr​​oid XML文件。这里是我的(context_menu.xml)为例:

Create a new Android XML file containing the layout for your custom menu. Here is mine (context_menu.xml) as an example:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/copy"
        android:icon="@drawable/ic_action_copy"
        android:showAsAction="always" <!-- Forces this button to be shown -->
        android:title="@string/copy">
    </item>
    <item
        android:id="@+id/button2"
        android:icon="@drawable/menu_button2icon"
        android:showAsAction="ifRoom" <!-- Show if there is room on the screen-->
        android:title="@string/button2">
    </item>
    <!-- Add as many more items as you want.
         Note that if you use "ifRoom", an overflow menu will populate
         to hold the action items that did not fit in the action bar. -->

</menu>

现在,该菜单定义,创建一个回调吧:

Now that the menu is defined, create a callback for it:

public class CustomWebView extends WebView {

    private ActionMode.Callback mActionModeCallback;

    private class CustomActionModeCallback implements ActionMode.Callback {

        // Called when the action mode is created; startActionMode() was called
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            // Inflate a menu resource providing context menu items
            MenuInflater inflater = mode.getMenuInflater();
            inflater.inflate(R.menu.context_menu, menu);
            return true;
        }

        // Called each time the action mode is shown.
        // Always called after onCreateActionMode, but
        // may be called multiple times if the mode is invalidated.
        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            // Note: This is called every time the selection handlebars move.
            return false; // Return false if nothing is done
        }

        // Called when the user selects a contextual menu item
        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {

            switch (item.getItemId()) {
            case R.id.copy:
                // Do some stuff for this button
                mode.finish(); // Action picked, so close the CAB
                return true;
            case R.id.button2:
                // Do some stuff for this button
                mode.finish();
                return true;
            // Create a case for every item
            ...
            default:
                mode.finish();
                return false;
        }

        // Called when the user exits the action mode
        @Override
        public void onDestroyActionMode(ActionMode mode) {
            // This will clear the selection highlight and handlebars.
            // However, it only works in 4.4; I am still investigating
            // how to reliably clear the selection in 4.3 and earlier
            clearFocus();
        }
    }
}

在这些作品都很到位,覆盖 startActionMode 方法,以便回调将实际发生在长点击:

Once those pieces are in place, override the startActionMode method so that the callback will actually occur on a long-click:

public class CustomWebView extends WebView {
    @Override
    public ActionMode startActionMode(Callback callback) {
        ViewParent parent = getParent();
        if (parent == null) {
        return null;
        }
        mActionModeCallback = new CustomActionModeCallback();
        return parent.startActionModeForChild(this, mActionModeCallback);
    }
}

现在你将要出现,并填充当用户长点击您的的WebView 自定义菜单。作为参考,我发现这个信息从 Android开发教程并从this回答。

Now you have a custom menu that will be appear and populate when a user long-clicks your WebView. For reference, I found this information from an Android Developer tutorial and modified the suggestion from this answer.

最后要注意:这种技术将覆盖所选文本的本地复制/粘贴菜单。如果你想保持这种功能,你将需要实现它自己。 (这就是为什么我的第一个按钮是'复制'。)如果你需要,请参阅的这个谷歌教程获得更多的信息和正确的方法来实现它。

One final note: This technique overrides the native copy/paste menu for selected text. If you want to maintain that functionality, you will need to implement it yourself. (That is why my first button is 'copy'.) If you need that, refer to this Google tutorial for more information and the proper way to implement it.

 
精彩推荐
图片推荐