1. 程式人生 > >android自定義view控制元件之一圓角背景TextView

android自定義view控制元件之一圓角背景TextView

繼昨天寫了一個TextView可以包括兩種不同的風格字型,而保證可以換行的情況下的自定義View。今天的正文還是寫一個自定義的TextView。

一慣風格首先亮出實現效果,這最是直接不過的了。看下圖:


其實不通過寫一個自定義view的方式也可以實現這個效果,但是就需你在你class檔案中堆更多的程式碼了,這從軟體工程的思想是不可取的。所以還是為了不省事,去寫一個自定義的TextView控制元件吧。相信大家都會寫這種比較簡單的自定義view了。

首先給出這個自定義view的類RadioTextView,程式碼如下:

package com.example.yuzhuo.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import com.example.yuzhuo.R;

/**
 * Created by yuzhuo on 16/9/4.
 */
public class RadioTextView extends View{

    /**
     * title文字
     */
    private String mTitleText;
    /**
     * title文字的顏色
     */
    private int mTitleTextColor;
    /**
     * titel文字的大小
     */
    private int mTitleTextSize;

    /**
     * background
     * @param context
     * @param attrs
     */
    private int background;

    /**
     * 圓角大小
     */
    private int mCornerSize;

    /**
     * 繪製時控制文字繪製的範圍
     */
    private Rect mtitleBound;
    private Paint mtitlePaint;

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

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

    /**
     * 獲得我自定義的樣式屬性
     *
     * @param context
     * @param attrs
     * @param defStyle
     */
    public RadioTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        /**
         * 獲得我們所定義的自定義樣式屬性
         */
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RaidoTextView, defStyle, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++)
        {
            int attr = a.getIndex(i);
            switch (attr)
            {
                case R.styleable.RaidoTextView_titleText:
                    mTitleText = a.getString(attr);
                    break;
                case R.styleable.RaidoTextView_titleTextColor:
                    // 預設顏色設定為黑色
                    mTitleTextColor = a.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.RaidoTextView_titleTextSize:
                    // 預設設定為16sp,TypeValue也可以把sp轉化為px
                    mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.RaidoTextView_background:
                    //預設為白色
                    background = a.getColor(attr, Color.WHITE);
                    break;
                case R.styleable.RaidoTextView_mCornerSize:
                    //預設圓角為0
                    mCornerSize = a.getInteger(attr,0);
                    break;

            }

        }
        a.recycle();
        /**
         * 獲得繪製文字的寬和高
         */
        mtitlePaint = new Paint();
        mtitlePaint.setTextSize(mTitleTextSize);
        mtitleBound = new Rect();
        mtitlePaint.getTextBounds(mTitleText, 0, mTitleText.length(), mtitleBound);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int width;
        int height ;
        if (widthMode == MeasureSpec.EXACTLY)
        {
            width = widthSize;
        } else
        {
            mtitlePaint.setTextSize(mTitleTextSize);
            mtitlePaint.getTextBounds(mTitleText, 0, mTitleText.length(), mtitleBound);

            int desired = getPaddingLeft() + mtitleBound.width() + getPaddingRight();
            width = desired<=widthSize?desired:widthSize;
        }

        if (heightMode == MeasureSpec.EXACTLY)
        {
            height = heightSize;
        } else
        {
            mtitlePaint.setTextSize(mTitleTextSize);
            mtitlePaint.getTextBounds(mTitleText, 0, mTitleText.length(), mtitleBound);
            int desired = getPaddingTop() + mtitleBound.height() + getPaddingBottom();
            height = desired<=heightSize?desired:heightSize;
        }
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);
        paint.setAntiAlias(true);
        paint.setColor(background);
        RectF rec = new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight());
        canvas.drawRoundRect(rec, mCornerSize, mCornerSize, paint);

        mtitlePaint.setColor(mTitleTextColor);
        Paint.FontMetricsInt fontMetrics = mtitlePaint.getFontMetricsInt();
        int baseline = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
        canvas.drawText(mTitleText,getPaddingLeft(), baseline, mtitlePaint);
    }
}
下面再給出在attrs.xml檔案中定義的styleable:
<declare-styleable name="RaidoTextView">
        <attr name="titleText" format="string" />
        <attr name="background" format="color"/>
        <attr name="titleTextSize" format="dimension"/>
        <attr name="titleTextColor" format="color"/>
        <attr name="mCornerSize" format="integer"/>
    </declare-styleable>
最後給出layout.xml中如何寫義的佈局檔案程式碼:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    <span style="color:#ff6666;">xmlns:radiostyle="http://schemas.android.com/apk/res-auto"</span>
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.yuzhuo.MainActivity" >

    <com.example.yuzhuo.view.RadioTextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        <span style="color:#ff0000;">radiostyle:titleText = "我是中國人"
        radiostyle:titleTextColor = "#ffffff"
        radiostyle:titleTextSize = "18sp"
        radiostyle:background ="#00ffff"
        radiostyle:mCornerSize = "18"/</span>>

    <com.example.yuzhuo.view.RadioTextView
        android:id="@+id/textView2"
        android:layout_marginTop="30dp"
        android:layout_below="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        radiostyle:titleText = "我是中國人"
        radiostyle:titleTextColor = "#ffffff"
        radiostyle:titleTextSize = "18sp"
        radiostyle:background ="#ff00ff"
        radiostyle:mCornerSize = "12"/>

    <com.example.yuzhuo.view.RadioTextView
        android:id="@+id/textView3"
        android:layout_marginTop="30dp"
        android:layout_below="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        radiostyle:titleText = "我是中國人"
        radiostyle:titleTextColor = "#ffffff"
        radiostyle:titleTextSize = "18sp"
        radiostyle:background ="#ffff00"
        radiostyle:mCornerSize = "6"/>


</RelativeLayout>
<span style="color:#ff6666;">xmlns:radiostyle="http://schemas.android.com/apk/res-auto"</span>
上面程式碼紅色標註出來的是,為你自定義的styleabe這義的標籤模式,這個名字可以隨意,只是需要與下面使用的時候保持一致,否則layout佈局載入的時候會造成識別不出來,而導致出錯。

這是一個特別簡單的自定義view控制元件,實現了個圓角背景的textview,但是通過最簡單的自定義view的編寫,可以很輕鬆的去了解和掌握自定義view控制元件的原理。

還是那句話,歡迎大家批評指正。手下點贊。需要專案工程的可以在github上面下載到,這個是連結點選開啟連結