Reputation: 21
I have a calculator app and would like to create a button with white normal sized text for click functionality, and smaller, grayed out, super-scripted text for the secondary hold functionally. Ideally this button would look very similarly to Android's default keyboard's top row keys, where the numbers are the secondary functionality to the qwerty keys.
Would I need to use a custom image button or a textview hacked into a button, or is there a cleaner way to do this?
Thanks.
Upvotes: 1
Views: 292
Reputation: 21
I ended up doing this by writing my own custom class that draw both the main text and the secondary text. The class also has some code in there that automatically scales the font size down if it doesn't fit in the button.
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.Button;
import com.llamacorp.equate.R;
class SecondaryTextButton extends Button {
protected static final int SECONDARY_FONT_PERCENTAGE = 70;
protected float mTextX;
protected float mTextY;
protected float mTextSize = 0f;
protected Paint mSecondaryPaint;
protected String mSecondaryText;
protected int mSecondaryTextColor;
protected float mSecondaryTextSize;
//the following are used to determine where to place the secondary text
protected float mButtonHeight;
protected float mButtonWidth;
protected float mSecTextWidth;
protected float mSecAdditionalXOffset;
protected float mSecTextHeight;
protected float mSecAdditionalYOffset;
//x and y coordinates for the secondary text
protected float mSecXCoord;
protected float mSecYCoord;
public SecondaryTextButton(Context context, AttributeSet attrs) {
super(context, attrs);
int secTextPerc = SECONDARY_FONT_PERCENTAGE;
//grab custom resource variable
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SecondaryTextButton, 0, 0);
try {
mSecondaryText = ta.getString(R.styleable.SecondaryTextButton_secondary_text);
secTextPerc = ta.getInteger(R.styleable.SecondaryTextButton_secondary_text_font_size_percentage,
SECONDARY_FONT_PERCENTAGE);
mSecondaryTextColor = ta.getColor(R.styleable.SecondaryTextButton_secondary_text_color,
getResources().getColor(R.color.button_secondary_text));
} finally { ta.recycle();}
mSecondaryTextSize = getPaint().getTextSize() * secTextPerc / 100f;
mSecondaryPaint = new Paint(getPaint());
}
/** Set secondary text string */
public void setSecondaryText(String text){
mSecondaryText = text;
}
@Override
protected void onTextChanged(CharSequence text, int start, int before, int after) {
super.onTextChanged(text, start, before, after);
layoutText();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) layoutText();
}
/** Helper method to size text */
protected void layoutText() {
Paint paint = getPaint();
if (mTextSize != 0f) paint.setTextSize(mTextSize);
float textWidth = paint.measureText(getText().toString());
float boxWidth = getWidth() - getPaddingLeft() - getPaddingRight();
float textSize = getTextSize();
if (textWidth > boxWidth) {
paint.setTextSize(textSize * boxWidth / textWidth);
mTextX = getPaddingLeft();
mTextSize = textSize;
} else {
mTextX = (getWidth() - textWidth) / 2;
}
mTextY = (getHeight() - paint.ascent() - paint.descent()) / 2;
if (mSecondaryPaint != null)
mSecondaryPaint.setTextSize(mSecondaryTextSize);
}
@Override
protected void onDraw(Canvas canvas) {
if(mSecondaryText != null){
//draw the text in the upper corner
mSecondaryPaint.setColor(mSecondaryTextColor);
mButtonHeight = getHeight(); // - getPaddingTop() - getPaddingBottom();
mButtonWidth = getWidth(); // - getPaddingLeft() - getPaddingRight();
mSecTextWidth = mSecondaryPaint.measureText(mSecondaryText);
mSecAdditionalXOffset = getContext().getResources()
.getDimensionPixelSize(R.dimen.button_ellipses_additional_offset_x);
mSecTextHeight = mSecondaryPaint.getTextSize();
mSecAdditionalYOffset = getContext().getResources()
.getDimensionPixelSize(R.dimen.button_ellipses_additional_offset_y);
findSecondaryTextCoord();
canvas.drawText(mSecondaryText, 0, mSecondaryText.length(),
mSecXCoord, mSecYCoord, mSecondaryPaint);
}
drawMainText(canvas);
}
/**
* Helper function to draw secondary text
*/
protected void drawMainText(Canvas canvas){
getPaint().setColor(getCurrentTextColor());
canvas.drawText(getPrimaryText(), 0, getPrimaryText().length(), mTextX, mTextY,
getPaint());
}
protected String getPrimaryText(){
if(getText().toString()==null)
return "";
return getText().toString();
}
/** Calculate where to put secondary text
* This method should get overriden to change text location */
protected void findSecondaryTextCoord(){
mSecXCoord = mButtonWidth - mSecTextWidth - mSecAdditionalXOffset;
mSecYCoord = mButtonHeight - 0 - mSecAdditionalYOffset;
}
}
You'll also need to add some attributes to your attrs.xml file, so it'll look something like this:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SecondaryTextButton">
<attr name="secondary_text" format="string" />
<attr name="secondary_text_color" format="color" />
<attr name="secondary_text_font_size_percentage" format="integer" />
</declare-styleable>
<declare-styleable name="AnimatedHoldButton">
<attr name="primary_text" format="string" />
<attr name="pressed_color" format="color" />
</declare-styleable>
<declare-styleable name="EditTextCursorWatcher">
<attr name="minimumTextSize" format="dimension" />
</declare-styleable>
</resources>
Here's the usage of the custom button in XML (note you'll have to replace llamacorp.equate.view with your package name)
<com.llamacorp.equate.view.AnimatedHoldButton
xmlns:customNS="http://schemas.android.com/apk/res/com.llamacorp.equate"
customNS:primary_text="@string/divide_button"
customNS:secondary_text="@string/invert_button"
customNS:secondary_text_font_size_percentage="50" />
Here's an example of the code in an app I wrote: https://github.com/evanre/equate
Upvotes: 0
Reputation: 5671
You can try to use TextView
with SpannableString
set to it. Here's an example of usage:
SpannableString spannedSlogan = new SpannableString(slogan);
spannedSlogan.setSpan(new CustomTypefaceSpan(mLightTypeface), 0,
slogan.length(), S pannable.SPAN_INCLUSIVE_EXCLUSIVE);
spannedSlogan.setSpan(new ForegroundColorSpan(getResources()
.getColor(android.R.color.black)), 0, slogan.length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
spannedSlogan.setSpan(new ForegroundColorSpan(getResources()
.getColor(R.color.green)), slogan.length() - 1, slogan
.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
spannedSlogan.setSpan(new CustomTypefaceSpan(mExtraBoldTypeface),
slogan.length() - 1, slogan.length(),
Spannable.SPAN_INCLUSIVE_INCLUSIVE);
mSloganView.setText(spannedSlogan);
"slogan" is a string with dot in the end. This code applies custom Typeface
to whole string, black color to everything except dot in the end, green color to the dot and bold style to the dot also. You can similarly deal with font size using RelativeSizeSpan
The second solution is to use html attributes to set text size. For example from here:
textView.setText(Html.fromHtml("<font size=\"5\" face=\"arial\" color=\"red\">"+
"This paragraph is in Arial, size 5, and in red text color." + "</font>" + ...));
Upvotes: 1