zoukankan      html  css  js  c++  java
  • 消息提醒小红点的实现

    消息提醒小红点的实现
    原创Homilier 发布于2017-10-31 14:52:12 阅读数 1687  收藏


    本人分享一下,自己写的一个消息提醒小红点控件,支持圆、矩形、椭圆、圆角矩形、正方形五种图形样式,可带文字,支持链式操作。

    先看一下实现效果,随便测了几个控件(TextView、ImageView、RadioButton、LinearLayout、RelativeLayout、FrameLayout),不确定其他会不会有问题。

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.RectF;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.Gravity;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.FrameLayout;
    import android.widget.TabWidget;
     
    public class BadgeView extends View {
        protected static final String LOG_TAG = "BadgeView";
        // 该控件的背景图形类型
        public static final int SHAPE_CIRCLE = 1;
        public static final int SHAPE_RECTANGLE = 2;
        public static final int SHAPE_OVAL = 3;
        public static final int SHAPTE_ROUND_RECTANGLE = 4;
        public static final int SHAPE_SQUARE = 5;
        // 该框架内容的文本画笔
        private Paint mTextPaint;
        // 该控件的背景画笔
        private Paint mBgPaint;
     
        private int mHeight = 0;
        private int mWidth = 0;
        private int mBackgroundShape = SHAPE_CIRCLE;
        private int mTextColor = Color.WHITE;
        private int mTextSize;
        private int mBgColor = Color.RED;
        private String mText = "";
        private int mGravity = Gravity.RIGHT | Gravity.TOP;
        private RectF mRectF;
        private float mtextH;
        private boolean mIsShow = false;
     
        public BadgeView(Context context) {
            this(context, null);
        }
     
        public BadgeView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
     
        public BadgeView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
     
            mRectF = new RectF();
     
            mTextSize = dip2px(context, 1);
            mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mTextPaint.setColor(mTextColor);
            mTextPaint.setStyle(Paint.Style.FILL);
            mTextPaint.setTextSize(mTextSize);
            mTextPaint.setTextAlign(Paint.Align.CENTER);
            mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mBgPaint.setColor(mBgColor);
            mBgPaint.setStyle(Paint.Style.FILL);
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                    FrameLayout.LayoutParams.WRAP_CONTENT,
                    FrameLayout.LayoutParams.WRAP_CONTENT);
            params.gravity = mGravity;
            setLayoutParams(params);
        }
     
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            mRectF.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
            Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
            mtextH = fontMetrics.descent - fontMetrics.ascent;
            switch (mBackgroundShape) {
                case SHAPE_CIRCLE:
                    canvas.drawCircle(getMeasuredWidth() / 2f,
                            getMeasuredHeight() / 2f, getMeasuredWidth() / 2, mBgPaint);
                    canvas.drawText(mText, getMeasuredWidth() / 2f, getMeasuredHeight()
                            / 2f + (mtextH / 2f - fontMetrics.descent), mTextPaint);
                    break;
                case SHAPE_OVAL:
     
                    canvas.drawOval(mRectF, mBgPaint);
                    canvas.drawText(mText, getMeasuredWidth() / 2f, getMeasuredHeight()
                            / 2f + (mtextH / 2f - fontMetrics.descent), mTextPaint);
                    break;
                case SHAPE_RECTANGLE:
                    canvas.drawRect(mRectF, mBgPaint);
                    canvas.drawText(mText, getMeasuredWidth() / 2f, getMeasuredHeight()
                            / 2f + (mtextH / 2f - fontMetrics.descent), mTextPaint);
                    break;
                case SHAPE_SQUARE:
                    int sideLength = Math.min(getMeasuredHeight(), getMeasuredWidth());
                    mRectF.set(0, 0, sideLength, sideLength);
                    canvas.drawRect(mRectF, mBgPaint);
                    canvas.drawText(mText, sideLength / 2f, sideLength / 2f
                            + (mtextH / 2f - fontMetrics.descent), mTextPaint);
                    break;
                case SHAPTE_ROUND_RECTANGLE:
                    canvas.drawRoundRect(mRectF, dip2px(getContext(), getMeasuredWidth()/2),
                            dip2px(getContext(), getMeasuredWidth()/2), mBgPaint);
                    canvas.drawText(mText, getMeasuredWidth() / 2f, getMeasuredHeight()
                            / 2f + (mtextH / 2f - fontMetrics.descent), mTextPaint);
                    break;
            }
     
        }
     
        /**
         * 设置该控件的背景颜色
         *
         * @param color
         *            背景颜色
         * @return BadgeView
         */
        public BadgeView setBadgeBackgroundColor(int color) {
            mBgColor = color;
            mBgPaint.setColor(color);
            invalidate();
            return this;
        }
     
        /**
         * 设置该控件的背景图形
         *
         * @param shape
         *            图形
         * @return
         */
        public BadgeView setBackgroundShape(int shape) {
            mBackgroundShape = shape;
            invalidate();
            return this;
        }
     
        /**
         * 设置该控件的宽
         *
         * @param width
         *            宽
         * @return BadgeView
         */
        public BadgeView setWidth(int width) {
            this.mWidth = width;
            this.setBadgeLayoutParams(width, mHeight);
            return this;
     
        }
     
        /**
         * 设置该控件的高
         *
         * @param height
         *            高
         * @return BadgeView
         */
        public BadgeView setHeight(int height) {
            this.mHeight = height;
            this.setBadgeLayoutParams(mWidth, height);
            return this;
        }
     
        /**
         * 设置该控件的高和宽
         *
         * @param width
         *            宽
         * @param height
         *            高
         * @return
         */
        public BadgeView setBadgeLayoutParams(int width, int height) {
            this.mWidth = width;
            this.mHeight = height;
            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
            params.width = dip2px(getContext(), width);
            params.height = dip2px(getContext(), height);
            setLayoutParams(params);
            return this;
        }
     
        /**
         * 设置该控件的位置
         *
         * @param gravity
         *            位置
         * @return BadgeView
         */
        public BadgeView setBadgeGravity(int gravity) {
            mGravity = gravity;
            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
            params.gravity = gravity;
            setLayoutParams(params);
            return this;
        }
     
        /**
         * 设置该控件的高和宽、位置
         *
         * @param width
         *            宽
         * @param height
         *            高
         * @param gravity
         *            位置
         * @return BadgeView
         */
        public BadgeView setBadgeLayoutParams(int width, int height, int gravity) {
            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
            params.width = dip2px(getContext(), width);
            params.height = dip2px(getContext(), height);
            setLayoutParams(params);
            setBadgeGravity(gravity);
            return this;
        }
     
        /**
         * 设置该控件的文本大小
         *
         * @param size
         *            文本大小(sp)
         * @return
         */
        public BadgeView setTextSize(int size) {
            mTextSize = sp2px(getContext(), size);
            mTextPaint.setTextSize(sp2px(getContext(), size));
            invalidate();
            return this;
        }
     
        /**
         * 设置该控件的文本颜色
         *
         * @param color
         *            文本颜色
         * @return BadgeView
         */
        public BadgeView setTextColor(int color) {
            mTextColor = color;
            mTextPaint.setColor(color);
            invalidate();
            return this;
        }
     
        /**
         * 设置该控件的文本是否为粗体
         *
         * @param flag
         */
        public void setBadgeBoldText(boolean flag) {
            mTextPaint.setFakeBoldText(flag);
            invalidate();
        }
     
        /**
         * 设置该控件要显示的整数文本
         *
         * @param count
         *            要显示的整数文本
         * @return BadgeView
         */
        public BadgeView setBadgeText(int count) {
            mText = String.valueOf(count);
            invalidate();
            return this;
        }
     
        /**
         * 设置该控件要显示的整数文本数字,超过指定上限显示为指定的上限内容
         *
         * @param count
         *            要显示的整数文本
         * @param maxCount
         *            数字上限
         * @param text
         *            超过上限要显示的字符串文本
         * @return BadgeView
         */
        public BadgeView setBadgeText(int count, int maxCount, String text) {
            if (count <= maxCount) {
                mText = String.valueOf(count);
            } else {
                mText = text;
            }
            invalidate();
            return this;
        }
        /**
         * 设置该控件要显示的字符串文本
         *
         * @param text
         *            要显示的字符串文本
         * @return BadgeView
         */
        public BadgeView setBadgeText(String text) {
            mText = text;
            invalidate();
            return this;
        }
        /**
         * 设置绑定的控件
         *
         * @param view
         *            要绑定的控件
         * @return BadgeView
         */
        public BadgeView setBindView(View view) {
            mIsShow = true;
            if (getParent() != null)
                ((ViewGroup) getParent()).removeView(this);
            if (view == null)
                return this;
            if (view.getParent() instanceof FrameLayout) {
                ((FrameLayout) view.getParent()).addView(this);
            } else if (view.getParent() instanceof ViewGroup) {
                ViewGroup parentContainer = (ViewGroup) view.getParent();
                int viewIndex = ((ViewGroup) view.getParent()).indexOfChild(view);
                ((ViewGroup) view.getParent()).removeView(view);
                FrameLayout container = new FrameLayout(getContext());
                ViewGroup.LayoutParams containerParams = view.getLayoutParams();
                container.setLayoutParams(containerParams);
                container.setId(view.getId());
                view.setLayoutParams(new ViewGroup.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT));
                container.addView(view);
                container.addView(this);
                parentContainer.addView(container, viewIndex);
            } else if (view.getParent() == null) {
                Log.e(LOG_TAG, "View must have a parent");
            }
            return this;
        }
        /**
         * 设置绑定的控件
         *
         * @param view 要绑定的控件
         * @param tabIndex 要绑定的控件的子项
         */
        public void setBindView(TabWidget view, int tabIndex) {
            View tabView = view
                    .getChildTabViewAt(tabIndex);
            this.setBindView(tabView);
        }
        /**
         * 移除绑定的控件
         *
         * @return BadgeView
         */
        public boolean removebindView() {
            if (getParent() != null) {
                mIsShow = false;
                ((ViewGroup) getParent()).removeView(this);
                return true;
            }
            return false;
        }
        /**
         * @return 改控件的显示状态
         */
        public boolean isShow() {
            return mIsShow;
        }
        /**
         * @return 控件的字符串文本
         */
        public String getBadgeText() {
            return mText;
        }
        private int dip2px(Context context, int dip) {
            return (int) (dip
                    * getContext().getResources().getDisplayMetrics().density + 0.5f);
        }
        private int sp2px(Context context, float spValue) {
            final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
            return (int) (spValue * fontScale + 0.5f);
        }
    }
    可自由定制自己喜欢的控件,为了方便使用这里还采用工厂模式封装一些基本方法,如下:
    import android.content.Context;
    import android.view.Gravity;
     
    public class BadgeFactory {
     
        public static BadgeView create(Context context) {
            return new BadgeView(context);
        }
        
        public static BadgeView createDot(Context context) {
            return new BadgeView(context).setBadgeLayoutParams(10, 10)
                    .setTextSize(0)
                    .setBadgeGravity(Gravity.RIGHT | Gravity.TOP)
                    .setBackgroundShape(BadgeView.SHAPE_CIRCLE);
        }
     
        public static BadgeView createCircle(Context context) {
            return new BadgeView(context).setBadgeLayoutParams(16, 16)
                    .setTextSize(12)
                    .setBadgeGravity(Gravity.RIGHT | Gravity.TOP)
                    .setBackgroundShape(BadgeView.SHAPE_CIRCLE);
        }
     
        public static BadgeView createRectangle(Context context) {
            return new BadgeView(context).setBadgeLayoutParams(2, 20)
                    .setTextSize(12)
                    .setBadgeGravity(Gravity.RIGHT | Gravity.TOP)
                    .setBackgroundShape(BadgeView.SHAPE_RECTANGLE);
        }
     
        public static BadgeView createOval(Context context) {
            return new BadgeView(context).setBadgeLayoutParams(25, 20)
                    .setTextSize(12)
                    .setBadgeGravity(Gravity.RIGHT | Gravity.TOP)
                    .setBackgroundShape(BadgeView.SHAPE_OVAL);
        }
     
        public static BadgeView createSquare(Context context) {
            return new BadgeView(context).setBadgeLayoutParams(20, 20)
                    .setTextSize(12)
                    .setBadgeGravity(Gravity.RIGHT | Gravity.TOP)
                    .setBackgroundShape(BadgeView.SHAPE_SQUARE);
        }
     
        public static BadgeView createRoundRect(Context context) {
            return new BadgeView(context).setBadgeLayoutParams(25, 20)
                    .setTextSize(12)
                    .setBadgeGravity(Gravity.RIGHT | Gravity.TOP)
                    .setBackgroundShape(BadgeView.SHAPTE_ROUND_RECTANGLE);
        }
        
    }

    源码传送门
    ————————————————
    版权声明:本文为CSDN博主「Homilier」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/Honiler/article/details/78403354

  • 相关阅读:
    155. 最小栈
    160. 相交链表
    PAT 1057 Stack
    PAT 1026 Table Tennis
    PAT 1017 Queueing at Bank
    PAT 1014 Waiting in Line
    PAT 1029 Median
    PAT 1016 Phone Bills
    PAT 1010 Radix
    PAT 1122 Hamiltonian Cycle
  • 原文地址:https://www.cnblogs.com/grj001/p/12223006.html
Copyright © 2011-2022 走看看