Ampliar vidrio para EditText como en iphone: ¿es posible dibujar fuera de una vista?

Estoy intentando hacer un FastSelectEditText, de modo que:

  1. El texto puede seleccionarse con un clic largo y deslizar el dedo.
  2. Al deslizar y seleccionar, mostrar un cristal de aumento (como iphone), para que el usuario puede ver el texto bajo su dedo.

Lamentablemente hay un problema con mi diseño: El MagGlass muestra sólo dentro de mi FastSelectEditText. Cuando el usuario está seleccionando el texto en las líneas superiores, no puede ver el vidrio mag.
Así que tengo que usar este trabajo alrededor: mostrar el vidrio mag inferior al dedo, cuando llega a la parte superior de la FastSelectEditText.

Entiendo que si utilizo otra vista para Mag Glass, eso no será un problema. Pero para mantener el código simple, creo que es mejor mantener el vidrio Mag dentro de FastSelectEditText.

¿Hay alguna manera de dibujar algo fuera del límite de una vista?
¿O debería escribir otra vista (en lugar de algún código dentro del Custom EditText) para implementar un Mag Glass? (Y probablemente poner estas vistas dentro de un marco de diseño?)

El vidrio mag se muestra superior al dedo tocado
El vidrio mag se muestra más bajo que el dedo tocado

public class FastSelectEditText extends EditText implements OnLongClickListener { /** * @param context */ public FastSelectEditText(Context context) { super(context); init(); } /** * @param context * @param attrs */ public FastSelectEditText(Context context, AttributeSet attrs) { super(context, attrs); init(); } /** * @param context * @param attrs * @param defStyle */ public FastSelectEditText(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private MagGlass mMagGlass; private float mScale; private void init(){ DisplayMetrics metrics = getResources().getDisplayMetrics(); mScale = metrics.density; setGravity(Gravity.TOP); setOnLongClickListener(this); mMagGlass = new MagGlass(); } private int getOffset(int x, int y){ Layout layout = getLayout(); int row = layout.getLineForVertical(getScrollY()+y-getPaddingTop()); return layout.getOffsetForHorizontal(row, x-getPaddingLeft()); } /** * the position/index when touch down. */ private int mDownOffset = 0; private int mOldSelStart, mOldSelEnd; /** * Did the user moved his finger after down event? */ private boolean mMoved = false; @Override public boolean dispatchTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); mMagGlass.setObjectCenter(x, y); boolean result; switch (event.getAction()){ case MotionEvent.ACTION_DOWN: mOldSelStart = getSelectionStart(); mOldSelEnd = getSelectionEnd(); if (mOldSelStart != mOldSelEnd){ startSlideAndSelect(); } mDownOffset = getOffset(x, y); return super.dispatchTouchEvent(event); case MotionEvent.ACTION_MOVE: result = super.dispatchTouchEvent(event); int offset = getOffset(x, y); if (!mMoved && mDownOffset != offset){ mMoved = true; } if (mSlideAndSelect){ if (mMoved){ setSelection(mDownOffset, offset); } return true; } return result; case MotionEvent.ACTION_UP: boolean moved = mMoved; // reset mMoved mMoved = false; boolean longClicked = mLongClicked; mLongClicked = false; if (mSlideAndSelect && moved){ event.setAction(MotionEvent.ACTION_CANCEL); } result = super.dispatchTouchEvent(event); if (mSlideAndSelect){ mSlideAndSelect = false; int upOffset = getOffset(x, y); if (!moved && mDownOffset == upOffset && longClicked){ setSelection(mOldSelStart, mOldSelEnd); showContextMenu(); }else{ setSelection(mDownOffset, upOffset); } return true; } return result; case MotionEvent.ACTION_CANCEL: mSlideAndSelect = false; // reset mMoved mMoved = false; mLongClicked = false; return super.dispatchTouchEvent(event); default: return super.dispatchTouchEvent(event); } } protected void startSlideAndSelect() { mSlideAndSelect = true; ViewParent parent = getParent(); if (parent != null){ parent.requestDisallowInterceptTouchEvent(true); } } private boolean mSlideAndSelect = false; private boolean mLongClicked = false; private Vibrator mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); @Override public boolean onLongClick(View v) { if (!mMoved){ startSlideAndSelect(); mLongClicked = true; mVibrator.vibrate(30); } return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mSlideAndSelect){ mMagGlass.draw(canvas); } } /** * Need a drawable.mag_glass to work. * * @author lifurong * */ class MagGlass{ private int mWidth, mHeight; private Bitmap mMagGlassBitmap; private int mX, mY; private final static int INSET = 10; public MagGlass(){ mMagGlassBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mag_glass); mWidth = mMagGlassBitmap.getWidth(); mHeight = mMagGlassBitmap.getHeight(); } public void setObjectCenter(int x, int y){ mX = x; mY = y; } public void draw(Canvas canvas) { final float left = mX-mWidth/2.0f; final float top = mY-mHeight/2.0f; final float right = mX+mWidth/2.0f; final float bottom = mY+mHeight/2.0f; float vTrans = 80*mScale; int vTransSign; int[] location = new int[2]; getLocationInWindow(location); int topEdge = location[1]-getPaddingTop()>0? 0:-location[1]+getPaddingTop(); if (top-vTrans > topEdge){ vTransSign = -1; }else{ vTransSign = 1; } canvas.translate(0, vTrans*vTransSign); canvas.clipRect(left, top, right, bottom); canvas.drawBitmap(mMagGlassBitmap, left, top, null); canvas.clipRect(left+INSET, top+INSET, right-INSET, bottom-INSET); FastSelectEditText.super.onDraw(canvas); } } 

}

Para dibujar fuera del límite de una vista, debe establecer el clipChildren del padre de la clipChildren en false .

De forma predeterminada, un grupo de ViewGroup tiene el clipChildren establecido en true , lo que provocó que los niños dibujen en un lienzo recortado a sus límites.

  • El método setLayoutParams () no funciona
  • Obtener la vista de los padres desde un diseño
  • cómo establecer el color de texto de webview en android
  • ¿Por qué obtengo una excepción de puntero nulo de TabWidget?
  • Android: Obtener una vista Referencia a un elemento de menú
  • No es un archivo DRM, abriendo notmally
  • ¿Cómo obtener el lienzo actual?
  • Aplicar una máscara a una sola vista de superposición sin enmascarar toda la actividad
  • Android Webview goback () problema con el método loadDataWithBaseURL
  • Diferencia entre OnTouchListener y OnClickListener
  • Android - listview obtener la vista del artículo por posición
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.