1. 程式人生 > >去除Android TextView預設內邊距

去除Android TextView預設內邊距

由於textview在繪製文字時,是按照四格線為基準繪製的,所以會在實際顯示文字的時候,在textview內部顯示出預設的內邊距,該內邊距並不是padding造成的。具體情況請參考:http://blog.csdn.net/harvic880925/article/details/50423762

網上也有不少解決方案例如:

android:includeFontPadding="false";

android:lineSpacingMultiplier="0.9"

等等,都沒達到我想要的預期要求,所以在參考了 http://blog.csdn.net/Ab0510/article/details/52219464之後,

寫了個自定義TextView達到要求。

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MyTextView extends LinearLayout {
    private MyTextViewInner textView;

    public MyTextView(Context context) {
        super(context);
        init(null, 0);
    }

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

    public MyTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, defStyle);
    }

    private void init(AttributeSet attrs, int defStyleAttr) {
        if (attrs != null && defStyleAttr > 0) {
            textView = new MyTextViewInner(getContext(), attrs, defStyleAttr);
        } else if (attrs != null) {
            textView = new MyTextViewInner(getContext(), attrs);
        } else {
            textView = new MyTextViewInner(getContext());
        }
        this.setPadding(0, 0, 0, 0);
        addView(textView);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMeasuredWidth();
        width = width + textView.getPaddingLeft() + textView.getPaddingRight();
        setMeasuredDimension(width, getMeasuredHeight());
    }

    public TextView getTextView() {
        return textView;
    }

    public class MyTextViewInner extends android.support.v7.widget.AppCompatTextView {
        //設定是否remove間距,true為remove
        private boolean noDefaultPadding = true;
        private Paint.FontMetricsInt fontMetricsInt;
        private Rect minRect;

        public MyTextViewInner(Context context) {
            super(context);
        }

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

        public MyTextViewInner(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            if (fontMetricsInt == null) {
                //fontMetricsInt包含的是text文字四條線的 距離,
                //此四條線距離也是以text文字baseline為基準的
                fontMetricsInt = new Paint.FontMetricsInt();
            }
            getPaint().getFontMetricsInt(fontMetricsInt);
            if (minRect == null) {
                //minRect用來獲取文字實際顯示的時候的左上角和右下角  座標
                //該座標是以text文字baseline為基準的
                minRect = new Rect();
            }
            getPaint().getTextBounds(getText().toString(), 0, getText().length(), minRect);
            ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) this.getLayoutParams();
            lp.topMargin = -(fontMetricsInt.bottom - minRect.bottom) + (fontMetricsInt.top - minRect.top);
            lp.rightMargin = -(minRect.left + (getMeasuredWidth() - minRect.right));
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            if (noDefaultPadding) {
                if (fontMetricsInt == null) {
                    //fontMetricsInt包含的是text文字四條線的 距離,
                    //此四條線距離也是以text文字baseline為基準的
                    fontMetricsInt = new Paint.FontMetricsInt();
                }
                getPaint().getFontMetricsInt(fontMetricsInt);
                if (minRect == null) {
                    //minRect用來獲取文字實際顯示的時候的左上角和右下角  座標
                    //該座標是以text文字baseline為基準的
                    minRect = new Rect();
                }
                getPaint().getTextBounds(getText().toString(), 0, getText().length(), minRect);
                canvas.translate(-minRect.left, fontMetricsInt.bottom - minRect.bottom);
            }
            super.onDraw(canvas);
        }

        @Override
        public void setText(CharSequence text, BufferType type) {
            super.setText(text, type);
            this.requestLayout();
        }
    }
}
沒使用canvas.translate(0, fontMetricsInt.bottom - fontMetricsInt.descent);
而使用canvas.translate(0, fontMetricsInt.bottom - minRect.bottom);
是因為文字實際顯示的時候,文字最底部並不一定是fontMetricsInt.descent,但minRect.bottom確一定能取到實際顯示的最底部的值。
具體原理還是要參考:http://blog.csdn.net/harvic880925/article/details/50423762
使用方法:
1.在xml中使用該自定義控制元件:
<com.test.myapplication.MyTextView
            android:id="@+id/tv1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@android:color/holo_red_dark"
            android:padding="10dp"
            android:text="hello"
            android:textSize="30sp"/>
2.java程式碼中獲取該控制元件,並操作該控制元件:
//myTextView實際上是自定義的LinearLayout
MyTextView myTextView = (MyTextView) findViewById(R.id.tv1);
//textView才是實際上的TextView
TextView textView = (TextView) myTextView.getTextView();
//對textView進行操作
textView.setText("perfect");
優點:1.去除了textView預設情況的下內邊距;
2.支援textview原生的屬性設定。
缺點:1.由於在原生textview外層嵌套了一層linearlayout,理論上會有效能降低,但是實際執行時候感覺不到;
2.也由於該層巢狀,所以在引用textview的時候需要多一步獲取textview的方法呼叫。
上述缺點目前都是可接受的。
以後有機會優化上面的缺點。同時感謝上述引用網站的創作者。