Android自定义控件及属性

在开发中,现有的控件并不能完全满足我们的需求,往往需要我们去进行自定义控件的设计。

在这里我们先了解一个属性,attrs中发 format。

format有多种可选值设置:

1. reference:参考某一资源ID。

(1)属性定义:

<declare-styleable name = "名称">

<attr name = "background" format = "reference" />

</declare-styleable>

(2)属性使用:

<ImageView

android:layout_width = "42dip"

android:layout_height = "42dip"

android:background = "@drawable/图片ID"/>

2. color:颜色值

<declare-styleable name = "名称">

<attr name = "textColor" format = "color" />

</declare-styleable>

3. boolean:布尔值

<declare-styleable name = "名称">

<attr name = "focusable" format = "boolean" />

</declare-styleable>

4. dimension:尺寸值。

<declare-styleable name = "名称">

<attr name = "layout_width" format = "dimension" />

</declare-styleable>

5. float:浮点值。

6. integer:整型值。

7. string:字符串

8. fraction:百分数。

9. enum:枚举值

10. flag:位或运算

注意:

属性定义时可以指定多种类型值。

(1)属性定义:

<declare-styleable name = "名称">

<attr name = "background" format = "reference|color" />

</declare-styleable>

(2)属性使用:

<ImageView

android:layout_width = "42dip"

android:layout_height = "42dip"

android:background = "@drawable/图片ID|#00FF00"/>


接下来我们就可以正式进行XML属性的自定义了

一、在res/values/attrs文件中定义属性

<declare-styleable name="PasswordInputView">
        <!--边框圆角值-->
        <attr name="pivBorderRadius" format="dimension"/>
        <!--边框颜色-->
        <attr name="pivBorderColor" format="color|reference"/>
        <!--边框宽度-->
        <attr name="pivBorderWidth" format="dimension"/>
        <!--圆角尺寸-->
        <attr name="pivPasswordRadius" format="dimension"/>
        <!--密码颜色-->
        <attr name="pivPasswordColor" format="color"/>
        <!--密码大小-->
        <attr name="pivPasswordWidth" format="dimension"/>
        <!--密码长度-->
        <attr name="pivPasswordLength" format="integer"/>
        <!--密码文本-->
        <attr name="pivTextSize" format="dimension"/>
        <attr name="pivTextColor" format="color"/>
        <attr name="pivIsPass" format="boolean"/>
    </declare-styleable>

二、定义MyView继承View与自定义属性相关联(在构造方法中关联)

public PasswordInputView(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.PasswordInputView, 0, 0);
        borderColor = a.getColor(R.styleable.PasswordInputView_pivBorderColor, borderColor);
        borderWidth = a.getDimension(R.styleable.PasswordInputView_pivBorderWidth, borderWidth);
        borderRadius = a.getDimension(R.styleable.PasswordInputView_pivBorderRadius, borderRadius);
        passwordLength = a.getInt(R.styleable.PasswordInputView_pivPasswordLength, passwordLength);
        passwordColor = a.getColor(R.styleable.PasswordInputView_pivPasswordColor, passwordColor);
        passwordWidth = a.getDimension(R.styleable.PasswordInputView_pivPasswordWidth, passwordWidth);
        passwordRadius = a.getDimension(R.styleable.PasswordInputView_pivPasswordRadius, passwordRadius);

        textSize = (int) a.getDimension(R.styleable.PasswordInputView_pivTextSize, textSize);
        textColor = a.getColor(R.styleable.PasswordInputView_pivTextColor, textColor);
        isPass = a.getBoolean(R.styleable.PasswordInputView_pivIsPass, isPass);

        a.recycle();

        borderPaint.setStrokeWidth(borderWidth);
        borderPaint.setColor(borderColor);
        passwordPaint.setStrokeWidth(passwordWidth);
        passwordPaint.setStyle(Paint.Style.FILL);
        passwordPaint.setColor(passwordColor);

        InputFilter[] filters = {new InputFilter.LengthFilter(passwordLength)};
        setFilters(filters);
    }

注意:为防止使用时属性值未设置,在初始化时将个属性进行默认值的设定


PasswordInputView的具体代码如下

package com.laobai.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.text.InputFilter;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.widget.EditText;

import com.laobai.R;

import static android.graphics.Paint.ANTI_ALIAS_FLAG;
/**
*改控件为自定义的密码输入框,可设置明文及密码
*/
@SuppressLint("AppCompatCustomView")
public class PasswordInputView extends EditText {

    private static final int defaultContMargin = 5;
    private static final int defaultSplitLineWidth = 3;
    /**
     * 边框颜色
     */
    private int borderColor = 0xFFCCCCCC;
    private float borderWidth = 2;
    private float borderRadius = 0;

    private int passwordLength = 4;
    private int passwordColor = 0xFFCCCCCC;
    private float passwordWidth = 8;
    private float passwordRadius = 3;

    int textSize = 15;
    int textColor = Color.BLACK;

    boolean isPass = true;

    private Paint passwordPaint = new Paint(ANTI_ALIAS_FLAG);
    private Paint borderPaint = new Paint(ANTI_ALIAS_FLAG);

    private int textLength;
    String passText;

    public PasswordInputView(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.PasswordInputView, 0, 0);
        borderColor = a.getColor(R.styleable.PasswordInputView_pivBorderColor, borderColor);
        borderWidth = a.getDimension(R.styleable.PasswordInputView_pivBorderWidth, borderWidth);
        borderRadius = a.getDimension(R.styleable.PasswordInputView_pivBorderRadius, borderRadius);
        passwordLength = a.getInt(R.styleable.PasswordInputView_pivPasswordLength, passwordLength);
        passwordColor = a.getColor(R.styleable.PasswordInputView_pivPasswordColor, passwordColor);
        passwordWidth = a.getDimension(R.styleable.PasswordInputView_pivPasswordWidth, passwordWidth);
        passwordRadius = a.getDimension(R.styleable.PasswordInputView_pivPasswordRadius, passwordRadius);

        textSize = (int) a.getDimension(R.styleable.PasswordInputView_pivTextSize, textSize);
        textColor = a.getColor(R.styleable.PasswordInputView_pivTextColor, textColor);
        isPass = a.getBoolean(R.styleable.PasswordInputView_pivIsPass, isPass);

        a.recycle();

        borderPaint.setStrokeWidth(borderWidth);
        borderPaint.setColor(borderColor);
        passwordPaint.setStrokeWidth(passwordWidth);
        passwordPaint.setStyle(Paint.Style.FILL);
        passwordPaint.setColor(passwordColor);

        InputFilter[] filters = {new InputFilter.LengthFilter(passwordLength)};
        setFilters(filters);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int width = getWidth();
        int height = getHeight();

        // 外边框
        RectF rect = new RectF(0, 0, width, height);
        borderPaint.setColor(borderColor);
        canvas.drawRoundRect(rect, borderRadius, borderRadius, borderPaint);

        // 内容区
        RectF rectIn = new RectF(rect.left + defaultContMargin, rect.top + defaultContMargin,
                rect.right - defaultContMargin, rect.bottom - defaultContMargin);
        borderPaint.setColor(Color.WHITE);
        canvas.drawRoundRect(rectIn, borderRadius, borderRadius, borderPaint);

        // 分割线
        borderPaint.setColor(borderColor);
        borderPaint.setStrokeWidth(defaultSplitLineWidth);
        for (int i = 1; i < passwordLength; i++) {
            float x = width * i / passwordLength;
            canvas.drawLine(x, 0, x, height, borderPaint);
        }

        float cx, cy = height / 2;
        float half = width / passwordLength / 2;
        if (isPass) {
            // 密码
            for (int i = 0; i < textLength; i++) {
                cx = width * i / passwordLength + half;
                canvas.drawCircle(cx, cy, passwordWidth, passwordPaint);
            }
        } else {
            passwordPaint.setTextSize(textSize);
            passwordPaint.setColor(textColor);
            passwordPaint.setTextAlign(Paint.Align.CENTER);

            Paint.FontMetrics fontMetrics = passwordPaint.getFontMetrics();
            float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
            float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom

            int baseLineY = (int) (rect.centerY() - top / 2 - bottom / 2);//基线中间点的y轴计算公式
            if (!TextUtils.isEmpty(passText)) {
                for (int i = 0; i < textLength; i++) {
                    cx = width * i / passwordLength + half;
                    canvas.drawText(String.valueOf(passText.charAt(i)), cx, baseLineY, passwordPaint);
                }
            }
        }
    }

    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        passText = text.toString();
        textLength = passText.length();
        invalidate();
    }

    public int getBorderColor() {
        return borderColor;
    }

    public void setBorderColor(int borderColor) {
        this.borderColor = borderColor;
        borderPaint.setColor(borderColor);
        invalidate();
    }

    public float getBorderWidth() {
        return borderWidth;
    }

    public void setBorderWidth(float borderWidth) {
        this.borderWidth = borderWidth;
        borderPaint.setStrokeWidth(borderWidth);
        invalidate();
    }

    public float getBorderRadius() {
        return borderRadius;
    }

    public void setBorderRadius(float borderRadius) {
        this.borderRadius = borderRadius;
        invalidate();
    }

    public int getPasswordLength() {
        return passwordLength;
    }

    public void setPasswordLength(int passwordLength) {
        this.passwordLength = passwordLength;
        invalidate();
    }

    public int getPasswordColor() {
        return passwordColor;
    }

    public void setPasswordColor(int passwordColor) {
        this.passwordColor = passwordColor;
        passwordPaint.setColor(passwordColor);
        invalidate();
    }

    public float getPasswordWidth() {
        return passwordWidth;
    }

    public void setPasswordWidth(float passwordWidth) {
        this.passwordWidth = passwordWidth;
        passwordPaint.setStrokeWidth(passwordWidth);
        invalidate();
    }

    public float getPasswordRadius() {
        return passwordRadius;
    }

    public void setPasswordRadius(float passwordRadius) {
        this.passwordRadius = passwordRadius;
        invalidate();
    }

    public void setIsPass(boolean isPass){
        this.isPass = isPass;
        invalidate();
    }
    public void setTextSize(int textSize){
        this.textSize = textSize;
        invalidate();
    }
    public void setTextColor(int textColor){
        this.textColor = textColor;
        invalidate();
    }
}

三、XML布局文件中的应用

要使用自定义属性必须加上前缀:xmlns:app="http://schemas.android.com/apk/res-auto"

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:background="@color/backcolor_white"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <com.view.PasswordInputView
        android:id="@+id/code_edit"
        android:layout_width="270dp"
        android:layout_height="45dp"
        android:layout_marginTop="10dp"
        android:inputType="number"
        android:lines="1"
        android:visibility="gone"
        app:pivBorderColor="#dddddd"
        app:pivBorderWidth="0.5dp"
        app:pivIsPass="false"
        app:pivPasswordLength="6"
        app:pivPasswordWidth="10dp"
        app:pivTextColor="#333333"
        app:pivTextSize="@dimen/sp_text_16"
        tools:text="125635"
        tools:visibility="visible" />

</LinearLayout>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值