Last active
May 7, 2023 16:24
-
-
Save alphamu/5aa2c0428681b18577d7 to your computer and use it in GitHub Desktop.
An TextDrawable that can be used to draw a String. This can be used anywhere you would normally use a drawable. You can watch the demo video here: https://youtu.be/l1HgpcJhIi0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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(), false, false); | |
} | |
/** | |
* 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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:clipChildren="false" | |
android:clipToPadding="false" | |
android:orientation="vertical" | |
android:padding="@dimen/activity_horizontal_margin"> | |
<EditText | |
android:id="@+id/txt_regular" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginTop="32dp" | |
android:hint="Regular EditText" /> | |
<TextView | |
android:id="@+id/drawable_test" | |
android:layout_width="200dp" | |
android:layout_height="200dp"/> | |
</LinearLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class UsageExampleActivity extends Activity { | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.usage_layout); | |
EditText regular = (EditText) findViewById(R.id.txt_regular); | |
regular.setCompoundDrawables(new TextDrawable(regular, "+61 "), null, new TextDrawable(regular, "\u2605"), null); | |
TextView view = (TextView) findViewById(R.id.drawable_test); | |
final TextDrawable textDrawable = new TextDrawable(view, "\u263A"); | |
textDrawable.setFillText(true); | |
textDrawable.getPaint().setColor(Color.RED); | |
view.setBackgroundDrawable(textDrawable); | |
CountDownTimer c = new CountDownTimer(10000, 1000) { | |
@Override | |
public void onTick(long millisUntilFinished) { | |
textDrawable.setText(textDrawable.getText()+"\u263A"); | |
} | |
@Override | |
public void onFinish() { | |
} | |
}; | |
c.start(); | |
} | |
} |
deppendency for com.alimuzaffar.customwidgets.PrefixEditText?
i am getting error like :Error inflating class com.alimuzaffar.customwidgets.PrefixEditText
Can you help me to draw your drawable in circular shape? So that my text would show in circular shape. Please help me on this.
before setCompoundDrawables is invoked, you can change the color , code like this below:
phoneNumberPrefixDrawable.getPaint().setTextSize(30));
phoneNumberPrefixDrawable.getPaint().setColor(Color.Red);
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nicely done!
How do you change the color of the text in the text drawable?
For eg . changing "+61 " from black to red.