当前位置: 首页 > 知识库问答 >
问题:

如何覆盖android webview操作系统4.1+的默认文本选择?

郑卜鹰
2023-03-14
  • 宏碁Iconia a500平板电脑:10英寸:Android OS-3.0
  • 宏碁Iconia a500平板电脑:10英寸:Android OS-3.2
  • 三星Galaxy标签:10英寸:Android OS-4.0
  • 三星Galaxy标签:7英寸:Android OS-4.0
  • 模拟器:Skin-WVGA800:Android OS-4.1.2

不在以下设备上工作:

  • 三星Galaxy标签:10英寸:Android OS-4.1.2
  • 三星Galaxy标签:7英寸:Android OS-4.1.2
  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);
}

提前道谢!

共有1个答案

陆宏壮
2023-03-14

我意识到这是一个老问题,但没有一个被接受的答案,而且提供的答案都没有多少票。

我已经通过创建一个自定义动作模式回调实现了您试图实现的目标。这允许在用户长时间单击视图时(对于WebView)创建自定义上下文操作条(CAB)。注意:这只在4.0+中有效,一件只在4.4中有效。

创建一个包含自定义菜单布局的新Android XML文件。下面是我的(context_menu.xml)作为示例:

<?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>
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();
        }
}
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);
    }
}
 类似资料:
  • 我目前正在做一个项目,在这个项目中,我们有一个jenkins实例与一个单独的网站并排运行,工作流程是这样的,用户需要点击网站中的链接,从而触发jenkins实例中的jenkins作业。 触发的jenkins作业有几十个参数,我们目前正在做的是,该网站将使用javascript构建一个如下URL: https://JENKINS_HOST/作业/JOB_NAME/build with Paramet

  • 我有一个RESTAPI,我不想强迫客户端发送请求参数。我有将近400个api方法,我不想将所有参数设置为“required=false” 我想覆盖Spring RequestParam的默认行为。我想将RequestParam接口的“required”属性的默认值设置为“false”。 有什么方法可以覆盖它吗?如果我不能或这不是最佳实践,有什么方法可以解决上述问题。

  • 问题内容: 是否有检测操作系统默认语言的通用方法?(无论运行代码的操作系统是什么) 上面的代码在Linux下工作,在其他OS上工作吗? 问题答案: 您可以在模块中使用该功能。它以元组形式返回系统默认语言环境的语言代码和编码:

  • 问题内容: 我已经能够覆盖所有名称以“ android:”为前缀的主题,但是Android themes.xml还定义了似乎无法被覆盖的属性。例如: colorTheground是在Theme.Light xml中定义的,但是在此处添加它可以使我 错误。如何为整个应用程序覆盖该样式? 问题答案: 您可以用修改属性(如)的方式覆盖标准属性,只是不要忘记添加如下前缀:

  • 问题内容: 我想覆盖Java外观。我只想显示不同的按钮。 我想要Windows Look and Feel的所有功能,但仅按钮有所不同。希望你明白我的意思。 还告诉我如何制作圆形的JtabbedPane ??? 问题答案: 自定义GUI类 调用您的自定义GUI类