Android实现控件右上⾓显⽰消息数量⽓泡(badge)
现在qq或者,甚⾄微博都有⼀个功能,就是在⽤户有未读消息时,在桌⾯图标右上⾓显⽰⼀个红⾊的⼩⽓泡,⾥⾯显⽰未读消息数量,在桌⾯图标显⽰的功能主要是利⽤⼴播来通知launcher,具体实现⽹上有不少内容,本⽂简单介绍下在应⽤内部的实现;
⾸先,右上的圆形⽓泡其实是⼀个textview,参考⽹上⼀个⽐较流⾏的开源代码(地址github/stefanjauker/BadgeView),该项⽬提供了⼀个jar包,不过这种⼩功能应该代码量不多,打开源码发现就是⼀个⾃定义view类。
该扩展使⽤⽅法也相当简单,⾸先确定要添加⽓泡的view ,然后
[java]
1. final BadgeView badgeView = new BadgeView(this);
2.        badgeView.setTargetView(target);
3.        badgeView.setBadgeCount(3);
显⽰效果如图:
下⾯分析⼀下源码:
[java]
1. public class BadgeView extends TextView {
html实现用户注册登录代码
2.
3.    private boolean mHideOnNull = true;
4.
5.    public BadgeView(Context context) {
6.        this(context, null);
7.    }
8.
9.    public BadgeView(Context context, AttributeSet attrs) {
10.        this(context, attrs, android.ViewStyle);
11.    }
12.
13.    public BadgeView(Context context, AttributeSet attrs, int defStyle) {
14.        super(context, attrs, defStyle);
15.
16.        init();
17.    }
该view的构造⽅法,其最终都调⽤了init()⽅法,这个⽅法主要是对本⾝设置了下layout属性,如下:
[java]
1. private void init() {
2.        if (!(getLayoutParams() instanceof LayoutParams)) {
3.            LayoutParams layoutParams =
4.                    new LayoutParams(
5.                            ViewGroup.LayoutParams.WRAP_CONTENT,
6.                            ViewGroup.LayoutParams.WRAP_CONTENT,
7.                            Gravity.RIGHT | Gravity.TOP);
8.            setLayoutParams(layoutParams);
9.        }
10.
11.        // set default font
12.        setTextColor(Color.WHITE);
13.        setTypeface(Typeface.DEFAULT_BOLD);
14.        setTextSize(TypedValue.COMPLEX_UNIT_SP, 17);
15.        setPadding(dip2Px(5), dip2Px(1), dip2Px(5), dip2Px(1));
16.
17.        // set default background
18.        setBackground(9, Color.parseColor("#d3321b"));
19.
20.        setGravity(Gravity.CENTER);
21.
22.        // default values
23.        setHideOnNull(true);
24.        setBadgeCount(0);
25.    }
然后最为关键的就是设置targe view的⽅法,在这个⽅法⾥为⽬标view添加了当前的textview作为⽓泡:
[java]
1. public void setTargetView(View target) {
2.        if (getParent() != null) {
3.            ((ViewGroup) getParent()).removeView(this);
4.        }
5.
6.        if (target == null) {
7.            return;
8.        }
9.
10.        if (Parent() instanceof FrameLayout) {
11.            ((FrameLayout) Parent()).addView(this);
12.
13.        } else if (Parent() instanceof ViewGroup) {
14.            // use a new Framelayout container for adding badge
15.            ViewGroup parentContainer = (ViewGroup) Parent();
16.            int groupIndex = parentContainer.indexOfChild(target);
17.            veView(target);
18.
19.          <strong> FrameLayout badgeContainer = new FrameLayout(getContext());</strong>
20.            ViewGroup.LayoutParams parentLayoutParams = LayoutParams();
21.
22.            badgeContainer.setLayoutParams(parentLayoutParams);
23.            target.setLayoutParams(new ViewGroup.LayoutParams(
24.                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
25.
26.            parentContainer.addView(badgeContainer, groupIndex, parentLayoutParams);
27.            badgeContainer.addView(target);
28.
29.            badgeContainer.addView(this);
30.        } else if (Parent() == null) {
31.            Log.e(getClass().getSimpleName(), "ParentView is needed");
32.        }
33.
34.    }
很明显,这个扩展的实现⽅式就是frameLayout,当设置target时,根据target的⽗控件的类型进⾏不同的设置,⽐如,当⽗控件就是framelayout时,直接添加,当⽗控件不是frameLayout时,记录下target在⽗控件中的位置,
[java]
1. int groupIndex = parentContainer.indexOfChild(target);
然后新建⼀个frameLayout,
[java]
1. FrameLayout badgeContainer = new FrameLayout(getContext());
将target与⽓泡的textview⼀同添加进去,最后在添加到初始⽗控件的groupIndex位置就可以了。
不过这种⽅式有些问题,在判断⽗控件为frameLayout时如果⽗控件指定了宽⾼,就会出现问题,⽐如当布局⽂件是:
[html]
1. <FrameLayout
2.        android:layout_width="match_parent"
3.        android:layout_height="100dp">
4.
5.        <Button
6.            android:id="@+id/frame"
7.            android:layout_width="wrap_content"
8.            android:layout_height="wrap_content"
9.            android:text="frameLayout" />
10.    </FrameLayout>
显⽰效果为:
相当尴尬
不过按照这个原理,我们要实现⽓泡只要在布局中⼿动修改反⽽更简单(个⼈认为),只需修改target 为⼀个复合的view完全没问题,只需要在⽗控件中添加⼀个:clipChildren="false" 属性,保证⽓泡可以再⽗控件之外显⽰

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。