欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android自定义控件及属性

程序员文章站 2022-06-08 23:48:50
...

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

在这里我们先了解一个属性,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>