你真的懂Android的TextView嗎?

晴空一堊發表於1970-01-01

TextView

在實際開發過程中,都會遇到一些問題。或多或少自定義控制元件的情況。而我們大多數喜歡用的是系統自帶的控制元件,比方說TextView,ImageView等,這裡講的是就是使用TextView達到一些效果

  1. TextView的圖片大小可控【因為正常的TextView對於圖片的大小需要通過程式碼來控制,這裡實現為xml來設定】
  2. TextView的圖片和文字需要在點選的時候有效果變化【正常的Textview的點選是沒有效果的】

以下為實現的效果圖:

你真的懂Android的TextView嗎?

以下為程式碼:

public class TextImageView extends android.support.v7.widget.AppCompatTextView { 
private int mLeftWidth;
private int mLeftHeight;
private int mTopWidth;
private int mTopHeight;
private int mRightWidth;
private int mRightHeight;
private int mBottomWidth;
private int mBottomHeight;
/** * 是否需要點選效果,預設為透明度變暗50% */ private boolean isNeedClickEffect;
public TextImageView(Context context) {
super(context);

} public TextImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);

} public TextImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);

} public void init(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TextImageView);
mLeftWidth = typedArray.getDimensionPixelOffset(R.styleable.TextImageView_drawableLeftWidth, 0);
mLeftHeight = typedArray.getDimensionPixelOffset(R.styleable.TextImageView_drawableLeftHeight, 0);
mTopWidth = typedArray.getDimensionPixelOffset(R.styleable.TextImageView_drawableTopWidth, 0);
mTopHeight = typedArray.getDimensionPixelOffset(R.styleable.TextImageView_drawableTopHeight, 0);
mRightWidth = typedArray.getDimensionPixelOffset(R.styleable.TextImageView_drawableRightWidth, 0);
mRightHeight = typedArray.getDimensionPixelOffset(R.styleable.TextImageView_drawableRightHeight, 0);
mBottomWidth = typedArray.getDimensionPixelOffset(R.styleable.TextImageView_drawableBottomWidth, 0);
mBottomHeight = typedArray.getDimensionPixelOffset(R.styleable.TextImageView_drawableBottomHeight, 0);
isNeedClickEffect = typedArray.getBoolean(R.styleable.TextImageView_clickEffect, false);
typedArray.recycle();
setDrawablesSize();

} private void setDrawablesSize() {
Drawable[] compoundDrawables = getCompoundDrawables();
for (int i = 0;
i <
compoundDrawables.length;
i++) {
switch (i) {
case 0: setDrawableBounds(compoundDrawables[0], mLeftWidth, mLeftHeight);
break;
case 1: setDrawableBounds(compoundDrawables[1], mTopWidth, mTopHeight);
break;
case 2: setDrawableBounds(compoundDrawables[2], mRightWidth, mRightHeight);
break;
case 3: setDrawableBounds(compoundDrawables[3], mBottomWidth, mBottomHeight);
break;
default: break;

}
} setCompoundDrawables(compoundDrawables[0], compoundDrawables[1], compoundDrawables[2], compoundDrawables[3]);

} private void setDrawableBounds(Drawable drawable, int width, int height) {
if (drawable != null) {
double scale = ((double) drawable.getIntrinsicHeight()) / ((double) drawable.getIntrinsicWidth());
drawable.setBounds(0, 0, width, height);
Rect bounds = drawable.getBounds();
//高寬只給一個值時,自適應 if (bounds.right != 0 || bounds.bottom != 0) {
if (bounds.right == 0) {
bounds.right = (int) (bounds.bottom / scale);
drawable.setBounds(bounds);

} if (bounds.bottom == 0) {
bounds.bottom = (int) (bounds.right * scale);
drawable.setBounds(bounds);

}
}
}
} @Override public boolean onTouchEvent(MotionEvent event) {
boolean intercept = super.onTouchEvent(event);
if (isNeedClickEffect) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: setAlpha(0.5f);
intercept = true;
break;
case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: setAlpha(1f);
break;
default: break;

}
} return intercept;

}
}複製程式碼

如果對於點選有不一樣的效果,可以使用上一篇文章講的this.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
來進行設定與改進

但是這樣就能滿足所有的情況了嗎?

然後在網上看到了這樣的一種效果圖。原文在這裡

你真的懂Android的TextView嗎?

TextView右下角的小圖片在這裡就不能實現,但是bbs中提供的解決方案就非常的不錯,這裡做個備案。

public class MyText extends android.support.v7.widget.AppCompatTextView { 
public MyText(Context context) {
super(context);

} public MyText(Context context, AttributeSet attrs) {
super(context, attrs);

} @Override protected void onDraw(Canvas canvas) {
//得到Drawable集合 分別對應 左上右下 Drawable[] drawables = getCompoundDrawables();
if (drawables != null) {
//獲取右邊圖片 Drawable drawableRight = drawables[2];
if (drawableRight != null) {
//獲取文字佔用長寬 int textWidth = (int) getPaint().measureText(getText().toString());
int textHeight = (int) getPaint().getTextSize();
//獲取圖片實際長寬 int drawableWidth = drawableRight.getIntrinsicWidth();
int drawableHeight = drawableRight.getIntrinsicHeight();
//setBounds修改Drawable在View所佔的位置和大小,對應引數同樣的 左上右下() drawableRight.setBounds(((textWidth - getWidth()) / 2), (textHeight - drawableHeight) / 2, ((textWidth - getWidth()) / 2) + drawableWidth, (textHeight + drawableHeight) / 2);

}
} super.onDraw(canvas);

}
}複製程式碼

以下是在使用TextView的時候發生的一些問題:

  1. 需要滾動
  2. 需要顯示不同的顏色的文字不同的字號
  3. TextView自動換行?
  4. 能不能顯示黑字白邊?
  5. 能不能增加行間距?字太擠了。

下面對這三個問題分別提出解決方案

  1. 基本上採用這個style就可以,如果你不能引用style可以採用將屬性移植到TextView中的方式
   <
style name="TextView_Marquee">
<
item name="android:focusable">
true<
/item>
<
item name="android:ellipsize">
marquee<
/item>
<
item name="android:focusableInTouchMode">
true<
/item>
<
item name="android:marqueeRepeatLimit">
marquee_forever<
/item>
<
item name="android:singleLine">
true<
/item>
<
/style>
複製程式碼

note:

  1. 這裡建議將相同的屬性都提取出來,有助於增加開發效率,也許剛開始提出來的時候會很麻煩但是,寫的多了,你就會發現這樣極大的提升了效率,二來也能對於以後設計或者產品想要對樣式進行修改可以一改就全都修改了,而不用每個地方都去查詢害怕遺漏了。

  2. 如果使用以上的方式在字型超過文字大小的時候還不能滾動,你就需要強制去呼叫tvName.requestFocus();
    這個方法了

  3. 還有可能產生不滾動的原因是因為TextView的位置是動態計算出來的,比方說之前遇到的一個問題:

    <
    LinearLayout android:id="@+id/ll_info" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="horizontal">
    <
    TextView android:id="@+id/tv_title" android:layout_width="0dp" android:textColor="@color/white" android:layout_height="wrap_content" android:layout_weight="1" android:ellipsize="marquee" android:focusable="true" android:singleLine="true" android:textSize="?attr/text_size_h2" />
    <
    TextView android:id="@+id/tv_time" android:layout_width="@dimen/m150" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/m5" android:gravity="right" android:text="0:00/0:00" android:textColor="@color/white" android:textSize="?attr/text_size_h4" />
    <
    /LinearLayout>
    複製程式碼

    如果將tv_time的寬度設定為wrap_content 就會導致不能滾動,因為TextView不能夠計算自己的寬度導致不能滾動

  1. Q:需要顯示不同的顏色的文字不同的字號

    1. 我記得很久以前查了半天為啥用Html.fromHtml() 怎麼實現不同顏色,因為我發現字號是可以的,後來才發現這麼寫,既影響效能,還不能實現效果,為啥網上的部落格都說可以呢,因為Android的裝置不一樣了啊,現在都是4.4+的天下了。

    2. 當然是使用SpannableString 來進行實現,他可以實現非常多的功能,我的使用時比較的簡單

      public static SpannableString getTitleForAudioNameWithArtists(String title, String subTitle) { 
      SpannableString spannableString;
      int songColor = 0;
      int artistColor = 0;
      songColor = Color.WHITE;
      artistColor = Color.parseColor("#7FFFFFFF");
      String name = String.format(Locale.getDefault(), "%s - %s", title, subTitle);
      spannableString = new SpannableString(name);
      spannableString.setSpan(new ForegroundColorSpan(songColor), 0, title.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
      spannableString.setSpan(new ForegroundColorSpan(artistColor) , title.length() + 1, name.length() , Spanned.SPAN_INCLUSIVE_INCLUSIVE);
      return spannableString;

      }複製程式碼

      我記得我當初看到很多Api的更換,我會產生一個疑問,為啥當初好好的api要換掉呢?比方說Html就是一個不錯的選擇,因為本人當初大學的時候學的是javaweb遇到這個東西,理論上來說是有點奇怪的,因為我寧願寫寫html的東西上去,現在還換成了SpannableString 這個難用的東西,因為本來我要寫一行的東西現在要寫好幾行?而很多東西真的越變越複雜,同時也越變越安全。

  2. Q:TextView自動換行?

    每當測試為我:為啥明明一行還有很多空間,為啥後面就顯示“…”了呢?為啥明明還可以顯示幾個字的,為啥就換行了呢?我表示我不知道啊,我只是簡單呼叫TextView的api而已。

    文字對齊,詳看,參考資料的第4條

  3. Q: 能不能顯示黑字白邊?

    參看資料的第二條

  4. Q: 能不能增加行間距?字太擠了。

  5. 參看資料的第一條,android提供的有的屬性letterSpacing lineSpacingExtra lineSpacingMultiplier

參考資料:

  1. 開發中的 TextView 技巧點整理
  2. 文字描邊
  3. TextView emoj的等圖示展示以及其他屬性
  4. 文字自動換行,整齊排版

來源:https://juejin.im/post/5c442ef56fb9a049d1327157

相關文章