Dynamically changing the contextual / long-term menu in EditText based on the long-press position

I am using the EditText widget and want to change the context menu that appears when the user clicks on the view for a long time. The problem I am facing is that I need to know the position of the character in the long press text so that I can determine what I need to add to the context menu. The base class does this because one of the options on the Add menu is word_clicked_on "To Dictionary". Customizing ClickableSpans in the text does not seem to be a solution, because it uses the click event, which makes it impossible to move the editing cursor within spaces.

+4
source share
1 answer

Here is the solution I came across and it works, so I would like to share it:

First, I came to the conclusion that I need to extend the EditText class so that I can intercept onTouchEvent, grab the ACTION_DOWN event and save the position. Now that I have a low point position, I can call getOffsetForPosition (downPointX, downPointY) and get the position of the character for a long press. There is one big problem: getOffsetForPosition was not added until SDK 14! To make this decision, I had to cancel the port of the getOffsetForPosition function and branches if the current SDK was earlier than SDK_INT 14. Here is the source code for the new class:

public class ScrapEditText extends EditText{ protected float LastDownPositionX, LastDownPositionY; public ScrapEditText(Context context) { super(context); } public ScrapEditText(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent event) { final int action = event.getActionMasked(); if(action == MotionEvent.ACTION_DOWN) { LastDownPositionX = event.getX(); LastDownPositionY = event.getY(); } return super.onTouchEvent(event); } public float GetLastDownPositionX() { return LastDownPositionX; } public float GetLastDownPositionY() { return LastDownPositionY; } public int GetOffsetForLastDownPosition() { if(Build.VERSION.SDK_INT > 13) { // as of SDK 14 the getOffsetForPosition was added to TextView return getOffsetForPosition(LastDownPositionX, LastDownPositionY); } else { return GetOffsetForPositionOlderSdk(); } } public int GetOffsetForPositionOlderSdk() { if (getLayout() == null) return -1; final int line = GetLineAtCoordinateOlderSDK(LastDownPositionY); final int offset = GetOffsetAtCoordinateOlderSDK(line, LastDownPositionX); return offset; } public int GetLineAtCoordinateOlderSDK(float y) { y -= getTotalPaddingTop(); // Clamp the position to inside of the view. y = Math.max(0.0f, y); y = Math.min(getHeight() - getTotalPaddingBottom() - 1, y); y += getScrollY(); return getLayout().getLineForVertical((int) y); } protected int GetOffsetAtCoordinateOlderSDK(int line, float x) { x = ConvertToLocalHorizontalCoordinateOlderSDK(x); return getLayout().getOffsetForHorizontal(line, x); } protected float ConvertToLocalHorizontalCoordinateOlderSDK(float x) { x -= getTotalPaddingLeft(); // Clamp the position to inside of the view. x = Math.max(0.0f, x); x = Math.min(getWidth() - getTotalPaddingRight() - 1, x); x += getScrollX(); return x; } } 

In the derived Activity class:

 ScrapText = (ScrapEditText) findViewById(R.id.sample_text); ScrapText.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener(){ @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { int charOffset = FileText.GetOffsetForLastDownPosition(); } }); 
+4
source

Source: https://habr.com/ru/post/1344657/


All Articles