我正在尝试制作FastSelectEditText,以便:
>可以通过长按选择文本并滑动手指.
>滑动和选择时,显示放大玻璃(如iphone),以便用户可以在手指下看到文字.
不幸的是我的设计存在问题:MagGlass只显示在我的FastSelectEditText中.当用户在顶行选择文本时,她看不到mag玻璃.
所以我必须使用这个工作:当它到达FastSelectEditText的顶部时,显示低于手指的mag玻璃.
我明白如果我使用Mag Glass的另一个视图,这不会有问题.但是为了保持代码简单,我认为最好将Mag Glass保留在FastSelectEditText中.
有没有办法在视图范围之外绘制一些东西?
或者我应该编写另一个视图(而不是自定义EditText中的一些代码)来实现Mag Glass?(并且可能将这些视图放在框架布局中?)
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);
}
}
}
最佳答案 要在视图范围之外绘制,您需要将视图的父级clipChildren设置为false.
默认情况下,ViewGroup将clipChildrenset设置为true,这会导致子项在剪裁到其边界的画布上绘制.