RelativeSizeTextView for Custom Controls

Posted by jennatar on Sun, 07 Jul 2019 03:31:58 +0200

Preface

Firstly, the blogger of this control really does not know what kind of Chinese name to explain, so the title can only carry the name of the control directly. The main function of the control is to display a pre-text and post-text that can configure the size and color. It may be said that they do not understand very well. Okay, first look at the effect map.

From the effect map, we can see that the middle is a normal text, and the two sides can display different sizes and colors of text. What's the use? I wonder if you have ever seen such an effect.

It's perfectly possible to use Spannable String on your own and then work with Relative SizeSpan, but if you need to use it in many parts of a project, it's not a good idea to copy and paste code.
So bloggers extract this to display a pre-text and post-text that can be configured with size and color.

Let's look at a way to use it first.

<com.move.widget.RelativeSizeTextView
            android:id="@+id/tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:text="I am the normal text 20 sp"
            android:textSize="20sp"
            app:endText="I'm 150 with the normal size of the blue postscript%"
            app:end_proportion="1.5"
            app:end_text_color="#0000FF"
            app:start_proportion="0.8"
            app:startText="I'm 80 with normal size pre-Red text.%"
            app:start_text_color="#FF0000" />

The usage is very clear, that is to configure the color and size percentages of the pre-text and post-text.

Here's how to implement this custom control

Code

In fact, the only thing we can think of is expanding functionality by inheriting TextView.

Define the properties of the control

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RelativeSizeTextView">

        <! - Text at the beginning and at the end - >
        <attr name="startText" format="string" />
        <attr name="endText" format="string" />
        <! - Unify the ratio of tag s at the beginning and at the end of the settings - >
        <attr name="proportion" format="float" />
        <! - Proportion of text at the beginning - >
        <attr name="start_proportion" format="float" />
        <! - Proportion of closing texts - >
        <attr name="end_proportion" format="float" />
        <! - The color of the beginning text and the ending text - >
        <attr name="start_end_text_color" format="color" />
        <attr name="start_text_color" format="color" />
        <attr name="end_text_color" format="color" />

    </declare-styleable>
</resources>

There must be corresponding attributes in our code, and they are read when the control is initialized.

    /**
     * Beginning Text
     */
    private String startText;

    /**
     * The color of the start text
     */
    private int startTextColor = 0;

    /**
     * Closing text
     */
    private String endText;

    /**
     * The color of the end text
     */
    private int endTextColor = 0;

    /**
     * Initial proportions
     */
    private float startProportion;

    /**
     * Proportion of closing text
     */
    private float endProportion;

Read custom properties

public class RelativeSizeTextView extends AppCompatTextView {

    public RelativeSizeTextView(Context context) {
        this(context, null);
    }

    public RelativeSizeTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RelativeSizeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        // Start reading custom properties
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RelativeSizeTextView);

        startText = a.getString(R.styleable.RelativeSizeTextView_startText);
        endText = a.getString(R.styleable.RelativeSizeTextView_endText);

        startProportion = a.getFloat(R.styleable.RelativeSizeTextView_proportion, 1f);
        endProportion = a.getFloat(R.styleable.RelativeSizeTextView_proportion, 1f);

        startProportion = a.getFloat(R.styleable.RelativeSizeTextView_start_proportion, startProportion);
        endProportion = a.getFloat(R.styleable.RelativeSizeTextView_end_proportion, endProportion);

        startTextColor = a.getColor(R.styleable.RelativeSizeTextView_start_end_text_color, startTextColor);
        endTextColor = a.getColor(R.styleable.RelativeSizeTextView_start_end_text_color, endTextColor);

        startTextColor = a.getColor(R.styleable.RelativeSizeTextView_start_text_color, startTextColor);
        endTextColor = a.getColor(R.styleable.RelativeSizeTextView_end_text_color, endTextColor);

        a.recycle();

        setTagText(getText());

    }

    /**
     * Beginning Text
     */
    private String startText;

    /**
     * The color of the start text
     */
    private int startTextColor = 0;

    /**
     * Closing text
     */
    private String endText;

    /**
     * The color of the end text
     */
    private int endTextColor = 0;

    /**
     * Initial proportions
     */
    private float startProportion;

    /**
     * Proportion of closing text
     */
    private float endProportion;
}

The last way to show results based on these attribute values

As mentioned above, if you want to use Spannable String and then work with Relative SizeSpan to achieve results, then that's how it works internally. Spannable String does not use self-searching.

    /**
     * Set the text and do not call the {@link android.widget.TextView#setText(CharSequence)} method when calling
     * Instead, call this method, or it will not work.
     * For example, setTagText("hello") has the effect of adding pre-text and post-text: <pre-text > Hello < post-text >
     *
     * @param text
     */
    public void setTagText(CharSequence text) {

        if (!TextUtils.isEmpty(startText)) {
            text = startText + text;
        }

        if (!TextUtils.isEmpty(endText)) {
            text = text + endText;
        }

        SpannableString ss = new SpannableString(text);
        RelativeSizeSpan startSpan = new RelativeSizeSpan(startProportion);
        RelativeSizeSpan endSpan = new RelativeSizeSpan(endProportion);

        if (!TextUtils.isEmpty(startText)) {
            ss.setSpan(startSpan, 0, startText.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
            if (startTextColor != 0) {
                ForegroundColorSpan fcs = new ForegroundColorSpan(startTextColor);
                ss.setSpan(fcs, 0, startText.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
            }
        }

        if (!TextUtils.isEmpty(endText)) {
            ss.setSpan(endSpan, text.length() - endText.length(), text.length(),
                    Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
            if (endTextColor != 0) {
                ForegroundColorSpan fcs = new ForegroundColorSpan(endTextColor);
                ss.setSpan(fcs, text.length() - endText.length(), text.length(),
                        Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
            }
        }

        super.setText(ss);
    }

It's important that we call the setTagText method once we read the custom properties.
Because the text shows the original text without our prefix and suffix, we will get the current text after reading the custom attribute and then call the setTagText method so that the user can display the effect by default without calling the setTagText method.

Source Download

https://github.com/xiaojinzi123/widget/blob/master/widget/src/main/java/com/move/widget/RelativeSizeTextView.java

Topics: Android Attribute Java xml