The sticky bit was adding text. I'd originally set up the button to open an alert dialog where you could enter your text, and select a font size via a slider. That was visually jarring and functionally awkward because you couldn't really tell how large to make your text in relation to the drawing. You would only know after placing it, so you'd have to undo and try again if you found it the wrong size.
So I found a bit of code that would include an actionable graphic (an image of an X to clear the text) in an EditText. From that starting point I made the EditText so it would be placed directly on the drawing surface, and it could be resized by dragging at the corner graphic. Clicking the checkmark graphic at the top cements the text in place. It's much smoother than having a dialog box.
After that, some code to save the drawing in JSON so it can be retrieved later.
For the next trick I want to put advertising in it. I'd like have a free-with-ads version, and a paid no-ads version. Don't hurt me, please. I'm not crazy about doing it either.
So to distract you from that last paragraph, here's the code for an edittext that can be moved around and the font resized by dragging. Both the drawing and the EditText are children of a Viewgroup.
public class MovableEditText extends EditText {
// 2 drawables: an OK 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;
public InputMethodManager imm;
private App app;
private boolean resizing;
private TextCompletedListener textListener;
private boolean finished = false;
private float startDeltaLeft;
private float startDeltaTop;
float leftMargin = 100;
float topMargin = 100;
public MovableEditText(Context context) {
super(context);
app = (App) context.getApplicationContext();
imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
init();
}
@Override
public void scrollTo(int x, int y) {
super.scrollTo(0, 0);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
timeFingerDown = event.getEventTime();
// Remembers where you grabbed the text
startDeltaLeft = event.getX();
startDeltaTop = event.getY();
setCursorVisible(true);
return true;
case MotionEvent.ACTION_UP:
resizing = false;
// clicking on the OK checkbox
if (event.getY() < getPaddingTop() + closeImg.getIntrinsicHeight()) {
MovableEditText.this.okButtonClick();
}
// otherwise, act like a proper edittext
if (event.getEventTime() - timeFingerDown < 200 && !finished) {
super.onTouchEvent(event);
}
return false;
case MotionEvent.ACTION_MOVE:
if (event.getX() > getWidth() - getPaddingRight() - resizeImg.getIntrinsicWidth()) {
resizeBox(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; close the keyboard
imm.hideSoftInputFromWindow(getWindowToken(), 0);
moveBox(event);
}
return true;
case MotionEvent.ACTION_CANCEL:
resizing = false;
return false;
}
return true;
}
public void setTextCompletedListener(TextCompletedListener l) {
textListener = l;
}
private void init() {
setMinimumHeight(closeImg.getIntrinsicHeight()*2);
setMinimumWidth(closeImg.getIntrinsicWidth()+resizeImg.getIntrinsicWidth() *2);
// 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();
//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(MotionEvent event) {
leftMargin += (int) (event.getX() - startDeltaLeft);
topMargin += (int) (event.getY() - startDeltaTop);
requestLayout();
}
// the following is to be used by drawview when resizing and panning
public void externalMove(float dragX, float dragY) {
leftMargin = (int) (leftMargin + dragX);
topMargin = (int) (topMargin + dragY);
requestLayout();
}
private void resizeBox(MotionEvent event) {
setWidth((int) event.getX());
setHeight((int) event.getY());
resizeText();
}
// change the text size to whatever will fit in the box
private void resizeText() {
String[] multiline = this.getText().toString().split("\n");
float adjustedHeight = (getMeasuredHeight()/multiline.length - getCompoundPaddingBottom() - getCompoundPaddingTop())/2;
setTextSize(adjustedHeight);
}
// if there is text, add the OK button
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() {
MyViewGroup viewGroup = (MyViewGroup) getParent();
// get the text, get the size, get the position, create a Stroke from it
// locate this view in the viewgroup's coordinate system
// the screen coordinates minus the location of the MET
Float deltaL = getLeft() - getScrollX() - viewGroup.dv.getCenterX();
Float deltaB = getTop() - getScrollY() + getBaseline() - viewGroup.dv.getCenterY() ;
// viewcenterxy are the canvas coordinates
Float dvViewCenterX = viewGroup.dv.getViewCenterX();
Float dvViewCenterY = viewGroup.dv.getViewCenterY();
Float scaleFactor = viewGroup.dv.getScaleFactor();
// translate that delta to the canvas's coordinates
Float translatedL = dvViewCenterX + (deltaL/scaleFactor);
Float translatedB = dvViewCenterY + (deltaB/scaleFactor);
if (this.getText().toString().length()>0) {
app.setText(getText().toString());
app.setTextSize(getTextSize()/2); // i do not know why it keeps doubling the size
app.strokeInProgress = new TextStrokeBuilder(app, translatedL, translatedB, scaleFactor);
app.finishStroke();
}
// tell viewgroup to delete the EditText
textListener.onTextCompleted();
finished = true;
imm.hideSoftInputFromWindow(getWindowToken(),0);
}
public void setLeftMargin(float left) {
leftMargin = left;
}
public void setTopMargin (float top) {
topMargin = top;
}
}
No comments:
Post a Comment