在drawview中放置自定义edittext

时间:2013-12-27 21:38:05

标签: android android-edittext android-canvas

我基于http://alinberce.wordpress.com/2012/02/20/android-edittext-with-custom-font-and-clear-button/松散地创建了一个自定义EditText。我的应用程序的主要xml是一个RelativeLayout,它包含一堆控制按钮和一个扩展View的自定义drawview类。当点击一个按钮时,我能够以编程方式将EditText添加到主xml中,并且它在那里工作:我可以通过拖动它的角来调整它的大小,然后按下>将其拖动到屏幕上。 100毫秒。

因为可以通过控制按钮移动EditText,我觉得EditText的正确位置在drawview中。所以我将drawview更改为ViewGroup,并添加了我希望将EditText放在那里的适当代码。我没有对自定义EditText如何操作进行任何更改(只是足以让它出现在Viewgroup而不是View中),但现在它不像以前那样工作。它显示为正方形而不是矩形,并且不会通过触摸移动或调整大小。

我一直在努力使用各种LayoutParams和MarginLayoutParams,以及editText.setMinimumHeight和.setMinimumWidth,但更改这些似乎没有任何区别。抽象地说,我知道我需要覆盖ViewGroup中的onMeasure并测量子节点。抽象地说,我知道我需要覆盖onLayout并执行editText.layout,看起来我应该创建一个Rect来定义它的边界,但是因为它应该在输入文本时原生自动化,并在拖动角落时调整大小,我不会知道Rect是否正确。我应该使用哪些具体方法?我没有从api文档中推断出来的经验。例子。有人能指出我正确的方向吗?

编辑:

绘制视图太长而无法发布,onMeasure和onLayout上的覆盖是我正在寻求帮助的。

将editText添加到drawview:

 private void addEditText() {
    final MovableEditText et = new MovableEditText(app);
 // I know this is terrifically messy
    et.setMinimumWidth(50);
    et.setMinimumHeight(30);
    et.setTextSize(app.getTextSize());
    et.setTextColor(app.getLineColor());
    et.setBackgroundColor(Color.parseColor("#77CCCCCC")); // some kind of light transparent gray
    et.setText(app.getText());
    et.setTag("TEXTENTRY");
    et.setTextCompletedListener(new TextCompletedListener() {
        @Override
        public void onTextCompleted() {
            removeEditText();
            drawView.invalidate();
        }
    });
    app.editText = et;
    // place the new editText sorta top center of the screen
 //        Rect clipBounds = drawView.getClipBounds();
    DrawView dv = (DrawView) findViewById(R.id.drawview);
    ViewGroup.MarginLayoutParams etParams = new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT);
    dv.addView(et, etParams);
    et.requestFocus();
    dv.invalidate();
    InputMethodManager imm = (InputMethodManager) app.getSystemService(Context.INPUT_METHOD_SERVICE);
    if (imm != null) {
        imm.showSoftInput(et, 0);
    }
}

edittext本身:

 public class MovableEditText extends EditText {

// 2 drawables, a close (cancel) and a resize handle
private Drawable closeImg = getResources().getDrawable(R.drawable.text_ok);
private Drawable resizeImg = getResources().getDrawable(R.drawable.text_resize);
private long timeFingerDown;
private InputMethodManager imm;
private App app;
private boolean resizing;
private TextCompletedListener textListener;

public MovableEditText(Context context) {
    super(context);
    app = (App) context.getApplicationContext();
    imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
    init();
}

public MovableEditText(Context context, AttributeSet attrs) {
    super(context, attrs);
    app = (App) context.getApplicationContext();
    imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
    init();
}

public MovableEditText(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    app = (App) context.getApplicationContext();
    imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
    init();
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
}

public void setTextCompletedListener(TextCompletedListener l) {
    textListener = l;
}

private void init() {
    // Set bounds of the Clear button so it will look ok
    closeImg.setBounds(0, 0, closeImg.getIntrinsicWidth(), closeImg.getIntrinsicHeight());
    resizeImg.setBounds(0, 0, resizeImg.getIntrinsicWidth(), resizeImg.getIntrinsicHeight());
    // There may be initial text in the field, so we may need to display the  button
    showOkButton();
    this.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            MovableEditText et = MovableEditText.this;
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    timeFingerDown = event.getEventTime();
                    return true;

                case MotionEvent.ACTION_UP:
                    //if the Close image is displayed and the user remove his finger from the button, clear it. Otherwise do nothing
 //                  Log.i("napkinapp", "event x,y = "+event.getX()+", "+event.getY());
                    if (resizing) {
                        resizing = false;
                    }
                    // clicking on the checkbox
                    if (event.getY() < et.getPaddingTop() + closeImg.getIntrinsicHeight()) {
                        et.okButtonClick();
                        return false;
                    }
                    // otherwise, show the keyboard
                    if (imm != null) {
                        imm.showSoftInput(MovableEditText.this, 0);
                    }

                    return false;

                case MotionEvent.ACTION_MOVE:
                    if (event.getX() > et.getWidth() - et.getPaddingRight() - resizeImg.getIntrinsicWidth()) {
                        resizeBox(et, event);
                        // we touched the arrow, so we are resizing the box (i.e. increasing font size)
                        resizing = true;
                        return true;
                    }
                    if (event.getEventTime() - timeFingerDown > 200 && !resizing) {
                        // we are moving the box
                        moveBox(et, event);
                    }
                    return true;
            }
            return false;
        }
    });

    //if text changes, take care of the button
    this.addTextChangedListener(new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            //
            MovableEditText.this.showOkButton();
        }

        @Override
        public void afterTextChanged(Editable arg0) {
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }
    });
}

private void moveBox(MovableEditText et, MotionEvent event) {
    ViewGroup.MarginLayoutParams etParams = (ViewGroup.MarginLayoutParams) this.getLayoutParams();
    etParams.leftMargin += (int) (event.getX() - (et.getWidth()/2));
    etParams.topMargin += (int) (event.getY() - this.getHeight()) ;
    et.setLayoutParams(etParams);
}

private void resizeBox(MovableEditText et, MotionEvent event) {
    et.setWidth((int) event.getX());
    et.setHeight((int) event.getY());
    resizeText(et);
}

private void resizeText(MovableEditText et) {
    int height = (int) ((et.getHeight() - closeImg.getIntrinsicHeight())*.25);
    et.setTextSize(height);
}

void showOkButton() {
    if (this.getText().toString().equals("")) {
        // remove the clear button
        this.setCompoundDrawables(this.getCompoundDrawables()[0],null, resizeImg, this.getCompoundDrawables()[3] );
    } else {
        //add clear button
        this.setCompoundDrawables(this.getCompoundDrawables()[0], closeImg, resizeImg, this.getCompoundDrawables()[3]);
    }
}

void okButtonClick() {
    // get the text, get the size, get the position, create a Stroke from it
    if (this.getText().toString().length()>0) {
        app.setText(this.getText().toString());
        app.setTextSize(this.getPaint().getTextSize()*.5f);
        ViewGroup.MarginLayoutParams etParams = (ViewGroup.MarginLayoutParams) this.getLayoutParams();
        int left = this.getLeft() + etParams.leftMargin;
        int bottom = this.getBottom() + etParams.topMargin + this.getHeight() - this.getPaddingBottom() ;
        app.strokeInProgress = new TextStrokeBuilder(app, left, bottom);
    }
    // make the keyboard go away
    imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
    // tell app to delete the EditText
    textListener.onTextCompleted();
}
}

1 个答案:

答案 0 :(得分:1)

所以我发现(或多或少)一个解决方案。我们摆脱了MoveableEditText的MarginLayoutParameters,它们非常烦人,而是为leftMargin和topMargin提供了字段,我们用100和100初始化了它。

将编辑文本添加的代码更改为:

private void addEditText() {
    MovableEditText et = new MovableEditText(app);
    et.setMinimumWidth(60);
    et.setTextSize(app.getTextSize());
    et.setTextColor(app.getLineColor());
    et.setBackgroundColor(Color.parseColor("#77CCCCCC")); // some kind of light transparent gray
    et.setText(app.getText());
    et.setTag("TEXTENTRY");
    et.setTextCompletedListener(new TextCompletedListener() {
        @Override
        public void onTextCompleted() {
            removeEditText();
            drawView.invalidate();
        }
    });
    app.editText = et;

    DrawView dv = (DrawView) findViewById(R.id.drawview);
    dv.addView(et);
    et.requestFocus();
    InputMethodManager imm = (InputMethodManager) app.getSystemService(Context.INPUT_METHOD_SERVICE);
    if (imm != null) {
        imm.showSoftInput(et, 0);
    }
}

将MoveableEditText中框移动的代码更改为:

private void moveBox(MovableEditText et, MotionEvent event) {
    leftMargin += (int) (event.getX() - (et.getWidth()/2));
    topMargin += (int) (event.getY() - this.getHeight());
    requestLayout();
}

onLayout和onMeasure在此之后变得非常简单。

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    for (int i = 0; i < getChildCount(); i++) {
        final MovableEditText child = (MovableEditText) getChildAt(i);
        int left = l + child.leftMargin;
        int top = t + child.topMargin;
        child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
    int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
    setMeasuredDimension(width, height);

    for (int i = 0; i < getChildCount(); i++) {
        getChildAt(i).measure(width, height);
    }
}