“This is the 14th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Android draggable text

At present, there are many picture editing apps on the market. Whether it is screenshots or professional picture processing apps, many of them have the function of adding labels and stickers. The author has also met the needs of editing pictures for several times, but they are not professional picture processing software, so it takes time and can always be polished. This article will show you how to achieve the draggable effect of text, limit its boundaries, and extend its functionality.

demand

  • Add text that can be customized

  • Words can be deleted and replaced

  • Text needs to limit boundaries

  • Text can be set to size

  • Text alignment must be configurable

  • Text does not need to be rotated (not a professional image processing app)

Simple implementation

Take a look at the renderings first

In fact all the effects of the code logic is very clear, only custom View. So let’s see how that works.

1. BaseStickerView class

Defining the BaseStickerView class and inheriting ViewGroup requires the creation of a constructor by default


public BaseStickerView(Context context) {

super(context);

onInitialize(context);

}

Copy the code

This class declares properties such as sticker content, actionable buttons, help classes, and scaling

/* private View mContentView; /* Private ImageView mRemoveView, mEditView; /* help class */ private StickerMoveHelper mMoveHelper; Private float mScale = 1f;Copy the code

Initialize the view in the constructor. In initialization, we set background transparency, add sticker content, initialize actionable buttons, and add actionable buttons to the view. In this method, we also initialize the help class, where the main drag is done, to make the code structure a little clearer.

Public void onInitialize(Context Context) {// setBackgroundColor(color.transparent); // Create the abstract view of the sticker and add mContentView = onCreateContentView(context); if (mContentView == null) return; addView(mContentView, getContentLayoutParams()); MRemoveView = new ImageView(context); mRemoveView.setScaleType(ImageView.ScaleType.FIT_XY); mRemoveView.setImageResource(R.drawable.sticker_ic_delete); mEditView = new ImageView(context); mEditView.setScaleType(ImageView.ScaleType.FIT_XY); mEditView.setImageResource(R.drawable.sticker_ic_edit); mRemoveView.setOnClickListener(this); mEditView.setOnClickListener(this); // Add component View to view addView(mRemoveView, getAnchorLayoutParams()); addView(mEditView, getAnchorLayoutParams()); // Initialize the helper class mMoveHelper = new StickerMoveHelper(this); }Copy the code

In the OnTouch callback method, we pass the event to the helper class and let the helper class do the sliding for us.


@Override

public boolean onTouchEvent(MotionEvent event) {

boolean handled = mMoveHelper.onTouch(this, event, ((ViewGroup) getParent()).getWidth(), ((ViewGroup) getParent()).getHeight(), getWidth(), getHeight(), mScale, true);

return handled | super.onTouchEvent(event);

}

Copy the code

2. StickerMoveHelper helper class

In the move class, bounds are restricted, which is the width and height of the parent container. We need to judge the top left, bottom right, and bottom left boundaries, and the logic is very simple: after the parent container is exceeded, let the view stand still and not change the x and y values.

public class StickerMoveHelper { private static final String TAG = "StickerMoveHelper"; private final View mView; private float mX, mY; private static final Matrix M = new Matrix(); public StickerMoveHelper(View view) { mView = view; } //isOverflow: Public Boolean onTouch(View v, MotionEvent Event, float parentWidth, float parentHeight, float width, float height, float scale, boolean isLimitBorder) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: mX = event.getX(); mY = event.getY(); M.reset(); M.setRotate(v.getRotation()); return true; case MotionEvent.ACTION_MOVE: float[] dxy = {event.getX() - mX, event.getY() - mY}; M.mapPoints(dxy); float x = mView.getTranslationX() + dxy[0]; float y = mView.getTranslationY() + dxy[1]; // Limit the margin (considering the width and height of the button, remove the TEXT_PADDING, If (isLimitBorder) {if (x < (-stickerconfig.text_padding)) x = (-stickerconfig.text_padding); if (x > (parentWidth - width + StickerConfig.TEXT_PADDING)) x = (parentWidth - width + StickerConfig.TEXT_PADDING); if (y < (-StickerConfig.TEXT_PADDING)) y = -StickerConfig.TEXT_PADDING; if (y > (parentHeight - height + StickerConfig.TEXT_PADDING)) y = (parentHeight - height + StickerConfig.TEXT_PADDING); } v.setTranslationX(x); v.setTranslationY(y); return true; } return false; }}Copy the code

3. StickerView

And since most of the logic is in the BaseStickerView, StickerView is all about creating views, you can create text or you can expand images.

public class StickerView extends BaseStickerView { private static final String TAG = "StickerView"; private TextView mTextView; public StickerView(Context context) { super(context); } @Override public View onCreateContentView(Context context) { mTextView = new TextView(context); mTextView.setPadding(StickerConfig.TEXT_PADDING, StickerConfig.TEXT_PADDING, StickerConfig.TEXT_PADDING, StickerConfig.TEXT_PADDING); mTextView.setSingleLine(); mTextView.setTextColor(Color.BLACK); mTextView.setTextSize(50); return mTextView; } public void setText(String text) { mTextView.setText(text); }}Copy the code

Use 4.

The main logic is in custom classes, and it’s easy to use.

StickerView stickerView = new StickerView(this); Stickerview.settext (" ha ha ha "); container.addView(stickerView);Copy the code