Android自定义View

近日在读《Android群英传》中自定义控件详解,此文作为总结与回顾。

View中有些重要的回调方法:

  • onFinishiInflate()从XML加载组件后回调
  • onSizeChanged()组件大小修改时回调
  • onMeasure()回调该方法对组件测量
  • onLayout()回调该方法显示位置
  • onTouchEvent()监听触摸事件

通常情况有三种方式创建自定义View控件:

  1. 对现有控件扩展
  2. 通过组合实现新控件
  3. 重写View实现新控件
1、对现有控件扩展
此方法是在原有控件基础上扩展,增加功能或者修改UI。
举一个例子,如下图,该控件继承自TextView,重写onDraw()方法,实现下图效果。

NewText代码:
public class NewText extends TextView {
    private int mViewWidth;
    private Paint mPaint;
    private LinearGradient mLinearGradient;
    private Matrix mGradientMatrix;
    private int mTranslate;
    private Paint mPaint1;
    private Paint mPaint2;

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

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

    public void onDraw(Canvas canvas) {
        mPaint1 = new Paint();
        mPaint1.setColor(Color.BLUE);
        mPaint1.setStyle(Paint.Style.STROKE);
        mPaint2 = new Paint();
        mPaint2.setColor(Color.YELLOW);
        mPaint2.setStyle(Paint.Style.FILL);
        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint1);  //绘制蓝色矩形
        canvas.drawRect(10,10,getMeasuredWidth() + 10,getMeasuredHeight() + 10,mPaint2);  //绘制黄色矩形
        canvas.save();
        super.onDraw(canvas);  //调用TextView的onDraw方法绘制文字
        canvas.restore();

    }
}
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    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"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.example.administrator.ui.MainActivity"
    tools:showIn="@layout/activity_main">

    <com.example.administrator.ui.NewText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="hello world"
        android:textSize="30sp"/>
</RelativeLayout>
遇到问题:
关于构造函数
public NewText(Context context) 通过Java代码动态创建该控件时调用
public NewText(Context context,AttributeSet attrs) xml布局文件中创建时调用
public NewText(Context context,AttributeSet attrs,int defStyle) xml布局文件中创建,同时设置Style时调用

2、通过组合实现新控件
通常继承一个GroupView,然后添加合适的控件,进而组合成新的复合控件。
下面以复合控件Topbar为例:
2.1定义属性
创建att.xml,定义相应属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="Topbar">
        <attr name="title1" format="string" />
        <attr name="titleTextSize" format="dimension" />
        <attr name="titleTextColor1" format="color|reference" />
        <attr name="leftTextColor" format="color|reference" />
        <attr name="leftBackground" format="reference|color" />
        <attr name="rightTextColor" format="reference|color" />
        <attr name="rightBackground" format="reference|color" />
        <attr name="rightText" format="string" />
        <attr name="leftText" format="string" />
    </declare-styleable>
</resources>
系统提供了TypeArray用来获取自定义属性集,通过TypeArray的getString(),getColor()等方法可以获得相应属性值。
TypeArray ta = context.obtainStyledAttributed(AttributeSet, int[]);

2.2组合控件
package com.example.administrator.ui;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;

/**
 * Created by Administrator on 2016/1/30.
 */
public class Topbar extends RelativeLayout {

    private   LayoutParams mTitleParams;
    private LayoutParams mRightParams;
    private LayoutParams mLeftParams;
    private TextView mTitleView;
    private Button mRightButton;
    private Button mLeftButton;
    private int mTitleTextColor;
    private String mTitle;
    private float mTitleTextSize;
    private Drawable mRightBackground;
    private String mRightText;
    private int mRightTextColor;
    private String mLeftText;
    private Drawable mLeftBackground;
    private int mLeftTextColor;
    TypedArray ta;

    public Topbar(Context context, AttributeSet attrs) {
        super(context, attrs);
        //将属性值存储到TypeArray对象中
        ta = context.obtainStyledAttributes(attrs, R.styleable.Topbar);
        
        //获取相应属性值
        mLeftTextColor = ta.getColor(R.styleable.Topbar_leftTextColor, 0);
        mLeftBackground = ta.getDrawable(R.styleable.Topbar_leftBackground);
        mLeftText = ta.getString(R.styleable.Topbar_leftText);

        mRightTextColor = ta.getColor(R.styleable.Topbar_rightTextColor, 0);
        mRightBackground = ta.getDrawable(R.styleable.Topbar_rightBackground);
        mRightText = ta.getString(R.styleable.Topbar_rightText);

        mTitleTextSize = ta.getDimension(R.styleable.Topbar_titleTextSize, 30);
        mTitleTextColor = ta.getColor(R.styleable.Topbar_titleTextColor1, 0);
        mTitle = ta.getString(R.styleable.Topbar_title1);
        
        //获取完TypeArray之后,调用recyle避免重新创建时出错
        ta.recycle();

        //创建组件并赋值
        mLeftButton = new Button(context);
        mRightButton = new Button(context);
        mTitleView = new TextView(context);

        mLeftButton.setBackground(mLeftBackground);
        mLeftButton.setText(mLeftText);
        mLeftButton.setTextColor(mLeftTextColor);

        mRightButton.setBackground(mRightBackground);
        mRightButton.setText(mRightText);
        mRightButton.setTextColor(mRightTextColor);

        mTitleView.setText(mTitle);
        mTitleView.setTextColor(mTitleTextColor);
        mTitleView.setTextSize(mTitleTextSize);
        mTitleView.setGravity(TEXT_ALIGNMENT_CENTER);

        //设置布局元素
        mLeftParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
        mLeftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);
        addView(mLeftButton, mLeftParams);

        mRightParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
        mRightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE);
        addView(mRightButton, mRightParams);

        mTitleParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
        mTitleParams.addRule(RelativeLayout.CENTER_IN_PARENT,TRUE);
        addView(mTitleView, mTitleParams);

        //添加mRightButton与mLeftButton响应事件
        mRightButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                mListener.RightClick();
            }
        });

        mLeftButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                mListener.LeftClick();
            }
        });
    }

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

    public Topbar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        ta = context.obtainStyledAttributes(attrs, R.styleable.Topbar);
    }

    private TopbarClickListener mListener;

    public void setonTopbarClickListener(TopbarClickListener listener){
        this.mListener = listener;
    }
    
    //为调用者暴漏接口
    public interface TopbarClickListener{
        void LeftClick();
        void RightClick();
    }
}

调用者实现接口回调
Topbar bar = (Topbar) findViewById(R.id.topbar);
        bar.setonTopbarClickListener(new Topbar.TopbarClickListener() {
            @Override
            public void LeftClick() {
                Toast.makeText(MainActivity.this,"left",Toast.LENGTH_LONG).show();
            }

            @Override
            public void RightClick() {
                Toast.makeText(MainActivity.this,"right",Toast.LENGTH_LONG).show();
            }
        });

2.3引用UI
第三方控件使用使用下面代码引入名字空间
xmlns:app="http://schemas.android.com/apk/res-auto"
名字空间取为app,自定义属性调用如下
<com.example.administrator.ui.Topbar
        android:id="@+id/topbar"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        app:leftBackground="@color/colorAccent"
        app:leftText="left"
        app:leftTextColor="@color/colorPrimary"
        app:rightBackground="@color/colorAccent"
        app:rightText="right"
        app:rightTextColor="@color/colorPrimary"
        app:title1="title"
        app:titleTextColor1="@color/colorPrimary"
        app:titleTextSize="30sp"/>
3、重写View实现新控件
继承View,并重写它的onDraw(),onMeasure()实现绘制,onTouchEvent()等触控事件实现交互。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值