public class SelectionController { private ViewGroup selectableViewGroup; public SelectionController(ViewGroup selectableViewGroup) { this.selectableViewGroup = selectableViewGroup; } }
public class SelectableLayoutManager extends LinearLayoutManager { private SelectionController sh; public SelectableLayoutManager(Context context) { super(context); } public SelectableLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } public SelectableLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } public void setSelectionController(SelectionController selectionController) { sh = selectionController; } }
public class SelectableRecyclerView extends RecyclerView { private SelectionController sh; public SelectableRecyclerView(Context context) { super(context); } public SelectableRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public SelectableRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onFinishInflate() { super.onFinishInflate(); sh = new SelectionController(this); } @Override public void setLayoutManager(LayoutManager layout) { super.setLayoutManager(layout); if (layout instanceof SelectableLayoutManager) { ((SelectableLayoutManager) layout).setSelectionController(sh); } } }
private void initGesture() { gestureDetector = new GestureDetector(selectableViewGroup.getContext(), new GestureDetector.SimpleOnGestureListener() { @Override public void onLongPress(MotionEvent event) { if (!selectInProcess) { startSelection(event); } } }); }
selectableViewGroup.getLocationOnScreen(location); int evX = (int) (event.getX() + location[0]); int evY = (int) (event.getY() + location[1]);
public boolean isInside(int evX, int evY) { int[] location = new int[2]; getLocationOnScreen(location); int left = location[0]; int right = left + getWidth(); int top = location[1]; int bottom = top + getHeight(); return left <= evX && right >= evX && top <= evY && bottom >= evY; }
private int getLineAtCoordinate(float y) { y -= getTotalPaddingTop(); y = Math.max(0.0f, y); y = Math.min(getHeight() - getTotalPaddingBottom() - 1, y); y += getScrollY(); return getLayout().getLineForVertical((int) y); }
private int getOffsetAtCoordinate(int line, float x) { x = convertToLocalHorizontalCoordinate(x); return getLayout().getOffsetForHorizontal(line, x); } private float convertToLocalHorizontalCoordinate(float x) { x -= getTotalPaddingLeft(); x = Math.max(0.0f, x); x = Math.min(getWidth() - getTotalPaddingRight() - 1, x); x += getScrollX(); return x; }
public int getOffsetForPosition(int x, int y) { if (getLayout() == null) return -1; final int line = getLineAtCoordinate(y); return getOffsetAtCoordinate(line, x); }
private int[] getHandlesPosition(final String text, final int pos) { final int[] handlesPosition = new int[2]; final int textLength = text.length(); handlesPosition[0] = 0; for (int i = pos; i >= 0; i--) { if (!LetterDigitPattern.matcher(String.valueOf(text.charAt(i))).matches()){ handlesPosition[0] = i + 1; break; } } handlesPosition[1] = textLength - 1; for (int i = pos; i < textLength; i++) { if (!LetterDigitPattern.matcher(String.valueOf(text.charAt(i))).matches()){ handlesPosition[1] = i; break; } } return handlesPosition; }
public void draw(Canvas canvas) { canvas.drawBitmap(handleImage, x, y, paint); }
@Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); sh.drawHandles(canvas); } SelectionController.java public void drawHandles(Canvas canvas) { if (!selectInProcess) return; rightHandle.draw(canvas); leftHandle.draw(canvas); }
public boolean onTouchEvent(MotionEvent ev) { if (gestureDetector != null) gestureDetector.onTouchEvent(ev); boolean dispatched = false; if (selectInProcess) { boolean right = rightHandleListener.onTouchHandle(ev); boolean left = leftHandleListener.onTouchHandle(ev); dispatched = right || left; } return dispatched; } public boolean onTouchHandle(MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: // handle.isMoving = handle.contains(event.getX(), event.getY()); if (handle.isMoving) { // yDelta = (int) (event.getY() - handle.y + 1); xDelta = (int) (event.getX() - handle.x + handle.correctX); // , parent' touchevent' selectableViewGroup.getParent().requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_UP: handle.isMoving = false; selectableViewGroup.getParent().requestDisallowInterceptTouchEvent(false); break; case MotionEvent.ACTION_POINTER_DOWN: break; case MotionEvent.ACTION_POINTER_UP: break; case MotionEvent.ACTION_MOVE: if (handle.isMoving) { // x = (int) (event.getRawX() - xDelta); y = (int) (event.getRawY() - yDelta); int oldHandlePos = handle.position; // handle.position = getCursorPosition(x, y, handle.position); if (handle.position != oldHandlePos) { // setHandleCoordinate(handle); // , setSelectionText(); // backround , // checkBackground(); // selectableViewGroup.invalidate(); } } break; } return handle.isMoving; }
@Override public boolean onSingleTapUp(MotionEvent e) { if (selectInProcess) { copyToClipBoard(stopSelection().toString()); } return super.onSingleTapUp(e); } private void copyToClipBoard(String s) { ClipboardManager clipboard = (ClipboardManager) selectableViewGroup.getContext().getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText("Article", s); clipboard.setPrimaryClip(clip); Toast.makeText(selectableViewGroup.getContext(), "Text was copied to clipboard", Toast.LENGTH_LONG).show(); }
public void checkHandlesPosition() { if (!selectInProcess) return; setHandleCoordinate(rightHandle); setHandleCoordinate(leftHandle); selectableViewGroup.postInvalidate(); } private void setHandleCoordinate(Handle handle) { Selectable textView = null; int totalPos = 0; for (SelectableInfo selectableInfo : selectableInfos) { String text = selectableInfo.getText().toString(); int length = text.length(); if (handle.position >= totalPos && handle.position < totalPos + length) { textView = selectableInfo.getSelectable(); break; } totalPos += length; } if (textView == null) { handle.visible = false; return; } if (!isSvgParent((View)textView)) { handle.visible = false; checkSelectableList(); return; } handle.visible = true; float[] coordinate = new float[2]; coordinate = textView.getPositionForOffset(handle.position - totalPos, coordinate); int[] location = new int[2]; selectableViewGroup.getLocationOnScreen(location); if (coordinate[0] == -1 || coordinate[1] == -1) return; handle.x = coordinate[0] - location[0] + handle.correctX; handle.y = coordinate[1] - location[1]; }
public class SelectableInfo { private int start; private int end; private String selectedText; private String text; private String key; private Selectable selectable; public SelectableInfo(Selectable selectable) { this.start = 0; this.end = 0; this.selectedText = ""; this.selectable = selectable; this.text = selectable.getText(); this.key = selectable.getKey(); } }
Selectable - , SelectableTextView. public interface Selectable { int getOffsetForPosition(int x, int y); int getVisibility(); CharSequence getText(); void setText(CharSequence text); void getLocationOnScreen(int[] location); int getHeight(); int getWidth(); float[] getPositionForOffset(int offset, float[] position); void selectText(int start, int end); CharSequence getSelectedText(); boolean isInside(int evX, int evY); void setColor(int selectionColor); int getStartSelection(); int getEndSelection(); String getKey(); void setKey(String key); }
@Override public void onBindViewHolder(VHolder viewHolder, int position) { viewHolder.textView.setText(sampleText); viewHolder.textView.setKey(" pos: " + position + sampleText); }
@Override public void addView(View child, int index) { super.addView(child, index); sh.addViewToSelectable(child); }
public void addViewToSelectable(View view) { checkSelectableList(); if (view instanceof Selectable){ addSelectableToSelectableInfos((Selectable) view); } else if (view instanceof ViewGroup){ findSelectableTextView((ViewGroup) view); } } public void findSelectableTextView(ViewGroup viewGroup) { for (int i = 0; i < viewGroup.getChildCount(); i++){ View view = viewGroup.getChildAt(i); if (view instanceof Selectable){ addSelectableToSelectableInfos((Selectable) view); continue; } if (view instanceof ViewGroup){ findSelectableTextView((ViewGroup) view); } } }
private void addSelectableToSelectableInfos(Selectable selectable) { boolean found = false; for (SelectableInfo selectableInfo : selectableInfos) { if (selectableInfo.getKey().equals(selectable.getKey())) { selectableInfo.setSelectable(selectable); found = true; break; } } if (!found) { final SelectableInfo selectableInfo = new SelectableInfo(selectable); selectableInfos.add(selectableInfo); } }
public void checkSelectableList() { for (SelectableInfo selectableInfo : selectableInfos) { if (selectableInfo.getSelectable() != null) { if (!selectableInfo.getSelectable().getKey().equals(selectableInfo.getKey())) { selectableInfo.removeSelectable(); continue; } if (!isSvgParent((View) selectableInfo.getSelectable())) { selectableInfo.removeSelectable(); } } } }
Source: https://habr.com/ru/post/268501/