Android中自定义View,自定义布局

这里主要用到两种自定义布局的方法,第一是使用inflate加载布局文件,也是最简单的,但是前提是要继承自ViewGroup,第二种是自定义View的方式是重写View的onMeasure(),onLayout(),onDraw方法,这种要稍微复杂一点。下面总结一下两种自定义View。
一、使用布局文件xml文件来自定义布局
首先定义定义一个View,继承自RelativeLayout,当然也可以是LieanerLayout。然后实现其三个构造方法,使加载布局文件的方式会调用有两个参数的构造方法。
这个举个例子,自定义一个标题栏,由于Android原生的toolbar或者actionBar有时候不能满足业务需求,那么就需要自定义View。来达到我们特定的需求。
TitleView.java代码如下

package com.pos.ui;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.pos.R;
public class TitleView extends RelativeLayout {
    private TextView title;
    private RelativeLayout iconBack;
    private RelativeLayout iconMore;
    private ImageView ivMore;
    public void setBackIconOnClickListener(OnClickListener clickListener) {
        if(iconBack != null)
            iconBack.setOnClickListener(clickListener);
    }


    public void setMoreIconOnClickListener(OnClickListener clickListener) {
        if(iconMore != null)
            iconMore.setOnClickListener(clickListener);
    }
    public void setTitle(String text) {
        title.setText(text);
    }

    public void init(Context context) {

    View.inflate(context, R.layout.item_title, this);
        iconMore = (RelativeLayout)findViewById(R.id.icon_more);
        ivMore = (ImageView)findViewById(R.id.img_more);

        title = (TextView)findViewById(R.id.tv_title);

    }
    public TitleView(Context context) {
        super(context);
        init(context);
    }

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

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

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

        String myTitle = a.getString(R.styleable.posView_myTitle);
        boolean backIconIsVisible = a.getBoolean(R.styleable.posView_backIconIsVisible, true);
        //Log.e("TitleView",backIconIsVisible+"");
        if (!backIconIsVisible) {

            ImageView img_back = (ImageView)findViewById(R.id.img_back);
            img_back.setImageResource(R.drawable.btn_nomal);
        } else {
            iconBack = (RelativeLayout)findViewById(R.id.icon_back);
        }
        int iconMoreId = a.getResourceId(R.styleable.posView_rightIcon, R.drawable.btn_nomal);
        ivMore.setImageResource(iconMoreId);
        title.setText(myTitle);

        a.recycle();
    }
}

布局文件item_title.xml的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dip"
    android:background="@color/red">


            <RelativeLayout
                android:id="@+id/icon_back"
                android:layout_width="50dp"
                android:layout_height="50dp"

                android:background="@drawable/bg_button"
                >
                <ImageView
                    android:id="@+id/img_back"
                    android:layout_marginLeft="10dp"
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:src="@drawable/icon_back"
                    android:layout_centerVertical="true"
                    />
            </RelativeLayout>



            <TextView
                android:id="@+id/tv_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:text="标题"
                android:textSize="17sp"
                android:textColor="#fff" />

            <RelativeLayout
                android:id="@+id/icon_more"
                android:layout_width="50dp"
                android:layout_height="match_parent"
                android:background="@drawable/bg_button"
                android:layout_alignParentRight="true" >
                <ImageView
                    android:id="@+id/img_more"
                    android:layout_width="35dp"
                    android:layout_height="30dp"
                    android:layout_centerInParent="true"
                    />
            </RelativeLayout>
</RelativeLayout>

最后的样子为:
这里写图片描述
标题栏主要由三个部分,左边的回退,中间的标题,右边的更多选项,默认不显示,也可以设置显示,比如:
这里写图片描述

自定义的标签:在value/attrs.xml中

<?xml version="1.0" encoding="utf-8"?>
<resources>
     <declare-styleable name="posView">
        <attr name="myTitle" format="string" />
        <attr name="myIcon" format="reference" />
        <attr name="bakIcon" format="reference" />
         <attr name="rightIcon" format="reference" />
         <attr name="backIconIsVisible" format="boolean"/>
    </declare-styleable>
</resources>

基本上通过布局文件自定义View的代码都粘贴完了,是不是感觉很简单呢,代码确实不多。
通过View.inflate方法将item_title.xml文件加载到TitleView这个ViewGroup上。这样TitileView就会显示item_title里面的布局了,这么也忽略了onDraw方法绘制View的繁琐。

View.inflate(context, R.layout.item_title, this);
iconMore = (RelativeLayout)findViewById(R.id.icon_more);
ivMore = (ImageView)findViewById(R.id.img_more);
title = (TextView)findViewById(R.id.tv_title);

代码中的自定义属性标签,通过TypedArray来获取,这里不多说。
使用的时候,

<com.pos.ui.TitleView
        android:id="@+id/author_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:myTitle = "标题字样"
        >
</com.pos.ui.TitleView>

其中还定义了左右两个按钮的点击事件,可以在Activity中进行相应的调用。

TitleView titleView = (TitleView) findViewById(R.id.author_title);
 titleView.setBackIconOnClickListener(new View.OnClickListener() {
      @Override
         public void onClick(View v) {
           AuthorizeContactActivity.this.finish();
         }
  });

这样就完成一个自定义View了,需要注意的是,这个TitleView继承了ViewGoup,而不能继承View,因为ViewGoup内部处理wrap_content这个属性,View内部对wrap_content的处理与match_content是一样的,所以不能继承View。如果继承了View,就需要在onLayout方法中对wrap_content这个属性就行处理。
二、通过重写View的onMeasure,onLayout,onDraw等方法自定义View。
下面以一个TextView为例,来看看如何拓展TextView从而创建新的空间,比如想让一个TextView的北京更加丰富,给其多绘制几层背景。比如
这里写图片描述
如果要实现这个效果,用布局文件可能很不好做,但是如果重写onDraw方法就会好很多,方法如下:

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

程序调用super.onDraw(canvas)方法来实现原生空间的功能,但是在调用super.onDraw(canvas)方法之前和之后,我们都可以实现自己的逻辑,分别在系统绘制文字前后,完成自己的操作,即如下显示。

@Override
    protected void onDraw(Canvas canvas) {
        //绘制文本内容前
        super.onDraw(canvas);
        //绘制文本内容后
    }

思路就是这样,首先在构造方法中完成必要的对象的初始化工作,这里是初始化画笔。代码如下:

private void initView() {
        mPaint1 = new Paint();
        mPaint1.setColor(getResources().getColor(
                android.R.color.holo_blue_light));
        mPaint1.setStyle(Paint.Style.FILL);
        mPaint2 = new Paint();
        mPaint2.setColor(Color.YELLOW);
        mPaint2.setStyle(Paint.Style.FILL);
    }

最后的onDraw为:

 @Override
    protected void onDraw(Canvas canvas) {
        // 绘制外层矩形
        canvas.drawRect(
                0,
                0,
                getMeasuredWidth(),
                getMeasuredHeight(),
                mPaint1);
        // 绘制内层矩形
        canvas.drawRect(
                10,
                10,
                getMeasuredWidth() - 10,
                getMeasuredHeight() - 10,
                mPaint2);
        canvas.save();
        // 绘制文字前平移10像素
        canvas.translate(10, 0);
        // 父类完成的方法,即绘制文本
        super.onDraw(canvas);
        canvas.restore();
    }

最后也贴出整个代码

package com.pos.ui;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.TextView;

public class MyTextView extends TextView {

    private Paint mPaint1, mPaint2;

    public MyTextView(Context context) {
        super(context);
        initView();
    }

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

    public MyTextView(Context context, AttributeSet attrs,
                      int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        mPaint1 = new Paint();
        mPaint1.setColor(getResources().getColor(
                android.R.color.holo_blue_light));
        mPaint1.setStyle(Paint.Style.FILL);
        mPaint2 = new Paint();
        mPaint2.setColor(Color.YELLOW);
        mPaint2.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 绘制外层矩形
        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint1);
        // 绘制内层矩形
        canvas.drawRect(10,10,getMeasuredWidth() - 10,getMeasuredHeight() - 10,mPaint2);
        canvas.save();
        // 绘制文字前平移10像素
        canvas.translate(10, 0);
        // 父类完成的方法,即绘制文本
        super.onDraw(canvas);
        canvas.restore();
    }
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值