Android自定义ViewAndroid开发经验谈Android自定义控件、自定义View、自定义ViewGroup

Android自定义消息提示容器

2019-06-05  本文已影响5人  Android师哥
night_rain.png

自定义View,一是为了满足设计需求,二是开发者进阶的标志之一。随心所欲就是我等奋斗的目标!!!

效果

效果图

实现逻辑

全部代码

/**
 * 自定义消息提示容器
 * {@link #countHintTextPosition() 计算绘制位置}
 * {@link #countDefaultTextBackgroundSize() 计算背景高度}
 *
 * @attr customHintTextColor         //消息数字颜色
 * @attr customHintTextSize          //消息数字尺寸
 * @attr customHintTextBackground    //消息背景颜色
 * @attr customSelfAdaption          //背景是否自适应数字大小
 * @attr customHintTextMarginLeft    //距离容器左侧外边距
 * @attr customHintTextMarginRight   //距离容器右侧外边距
 * @attr customHintTextMarginTop     //距离容器顶部外边距
 * @attr customHintTextMarginBottom  //距离容器底部外边距
 * @attr customHintPosition          //消息提示相对容器位置
 */
public class CustomMessageHintContainerView extends LinearLayout {
    private static final String TAG = "CustomMessageHintContai";
    //提示文字默认长度
    private final int DEFAULT_LENGTH = 3;
    //左上
    public static final int POSITION_TOP_LIFT = 101;
    //左下
    public static final int POSITION_BOTTOM_LIFT = 102;
    //右上
    public static final int POSITION_TOP_RIGHT = 103;
    //右下
    public static final int POSITION_BOTTOM_RIGHT = 104;
    /**
     * 提示文字内容
     */
    private String mMessageHintTextContent;
    //绘制提示文字背景的画笔
    private Paint mPaint;
    //绘制提示文字的画笔
    private TextPaint mTextPaint;
    //提示文字的颜色
    private int mMessageHintTextColor;
    //提示文字的尺寸
    private float mMessageHintTextSize;
    //提示文字的背景颜色
    private int mMessageHintBackgroundColor;
    //提示内容相对容器的位置
    private int mMessageHintPosition;
    //是否根据文字自适应背景大小
    private boolean isSelfAdaption;
    //提示文字外边距
    private float mMessageHintMarginLeft;
    private float mMessageHintMarginTop;
    private float mMessageHintMarginRight;
    private float mMessageHintMarginBottom;
    //默认背景的高度
    private float mDefaultBackgroundHeight = 0;


    public CustomMessageHintContainerView(Context context) {
        this(context, null);
    }

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

    public CustomMessageHintContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //初始默认属性
        initDefaultAttrs();
        //初始自定义属性
        initAttrs(context, attrs);
        //初始画笔
        initPaint();
        //计算默认情况下需要的背景尺寸
        countDefaultTextBackgroundSize();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        RectF mRectF = countHintTextPosition();
        if (mRectF != null) {
            float backgroundWidth = mRectF.width();
            float backgroundHeight = mRectF.height();
            float radius = backgroundHeight / 2.0F;
            //绘制背景
            canvas.drawRoundRect(mRectF, radius, radius, mPaint);
            Rect measureTextSize = measureTextSize("8");
            //绘制文字
            if (!isSelfAdaption) {
                if (Integer.parseInt(mMessageHintTextContent) > 99) {
                    canvas.drawText("99+", backgroundWidth / 2.0F + mRectF.left, radius + mRectF.top + measureTextSize.height() / 2.0F, mTextPaint);
                } else {
                    canvas.drawText(mMessageHintTextContent, backgroundWidth / 2.0F + mRectF.left, radius + mRectF.top + measureTextSize.height() / 2.0F, mTextPaint);
                }
            } else {
                canvas.drawText(mMessageHintTextContent, backgroundWidth / 2.0F + mRectF.left, radius + mRectF.top + measureTextSize.height() / 2.0F, mTextPaint);
            }


        }
    }


    /**
     * 计算默认背景尺寸
     */
    private void countDefaultTextBackgroundSize() {
        if (!TextUtils.isEmpty(mMessageHintTextContent)) {
            StringBuffer mStringBuffer = new StringBuffer();
            for (int i = 0; i < DEFAULT_LENGTH; i++) {
                mStringBuffer.append("8");
            }
            Rect mDefaultTextRect = measureTextSize(mStringBuffer.toString());
            mDefaultBackgroundHeight = (float) Math.ceil(Math.sqrt((Math.pow(mDefaultTextRect.width(), 2) + Math.pow(mDefaultTextRect.height(), 2))));

        }
    }

    /**
     * 计算提示文字显示位置
     */
    private RectF countHintTextPosition() {

        RectF mRectF = null;
        if (!TextUtils.isEmpty(mMessageHintTextContent)) {
            if (mDefaultBackgroundHeight == 0) {
                countDefaultTextBackgroundSize();
            }
            //显示内容的文字尺寸
            Rect mTextContentRect = measureTextSize(mMessageHintTextContent);
            int mMeasuredWidth = this.getMeasuredWidth();
            int mMeasuredHeight = this.getMeasuredHeight();
            mRectF = new RectF();
            switch (mMessageHintPosition) {
                case POSITION_TOP_LIFT:
                    mRectF.top = mMessageHintMarginTop;
                    mRectF.bottom = mMessageHintMarginTop + mDefaultBackgroundHeight;
                    mRectF.left = mMessageHintMarginLeft;
                    if (isSelfAdaption) {
                        if (mMessageHintTextContent.length() <= DEFAULT_LENGTH) {
                            mRectF.right = mMessageHintMarginLeft + mDefaultBackgroundHeight;
                        } else {
                            mRectF.right = mMessageHintMarginLeft + mTextContentRect.width() + mDefaultBackgroundHeight / 2;
                        }
                    } else {
                        mRectF.right = mMessageHintMarginLeft + mDefaultBackgroundHeight;
                    }
                    break;
                case POSITION_BOTTOM_LIFT:
                    mRectF.left = mMessageHintMarginLeft;
                    mRectF.bottom = mMeasuredHeight - mMessageHintMarginBottom;
                    mRectF.top = mMeasuredHeight - mMessageHintMarginBottom - mDefaultBackgroundHeight;
                    if (isSelfAdaption) {
                        if (mMessageHintTextContent.length() <= DEFAULT_LENGTH) {
                            mRectF.right = mMessageHintMarginLeft + mDefaultBackgroundHeight;
                        } else {
                            mRectF.right = mMessageHintMarginLeft + mTextContentRect.width() + mDefaultBackgroundHeight / 2;
                        }
                    } else {
                        mRectF.right = mMessageHintMarginLeft + mDefaultBackgroundHeight;
                    }
                    break;
                case POSITION_TOP_RIGHT:
                    mRectF.top = mMessageHintMarginTop;
                    mRectF.bottom = mMessageHintMarginTop + mDefaultBackgroundHeight;
                    mRectF.right = mMeasuredWidth - mMessageHintMarginRight;
                    if (isSelfAdaption) {
                        if (mMessageHintTextContent.length() <= DEFAULT_LENGTH) {
                            mRectF.left = mMeasuredWidth - (mMessageHintMarginRight + mDefaultBackgroundHeight);
                        } else {
                            mRectF.left = mMeasuredWidth - (mMessageHintMarginRight + mTextContentRect.width() + mDefaultBackgroundHeight / 2);
                        }
                    } else {
                        mRectF.left = mMeasuredWidth - (mMessageHintMarginRight + mDefaultBackgroundHeight);
                    }
                    break;
                case POSITION_BOTTOM_RIGHT:
                    mRectF.right = mMeasuredWidth - mMessageHintMarginRight;
                    mRectF.bottom = mMeasuredHeight - mMessageHintMarginBottom;
                    mRectF.top = mMeasuredHeight - mMessageHintMarginBottom - mDefaultBackgroundHeight;
                    if (isSelfAdaption) {
                        if (mMessageHintTextContent.length() <= DEFAULT_LENGTH) {
                            mRectF.left = mMeasuredWidth - mMessageHintMarginRight - mDefaultBackgroundHeight;
                        } else {
                            mRectF.left = mMeasuredWidth - mMessageHintMarginRight - mTextContentRect.width() - mDefaultBackgroundHeight / 2;
                        }
                    } else {
                        mRectF.left = mMeasuredWidth - mMessageHintMarginRight - mDefaultBackgroundHeight;

                    }
                    break;
                default:
                    mRectF.top = mMessageHintMarginTop;
                    mRectF.bottom = mMessageHintMarginTop + mDefaultBackgroundHeight;
                    mRectF.right = mMeasuredWidth - mMessageHintMarginRight;
                    if (isSelfAdaption) {
                        if (mMessageHintTextContent.length() <= DEFAULT_LENGTH) {
                            mRectF.left = mMeasuredWidth - (mMessageHintMarginRight + mDefaultBackgroundHeight);
                        } else {
                            mRectF.left = mMeasuredWidth - (mMessageHintMarginRight + mTextContentRect.width() + mDefaultBackgroundHeight / 2);
                        }
                    } else {
                        mRectF.left = mMeasuredWidth - (mMessageHintMarginRight + mDefaultBackgroundHeight);
                    }
            }
        }
        return mRectF;
    }


    //初始化画笔
    private void initPaint() {
        //绘制背景画笔
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setColor(mMessageHintBackgroundColor);
        //绘制文字画笔
        mTextPaint = new TextPaint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(mMessageHintTextColor);
        mTextPaint.setTextSize(mMessageHintTextSize);
        mTextPaint.setTextAlign(TextPaint.Align.CENTER);
    }


    /**
     * 初始默认属性
     */
    private void initDefaultAttrs() {
        //默认文字颜色为白色
        mMessageHintTextColor = Color.WHITE;
        //默认文字大小12SP
        mMessageHintTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics());
        //默认提示文字背景颜色红色
        mMessageHintBackgroundColor = Color.RED;
        //默认提示文字位置在右上角
        mMessageHintPosition = POSITION_TOP_RIGHT;
        //默认开启文字自适应
        isSelfAdaption = true;
        //默认外边距
        mMessageHintMarginLeft = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics());
        mMessageHintMarginRight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics());
        mMessageHintMarginTop = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics());
        mMessageHintMarginBottom = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics());
    }

    /**
     * 初始化自定义属性
     */
    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomMessageHintContainerView);
        isSelfAdaption = mTypedArray.getBoolean(R.styleable.CustomMessageHintContainerView_customSelfAdaption, isSelfAdaption);
        mMessageHintBackgroundColor = mTypedArray.getColor(R.styleable.CustomMessageHintContainerView_customHintTextBackground, mMessageHintBackgroundColor);
        mMessageHintTextColor = mTypedArray.getColor(R.styleable.CustomMessageHintContainerView_customHintTextColor, mMessageHintTextColor);
        mMessageHintTextSize = mTypedArray.getDimension(R.styleable.CustomMessageHintContainerView_customHintTextSize, mMessageHintTextSize);
        mMessageHintPosition = mTypedArray.getInt(R.styleable.CustomMessageHintContainerView_customHintPosition, mMessageHintPosition);
        mMessageHintMarginLeft = mTypedArray.getDimension(R.styleable.CustomMessageHintContainerView_customHintTextMarginLeft, mMessageHintMarginLeft);
        mMessageHintMarginRight = mTypedArray.getDimension(R.styleable.CustomMessageHintContainerView_customHintTextMarginRight, mMessageHintMarginRight);
        mMessageHintMarginTop = mTypedArray.getDimension(R.styleable.CustomMessageHintContainerView_customHintTextMarginTop, mMessageHintMarginTop);
        mMessageHintMarginBottom = mTypedArray.getDimension(R.styleable.CustomMessageHintContainerView_customHintTextMarginBottom, mMessageHintMarginBottom);
        mTypedArray.recycle();
    }


    /**
     * 测量文字的尺寸
     *
     * @return 一个汉字的矩阵
     */
    private Rect measureTextSize(String content) {
        Rect mRect = null;
        if (!TextUtils.isEmpty(content)) {
            if (mTextPaint != null) {
                mRect = new Rect();
                mTextPaint.getTextBounds(content, 0, content.length(), mRect);
            }
        }
        return mRect;
    }

    /**
     * 设置提示消息数
     *
     * @param number 提示数
     */
    public void setMessageNumber(int number) {
        this.mMessageHintTextContent = String.valueOf(number);
        invalidate();
    }

    /**
     * 设置背景根据内容自适应
     *
     * @param isSelfAdaption 是否开启自适应
     */
    public void setSelfAdaption(boolean isSelfAdaption) {
        this.isSelfAdaption = isSelfAdaption;
        invalidate();
    }

    /**
     * 设置消息相对容器的位置
     *
     * @param messageHintPosition 位置
     *                            <p> See
     *                            {@link #POSITION_TOP_RIGHT 右上角},
     *                            {@link #POSITION_BOTTOM_LIFT 左下角},
     *                            {@link #POSITION_BOTTOM_RIGHT 右下角},
     *                            {@link #POSITION_TOP_LIFT 左上角}
     */
    public void setMessageHintPosition(int messageHintPosition) {
        this.mMessageHintPosition = messageHintPosition;
        invalidate();
    }

    /**
     * 获取提示消息数
     *
     * @return 消息数
     */
    public int getMessageHintCount() {
        if (TextUtils.isEmpty(mMessageHintTextContent)) {
            return 0;
        }
        return Integer.parseInt(mMessageHintTextContent);
    }

    /**
     * 获取自适应状态
     *
     * @return 状态
     */
    public boolean getSelfAdaptionStatus() {
        return isSelfAdaption;
    }
}

自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomMessageHintContainerView">
        <attr name="customHintTextColor" format="color" />
        <attr name="customHintTextSize" format="dimension" />
        <attr name="customHintTextBackground" format="color" />
        <attr name="customSelfAdaption" format="boolean" />
        <attr name="customHintTextMarginLeft" format="dimension" />
        <attr name="customHintTextMarginRight" format="dimension" />
        <attr name="customHintTextMarginTop" format="dimension" />
        <attr name="customHintTextMarginBottom" format="dimension" />
        <attr name="customHintPosition">
            <enum name="top_left" value="101" />
            <enum name="bottom_left" value="102" />
            <enum name="top_right" value="103" />
            <enum name="bottom_right" value="104" />
        </attr>
    </declare-styleable>
</resources>
上一篇下一篇

猜你喜欢

热点阅读