Tuesday, July 17, 2018

Chapter 4: TextView



Everything related to TextView customization in Android SDK

Section 4.1: Spannable TextView

A spannable TextView can be used in Android to highlight a particular portion of text with a different color, style, size, and/or click event in a single TextView widget.

Consider that you have defined a TextView as follows:
[code hl="1, 4, 7"] TextView textview=findViewById(R.id.textview); [/code]

Then you can apply different highlighting to it as shown below:

Spannable color: In order to set a different color to some portion of text, a ForegroundColorSpan can be used, as shown in the following example:
[code hl="1, 4, 7"] Spannable spannable = new SpannableString(firstWord+lastWord); spannable.setSpan(new ForegroundColorSpan(firstWordColor), 0, firstWord.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spannable.setSpan(new ForegroundColorSpan(lastWordColor), firstWord.length(), firstWord.length()+lastWord.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); textview.setText( spannable ); [/code]

Output created by the code above:







Spannable font: In order to set a different font size to some portion of text, a RelativeSizeSpan can be
used, as shown in the following example:
[code hl="1, 4, 7"] Spannable spannable = new SpannableString(firstWord+lastWord); spannable.setSpan(new RelativeSizeSpan(1.1f),0, firstWord.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // set size spannable.setSpan(new RelativeSizeSpan(0.8f), firstWord.length(), firstWord.length() + lastWord.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // set size textview.setText( spannable ); [/code]

Output created by the code above:







Spannable typeface: In order to set a different font typeface to some portion of text, a custom TypefaceSpan can be used, as shown in the following example:
[code hl="1, 4, 7"] Spannable spannable = new SpannableString(firstWord+lastWord); spannable.setSpan( new CustomTypefaceSpan("SFUIText-Bold.otf",fontBold), 0, firstWord.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spannable.setSpan( new CustomTypefaceSpan("SFUIText-Regular.otf",fontRegular), firstWord.length(), firstWord.length() + lastWord.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); text.setText( spannable ); [/code]


However, in order to make the above code working, the class CustomTypefaceSpan has to be derived from the class TypefaceSpan. This can be done as follows:
[code hl="1, 4, 7"] family); newType = type; } @Override public void updateDrawState(TextPaint ds) { applyCustomTypeFace(ds, newType); } @Override public void updateMeasureState(TextPaint paint) { applyCustomTypeFace(paint, newType); } private static void applyCustomTypeFace(Paint paint, Typeface tf) { int oldStyle; Typeface old = paint.getTypeface(); if (old == null) { oldStyle = 0; } else { oldStyle = old.getStyle(); } int fake = oldStyle & ~tf.getStyle(); if ((fake & Typeface.BOLD) != 0) { paint.setFakeBoldText(true); } if ((fake & Typeface.ITALIC) != 0) { paint.setTextSkewX(-0.25f); } paint.setTypeface(tf); } } [/code]


Section 4.2: Strikethrough TextView

Strikethrough the entire text
[code hl="1, 4, 7"] String sampleText = "This is a test strike"; textView.setPaintFlags(tv.getPaintFlags()| Paint.STRIKE_THRU_TEXT_FLAG); textView.setText(sampleText); [/code]


Strikethrough only parts of the text
[code hl="1, 4, 7"] String sampleText = "This is a test strike"; SpannableStringBuilder spanBuilder = new SpannableStringBuilder(sampleText); StrikethroughSpan strikethroughSpan = new StrikethroughSpan(); spanBuilder.setSpan( strikethroughSpan, // Span to add 0, // Start 4, // End of the span (exclusive) Spanned.SPAN_EXCLUSIVE_EXCLUSIVE // Text changes will not reflect in the strike changing ); textView.setText(spanBuilder); [/code]


Section 4.3: TextView with image

Android allows programmers to place images at all four corners of a TextView. For example, if you are creating a field with a TextView and at same time you want to show that the field is editable, then developers will usually place an edit icon near that field. Android provides us an interesting option called compound drawable for a TextView:
[code hl="1, 4, 7"] [/code]


You can set the drawable to any side of your TextView as follows:
[code hl="1, 4, 7"] android:drawableLeft="@drawable/edit" android:drawableRight="@drawable/edit" android:drawableTop="@drawable/edit" android:drawableBottom="@drawable/edit" [/code]


Setting the drawable can also be achieved programmatically in the following way:
[code hl="1, 4, 7"] yourTextView.setCompoundDrawables(leftDrawable, rightDrawable, topDrawable, bottomDrawable); [/code]


Setting any of the parameters handed over to setCompoundDrawables() to null will remove the icon from the corresponding side of the TextView.


Section 4.4: Make RelativeSizeSpan align to top

In order to make a RelativeSizeSpan align to the top, a custom class can be derived from the class
SuperscriptSpan. In the following example, the derived class is named TopAlignSuperscriptSpan:

activity_main.xml:
[code hl="1, 4, 7"] [/code]

MainActivity.java:
[code hl="1, 4, 7"] TextView txtView = (TextView) findViewById(R.id.txtView); SpannableString spannableString = new SpannableString("RM123.456"); spannableString.setSpan( new TopAlignSuperscriptSpan( (float)0.35 ), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE ); txtView.setText(spannableString); [/code]

TopAlignSuperscriptSpan.java:
[code hl="1, 4, 7"] private class TopAlignSuperscriptSpan extends SuperscriptSpan { //divide superscript by this number protected int fontScale = 2; //shift value, 0 to 1.0 protected float shiftPercentage = 0; //doesn't shift TopAlignSuperscriptSpan() {} //sets the shift percentage TopAlignSuperscriptSpan( float shiftPercentage ) { if( shiftPercentage > 0.0 && shiftPercentage < 1.0 ) this.shiftPercentage = shiftPercentage; } @Override public void updateDrawState( TextPaint tp ) { //original ascent float ascent = tp.ascent(); //scale down the font tp.setTextSize( tp.getTextSize() / fontScale ); //get the new font ascent float newAscent = tp.getFontMetrics().ascent; //move baseline to top of old font, then move down size of new font //adjust for errors with shift percentage tp.baselineShift += ( ascent - ascent * shiftPercentage ) - (newAscent - newAscent * shiftPercentage ); } @Override public void updateMeasureState( TextPaint tp ) { updateDrawState( tp ); } } [/code]

Reference screenshot:



















Section 4.5: Pinchzoom on TextView

activity_main.xml:
[code hl="1, 4, 7"] [/code]

MainActivity.java:
[code hl="1, 4, 7"] import android.app.Activity; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.TextView; public class MyTextViewPinchZoomClass extends Activity implements OnTouchListener { final static float STEP = 200; TextView mytv; float mRatio = 1.0f; int mBaseDist; float mBaseRatio; float fontsize = 13; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mytv = (TextView) findViewById(R.id.mytv); mytv.setTextSize(mRatio + 13); } public boolean onTouchEvent(MotionEvent event) { if (event.getPointerCount() == 2) { int action = event.getAction(); int pureaction = action & MotionEvent.ACTION_MASK; if (pureaction == MotionEvent.ACTION_POINTER_DOWN) { mBaseDist = getDistance(event); mBaseRatio = mRatio; } else { float delta = (getDistance(event) - mBaseDist) / STEP; float multi = (float) Math.pow(2, delta); mRatio = Math.min(1024.0f, Math.max(0.1f, mBaseRatio * multi)); mytv.setTextSize(mRatio + 13); } } return true; } int getDistance(MotionEvent event) { int dx = (int) (event.getX(0) - event.getX(1)); int dy = (int) (event.getY(0) - event.getY(1)); return (int) (Math.sqrt(dx * dx + dy * dy)); } public boolean onTouch(View v, MotionEvent event) { return false; } } [/code]



Section 4.6: Textview with different Textsize

You can archive different Textsizes inside a Textview with a Span
[code hl="1, 4, 7"] TextView textView = (TextView) findViewById(R.id.textView); Spannable span = new SpannableString(textView.getText()); span.setSpan(new RelativeSizeSpan(0.8f), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(span) [/code]