Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義帶標題邊框的Layout

Android自定義帶標題邊框的Layout

編輯:關於Android編程

前言:Android提供了一些方便使用的組件:TextView等,但是很多時候,默認的組件不能滿足需要,因此,必需掌握“自定義組件”的能力。對於程序員,或者其它職業,應當直面自己缺失的東西,通過這種方式,掌握新知識,新技能,這樣子,才能在快速迭代的社會裡,不被淘汰。

 

其實對於自定義View,現在我還停留在理解理論的層面,知道大概的步驟:

1、在value/attrs.xml裡,添加自定義View需要用到的一些變量屬性,可以在布局文件裡和代碼裡,給這些屬性賦值;

2、在自定義View的構造方法裡,獲取屬性的賦值(方便後面步驟使用);

3、根據需要,在onMeasure方法裡,重新測量View的一些尺寸;

4、重寫onDraw;

於是,我找來一些自定義的博客,跟著敲代碼,通過實操,深化自定義View的過程和期間遇到的問題。

期間,遇到的問題有:

1、Canvas.drawText()繪制文字的注意事項;

2、長度單位的認識;

那麼開始進入正題。

目標實現的效果:給Layout添加外邊框,和標題。

\

 

步驟:

1、添加屬性

這裡直接使用了上面博主的,其中"titleTextColor"屬性,因與系統定義的沖突,所以改名為“titleTextColor1”

 


        
        
        
        
        
        
        
        
        
        
        
        

2、在構造方法裡,加載屬性賦值

 

加載屬性賦值時,需要根據屬性值的格式,選擇取值的方法,需要注意的是單位。

 

public TitleBorderLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        setWillNotDraw(false);

        mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        Resources res = getResources();
        mTextPaint.density = res.getDisplayMetrics().density;

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TitleBorderLayout);

        mTitle = a.getText(R.styleable.TitleBorderLayout_title);
        int titleColor = a.getColor(R.styleable.TitleBorderLayout_titleTextColor1, DEFAULT_TITLE_COLOR);
        mTextPaint.setColor(titleColor);

        titleTextSize = a.getDimension(R.styleable.TitleBorderLayout_titleTextSize, 0);
        if (titleTextSize > 0) {
            mTextPaint.setTextSize(titleTextSize);
        }

        mTitlePosition = a.getDimensionPixelSize(R.styleable.TitleBorderLayout_titlePosition, -1);

        mBorderSize = a.getDimensionPixelSize(R.styleable.TitleBorderLayout_borderSize, DEFAULT_BORDER_SIZE);

        int borderColor = a.getColor(R.styleable.TitleBorderLayout_borderColor, DEFAULT_BORDER_COLOR);
        mBorderPaint.setColor(borderColor);

        a.recycle();
}


 

3、重寫onDraw

 

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Paint.FontMetrics fm = mTextPaint.getFontMetrics();
        final float titleHeight = fm.bottom - fm.top;

        final CharSequence titleText = (mTitle == null) ? "" : mTitle;
        final float titleWidth = Layout.getDesiredWidth(titleText, mTextPaint);

        final int width = getWidth();
        final int height = getHeight();


        if (mTitlePosition <= 0 || mTitlePosition + titleWidth > width) {
            mTitlePosition = (int) (DEFAULT_TITLE_POSITION_SCALE * width);
        }

        final float topBorderStartY = titleHeight / 2f - mBorderSize / 2f;

        mBorderPaneHeight = (int) Math.ceil(height - topBorderStartY);
        /* 畫標題邊框*/
        // 上
        canvas.drawRect(0, topBorderStartY, mTitlePosition, topBorderStartY + mBorderSize, mBorderPaint);
        canvas.drawText(titleText.toString(), mTitlePosition, - fm.top , mTextPaint);

        canvas.drawRect(mTitlePosition + titleWidth, topBorderStartY, width, topBorderStartY + mBorderSize, mBorderPaint);
        // 左
        canvas.drawRect(0, topBorderStartY + mBorderSize, mBorderSize, height, mBorderPaint);
        // 右
        canvas.drawRect(width - mBorderSize, topBorderStartY + mBorderSize, width, height, mBorderPaint);
        // 下
        canvas.drawRect(mBorderSize, height - mBorderSize, width - mBorderSize, height, mBorderPaint);
}

這裡實現了標題和邊框的繪制。其中重點說明一下文字的繪制。

 

Canvas提供drawText方法來繪制文字,具體的文檔說明如下:

\

參數“text”是將要繪制的文字;參數“paint”是繪制文字所使用的畫筆,一些文字屬性如尺寸,顏色,對齊方式,都可能調用paint的方法來實現;

參數“x”是文字開始繪制的x坐標,最後參數“y”是最重要的,它並不是文字的開始繪制的y坐標,而是定義為baseline的y坐標值。

如果想在矩形中心繪制文字的話,有些人的做法是:

\

①獲取文字所在的外框矩形Bound;②繪制文字時,使用Bound的高度計算“y”的參數值

可是得到的實際效果是:文字的位置偏低了。

 

我們來畫圖分析一下:

\

 

Baseline位於Hello的底部邊緣的地方,其下面區域(Baseline到Descent之間)可能還存在字符其他的部份,如:jpg字符。

在文字的坐標系統時,BaseLine的值為0,Descent為正數值,Ascent為負數值,如果想得到文字的高度,應該為Descent - Ascent。

 

文字畫筆提供了獲取這些數值的方法:

 

Paint.FontMetrics fm = mTextPaint.getFontMetrics();
final float titleHeight = fm.descent - fm.ascent;

 

 

查看FontMetrics的代碼,可以看到,其實在Descent下面還有bottom,在Ascent的上面還有top,關於這兩個參數的說明,我不是很理解,大概是邊緣吧,所以在獲取文字的高度時,我是這麼做的:

 

Paint.FontMetrics fm = mTextPaint.getFontMetrics();
final float titleHeight = fm.bottom - fm.top;

 

 

那麼針對上面的,在矩形的中心繪制文字時,y參數該如何取值呢?

\

 

(rectHeight - titleHeight) / 2 - top.

需要注意top為負數值.

 

4、修改構造方法

當我跟著博主的步驟時發現,自定義的View並沒有對添加標題,邊框後帶來的影響做處理?

就是如下圖的:

\

 

存在的問題:①自定義的View,其子View覆蓋在開始的地方;②子View覆蓋掉邊框

 

解決方法有兩種:①在布局文件裡,給自定義的View設置與titleTextSize相同大小的paddingTop,與borderSize相同大小的paddingLeft,paddingRightt和paddingBottom;

②在自定義View的文件裡,重新測量padding。

 

如果使用①的方法,每次使用的時候,都添加這些屬性,這顯得有些繁瑣,編寫代碼,不就是為了偷懶麼!!這並非首選方案。

下面貼上代碼:

public TitleBorderLayout(Context context, AttributeSet attrs) { super(context, attrs); setWillNotDraw(false); mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); Resources res = getResources(); mTextPaint.density = res.getDisplayMetrics().density; TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TitleBorderLayout); mTitle = a.getText(R.styleable.TitleBorderLayout_title); int titleColor = a.getColor(R.styleable.TitleBorderLayout_titleTextColor1, DEFAULT_TITLE_COLOR); mTextPaint.setColor(titleColor); titleTextSize = a.getDimension(R.styleable.TitleBorderLayout_titleTextSize, 0); if (titleTextSize > 0) { mTextPaint.setTextSize(titleTextSize); } mTitlePosition = a.getDimensionPixelSize(R.styleable.TitleBorderLayout_titlePosition, -1); mBorderSize = a.getDimensionPixelSize(R.styleable.TitleBorderLayout_borderSize, DEFAULT_BORDER_SIZE); int borderColor = a.getColor(R.styleable.TitleBorderLayout_borderColor, DEFAULT_BORDER_COLOR); mBorderPaint.setColor(borderColor); a.recycle(); int paddingStart = getPaddingStart(); int paddingTop = getPaddingTop(); int paddingEnd = getPaddingEnd(); int paddingBottom = getPaddingBottom(); int titleHeightPixel = (int) ((mTextPaint.getFontMetrics().bottom - mTextPaint.getFontMetrics().top)); paddingTop = paddingTop + titleHeightPixel; paddingStart = paddingStart + mBorderSize; paddingEnd = paddingEnd + mBorderSize; paddingBottom = paddingBottom + mBorderSize; setPadding(paddingStart, paddingTop, paddingEnd, paddingBottom); }
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved