Android自定义控件(一):入门篇

当Android学习了一段时间后,可能就不满足于系统所提供的控件了,特别是有个性的开发者有着自己的想法,这时就需要学习Android自定义控件了,这里简单介绍一下自定义控件的几个步骤:

  1. 编写自定义控件属性;
  2. 编写自定义控件类,继承View类型或者ViewGroup类型;
  3. 在构造方法中获取xml属性值;
  4. 重写onMeasure,测量子View的宽高;
  5. 重写onLayout,布置子View的位置;
  6. 重写onDraw,绘制元素;

这6个步骤并不是必须的,按需所取。


入门

既然是个入门,那就从最简单的开始吧。我们的目标是实现一个自定义View,能够显示图片文字水印的控件,能够自定义文字水印的位置、大小、字体颜色等。效果图如下:

这里写图片描述

额,我承认是有点low,但这个作为自定义控件入门还是非常不错的,然后根据上面的步骤一步步来看,首先我们需要编写自定义控件属性,在values文件夹下面新建attrs.xml文件,这个里面可以声明我们想要自定义控件的属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyImageView">
        <attr name="img_description" format="string" />
        <attr name="description_size" format="dimension" />
        <attr name="description_color" format="color" />
        <attr name="description_position" format="enum">
            <enum name="left_top" value="0" />
            <enum name="right_top" value="1" />
            <enum name="center" value="2" />
            <enum name="left_bottom" value="3" />
            <enum name="right_bottom" value="4" />
        </attr>
        <attr name="description_padding" format="dimension" />
    </declare-styleable>
</resources>

根据属性命名,结合效果图来看不难理解,这里面定义了图片描述字体大小字体颜色文字位置文字边距

有了这些自定义属性,那么我们就要新建我们自定义的控件类,这里就是MyImageView,继承自ImageView,这边代码比较多,主要是为了能够完整地看到一个自定义控件类的初级编写:

package com.cjt.customview;

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.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ImageView;

/**
 * Created by mvp-cjt on 2016/6/21.
 * Email:879309896@qq.com
 */
public class MyImageView extends ImageView{

    /**
     * 左上
     */
    public static final int LEFT_TOP = 0;

    /**
     * 右上
     */
    public static final int RIGHT_TOP = 1;

    /**
     * 中间
     */
    public static final int CENTER = 2;

    /**
     * 左下
     */
    public static final int LEFT_BOTTOM = 3;

    /**
     * 右下
     */
    public static final int RIGHT_BOTTOM = 4;

    /**
     * 画笔
     */
    private Paint mPaint;

    /**
     * 文字水印
     */
    private String imgDescription;

    /**
     * 字体大小
     */
    private int descriptionSize;

    /**
     * 字体宽高
     */
    private Rect mBound;

    /**
     * 水印位置,默认是CENTER
     */
    private int descriptionPosition = CENTER;

    /**
     * 文字颜色
     */
    private int descriptionColor = Color.BLACK;

    /**
     * 文字水印与图片边距的距离
     */
    private int descriptionPadding;

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

    public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        /**
         * 获得我们所定义的自定义样式属性
         */
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyImageView, defStyleAttr, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++)
        {
            int attr = a.getIndex(i);
            switch (attr)
            {
                case R.styleable.MyImageView_img_description:
                    imgDescription = a.getString(attr);
                    break;
                case R.styleable.MyImageView_description_size:
                    // 获取文字大小,默认是16sp,这里需要转换为px
                    descriptionSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP, 10, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.MyImageView_description_position:
                    descriptionPosition = a.getInt(attr, CENTER);
                    break;
                case R.styleable.MyImageView_description_color:
                    descriptionColor = a.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.MyImageView_description_padding:
                    descriptionPadding = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics()));
                    break;
            }
        }
        a.recycle();
        mPaint = new Paint();

        /**
         * 获得绘制文本的宽和高
         */
        mPaint.setTextSize(descriptionSize);
        mBound = new Rect();
        mPaint.getTextBounds(imgDescription, 0, imgDescription.length(), mBound);
        mPaint.setTextSize(descriptionSize);
        mPaint.setColor(descriptionColor);
        // 消除锯齿
        mPaint.setAntiAlias(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float x = 0;
        float y = 0;
        switch (descriptionPosition){
            case LEFT_TOP:
                x = descriptionPadding;
                y = mBound.height() + descriptionPadding;
                break;
            case RIGHT_TOP:
                x = getWidth() - mBound.width() - descriptionPadding;
                y = mBound.height() + descriptionPadding;
                break;
            case CENTER:
                x = getWidth()/2 - mBound.width()/2;
                y = getHeight()/2 + mBound.height()/2;
                break;
            case LEFT_BOTTOM:
                x = descriptionPadding;
                y = getHeight() - descriptionPadding;
                break;
            case RIGHT_BOTTOM:
                x = getWidth() - mBound.width() - descriptionPadding;
                y = getHeight() - descriptionPadding;
                break;
        }
        canvas.drawText(imgDescription, x, y, mPaint);
    }
}

由于这是一个自定义View,所以就没有重写onMeasure和onLayout方法,这两个主要是针对于自定义ViewGroup而言的。这里在构造方法通过固定的方式,获取到xml中编写的属性值。然后在onDraw方法中通过一定的计算,画出我们的文字水印。

注意:重写控件类一定要注意几个构造方法的区别,还有java中的super和this的差异。

大功告成!!撒花撒花- -。那么具体怎么用,这里给个最简单的例子:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    ...>

    <com.cjt.customview.MyImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/curry"
        custom:description_padding="10dp"
        custom:description_position="right_bottom"
        custom:description_size="24sp"
        custom:description_color="#FFF"
        custom:img_description="Stephen Curry" />
</RelativeLayout>

是不是灰常灰常的方便呢?就是这么酷炫,O(∩_∩)O哈哈~。入了门,还是要自己动动手才会印象深刻,写个验证码控件多点触控图片控件都是可以的。加油,敬请期待下篇Android自定义控件(二):提高篇。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值