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小时内删除。
发表评论