refactor(TextDrawable.java): add back TextDrawable.java

This commit is contained in:
LucasGGamerM
2025-04-13 12:59:14 -03:00
parent 2df7aade48
commit 43ff783014

View File

@@ -0,0 +1,242 @@
package org.joinmastodon.android.ui.utils;
/*
* Copyright 2016 Ali Muzaffar
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.TextView;
import java.lang.ref.WeakReference;
public class TextDrawable extends Drawable implements TextWatcher {
private WeakReference<TextView> ref;
private String mText;
private Paint mPaint;
private Rect mHeightBounds;
private boolean mBindToViewPaint = false;
private float mPrevTextSize = 0;
private boolean mInitFitText = false;
private boolean mFitTextEnabled = false;
/**
* Create a TextDrawable using the given paint object and string
*
* @param paint
* @param s
*/
public TextDrawable(Paint paint, String s) {
mText = s;
mPaint = new Paint(paint);
mHeightBounds = new Rect();
init();
}
/**
* Create a TextDrawable. This uses the given TextView to initialize paint and has initial text
* that will be drawn. Initial text can also be useful for reserving space that may otherwise
* not be available when setting compound drawables.
*
* @param tv The TextView / EditText using to initialize this drawable
* @param initialText Optional initial text to display
* @param bindToViewsText Should this drawable mirror the text in the TextView
* @param bindToViewsPaint Should this drawable mirror changes to Paint in the TextView, like textColor, typeface, alpha etc.
* Note, this will override any changes made using setColorFilter or setAlpha.
*/
public TextDrawable(TextView tv, String initialText, boolean bindToViewsText, boolean bindToViewsPaint) {
this(tv.getPaint(), initialText);
ref = new WeakReference<>(tv);
if (bindToViewsText || bindToViewsPaint) {
if (bindToViewsText) {
tv.addTextChangedListener(this);
}
mBindToViewPaint = bindToViewsPaint;
}
}
/**
* Create a TextDrawable. This uses the given TextView to initialize paint and the text that
* will be drawn.
*
* @param tv The TextView / EditText using to initialize this drawable
* @param bindToViewsText Should this drawable mirror the text in the TextView
* @param bindToViewsPaint Should this drawable mirror changes to Paint in the TextView, like textColor, typeface, alpha etc.
* Note, this will override any changes made using setColorFilter or setAlpha.
*/
public TextDrawable(TextView tv, boolean bindToViewsText, boolean bindToViewsPaint) {
this(tv, tv.getText().toString(), bindToViewsText, bindToViewsPaint);
}
/**
* Use the provided TextView/EditText to initialize the drawable.
* The Drawable will copy the Text and the Paint properties, however it will from that
* point on be independant of the TextView.
*
* @param tv a TextView or EditText or any of their children.
*/
public TextDrawable(TextView tv) {
this(tv, false, false);
}
/**
* Use the provided TextView/EditText to initialize the drawable.
* The Drawable will copy the Paint properties, and use the provided text to initialise itself.
*
* @param tv a TextView or EditText or any of their children.
* @param s The String to draw
*/
public TextDrawable(TextView tv, String s) {
this(tv, s, false, false);
}
@Override
public void draw(Canvas canvas) {
if (mBindToViewPaint && ref.get() != null) {
Paint p = ref.get().getPaint();
canvas.drawText(mText, 0, getBounds().height(), p);
} else {
if (mInitFitText) {
fitTextAndInit();
}
canvas.drawText(mText, 0, getBounds().height(), mPaint);
}
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
int alpha = mPaint.getAlpha();
if (alpha == 0) {
return PixelFormat.TRANSPARENT;
} else if (alpha == 255) {
return PixelFormat.OPAQUE;
} else {
return PixelFormat.TRANSLUCENT;
}
}
private void init() {
Rect bounds = getBounds();
//We want to use some character to determine the max height of the text.
//Otherwise if we draw something like "..." they will appear centered
//Here I'm just going to use the entire alphabet to determine max height.
mPaint.getTextBounds("1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 0, 1, mHeightBounds);
//This doesn't account for leading or training white spaces.
//mPaint.getTextBounds(mText, 0, mText.length(), bounds);
float width = mPaint.measureText(mText);
bounds.top = mHeightBounds.top;
bounds.bottom = mHeightBounds.bottom;
bounds.right = (int) width;
bounds.left = 0;
setBounds(bounds);
}
public void setPaint(Paint paint) {
mPaint = new Paint(paint);
//Since this can change the font used, we need to recalculate bounds.
if (mFitTextEnabled && !mInitFitText) {
fitTextAndInit();
} else {
init();
}
invalidateSelf();
}
public Paint getPaint() {
return mPaint;
}
public void setText(String text) {
mText = text;
//Since this can change the bounds of the text, we need to recalculate.
if (mFitTextEnabled && !mInitFitText) {
fitTextAndInit();
} else {
init();
}
invalidateSelf();
}
public String getText() {
return mText;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
setText(s.toString());
}
/**
* Make the TextDrawable match the width of the View it's associated with.
* <p/>
* Note: While this option will not work if bindToViewPaint is true.
*
* @param fitText
*/
public void setFillText(boolean fitText) {
mFitTextEnabled = fitText;
if (fitText) {
mPrevTextSize = mPaint.getTextSize();
if (ref.get() != null) {
if (ref.get().getWidth() > 0) {
fitTextAndInit();
} else {
mInitFitText = true;
}
}
} else {
if (mPrevTextSize > 0) {
mPaint.setTextSize(mPrevTextSize);
}
init();
}
}
private void fitTextAndInit() {
float fitWidth = ref.get().getWidth();
float textWidth = mPaint.measureText(mText);
float multi = fitWidth / textWidth;
mPaint.setTextSize(mPaint.getTextSize() * multi);
mInitFitText = false;
init();
}
}