当前位置:   article > 正文

Android开源控件viewbadger的原理及使用

viewbadger

viewbadger是github上的一个开源控件,能够以一个小徽章的样式附着在某个view上,通常用于显示未读消息数,典型的如微信、QQ、微博等,地址为:https://github.com/jgilfelt/android-viewbadger。下图为项目主页给出的样式图,可见还是能满足各种需求的。


viewbadger继承自textview,使用起来很简单,项目主页给出的Sample就四行:

  1. View target = findViewById(R.id.target_view);
  2. BadgeView badge = new BadgeView(this, target);
  3. badge.setText("1");
  4. badge.show();

看起来虽然简单,但用起来如果不小心也可能会出现一些意外,造成布局发生错误。我第一次使用时简单地把创建两个badgeview并设置target,却造成了这样的结果:

可见Item中的布局发生了错误,而底部bar的一项没显示出来。以下分别是listview中item的布局和底部bar的布局

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:layout_width="match_parent"
  3. android:layout_height="64dp"
  4. android:clickable="true"
  5. android:id="@+id/layout_root"
  6. android:background="@drawable/item_normal_background"
  7. android:gravity="center_vertical">
  8. <ImageView
  9. android:id="@+id/iv_avatar"
  10. android:layout_width="56dp"
  11. android:layout_height="56dp"
  12. android:src="@drawable/display_picture_default"
  13. />
  14. <TextView
  15. android:id="@+id/tv_name"
  16. android:layout_width="100dp"
  17. android:layout_height="wrap_content"
  18. android:layout_toRightOf="@id/iv_avatar"
  19. android:layout_marginTop="2dp"
  20. android:textSize="14sp"
  21. android:textColor="#000000"
  22. android:ellipsize="end"
  23. android:text="name"
  24. android:lines="1"/>
  25. <TextView
  26. android:id="@+id/tv_content"
  27. android:layout_width="250dp"
  28. android:layout_height="wrap_content"
  29. android:layout_toRightOf="@id/iv_avatar"
  30. android:layout_below="@id/tv_name"
  31. android:layout_marginTop="2dp"
  32. android:textSize="12sp"
  33. android:textColor="#7A7E83"
  34. android:ellipsize="end"
  35. android:text="content"
  36. android:lines="1" />
  37. <TextView
  38. android:id="@+id/tv_time"
  39. android:layout_width="wrap_content"
  40. android:layout_height="wrap_content"
  41. android:layout_alignParentRight="true"
  42. android:layout_alignParentTop="true"
  43. android:layout_marginTop="4dp"
  44. android:layout_marginRight="8dp"
  45. android:textSize="10sp"
  46. android:textColor="#7A7E83"
  47. android:ellipsize="end"
  48. android:text="time"
  49. android:lines="1" />
  50. </RelativeLayout>
<span style="font-family: Arial, Helvetica, sans-serif;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"</span>
  1. xmlns:app="http://schemas.android.com/apk/res-auto"
  2. android:layout_width="match_parent"
  3. android:layout_height="60dp"
  4. android:orientation="horizontal">
  5. <com.example.lbf.imitationofwechat.views.TabItemView
  6. android:id="@+id/tab_item_chats"
  7. android:layout_width="0dp"
  8. android:layout_height="match_parent"
  9. android:layout_weight="1"
  10. app:description="微信"
  11. app:iconNormal="@drawable/chats1"
  12. app:iconSelected="@drawable/chats2"
  13. android:padding="8dp"/>
  14. <com.example.lbf.imitationofwechat.views.TabItemView
  15. android:id="@+id/tab_item_contacts"
  16. android:layout_width="0dp "
  17. android:layout_height="match_parent"
  18. android:layout_weight="1"
  19. android:padding="8dp"
  20. app:description="通讯录"
  21. app:iconNormal="@drawable/contacts1"
  22. app:iconSelected="@drawable/contacts2" />
  23. <com.example.lbf.imitationofwechat.views.TabItemView
  24. android:id="@+id/tab_item_discover"
  25. android:layout_width="0dp "
  26. android:layout_height="match_parent"
  27. android:layout_weight="1"
  28. android:padding="8dp"
  29. app:description="发现"
  30. app:iconNormal="@drawable/discover1"
  31. app:iconSelected="@drawable/discover2" />
  32. <com.example.lbf.imitationofwechat.views.TabItemView
  33. android:id="@+id/tab_item_me"
  34. android:layout_width="0dp "
  35. android:layout_height="match_parent"
  36. android:layout_weight="1"
  37. android:padding="8dp"
  38. app:description="我"
  39. app:iconNormal="@drawable/me1"
  40. app:iconSelected="@drawable/me2" />
  41. </LinearLayout>

主布局分别使用了linearlayout和relativelayout,可以猜测使用了badgeview后对控件的分布造成了影响才导致这样的结果,那么就来看看的badgeview的源码,主要的代码如下:

  1. private void applyTo(View target) {
  2. LayoutParams lp = target.getLayoutParams();
  3. ViewParent parent = target.getParent();
  4. FrameLayout container = new FrameLayout(this.context);
  5. if(target instanceof TabWidget) {
  6. target = ((TabWidget)target).getChildTabViewAt(this.targetTabIndex);
  7. this.target = target;
  8. ((ViewGroup)target).addView(container, new LayoutParams(-1, -1));
  9. this.setVisibility(8);
  10. container.addView(this);
  11. } else {
  12. ViewGroup group = (ViewGroup)parent;
  13. int index = group.indexOfChild(target);
  14. group.removeView(target);
  15. group.addView(container, index, lp);
  16. container.addView(target);
  17. this.setVisibility(8);
  18. container.addView(this);
  19. group.invalidate();
  20. }
  21. }


思路很简单,首先把target从所在的viewgroup中移除,然后创建一个framelayout,把target和badgeview放入framelayout,最后再把framelayout放回原来的viewgroup中,接下来分析为什么会出现那样的结果。
一.  第一个layout中用的是relativelayout,头像的右边有两个textView,分别显示昵称和内容,其位置通过layout_toRightOf="@id/iv_avatar"来确定,因此是依赖于头像的imageview的。根据badgeview的原理,会为头像创建一个新的framelayout,此时头像与两个textView不再属于同一层级了,而layout_toRightOf只能作用在同一层级的view,因此失效了,导致两个textView位于relativelayout 的开头处。解决办法很简单,让两个textView的位置不要依赖于头像的imageview即可。
二.  第二个layout中用的是linearlayout,且四个子view均分其宽度。使用badgeview作用于其中一个item后,同样会创建一个新的framelayout,此framelayout的属性与原来的item相同,因此不会影响其他三个子view的位置,但是原来的子view就不显示了。这是因为原来的子view的宽度设为了0,在新的framelayout中weigh又不起作用,因此宽度为0,自然就不显示了。解决办法也很简单,将原来的四个子view的宽度全设为match_parent,或者为其设置一个最小宽度就可以了。

修改布局后再调整一些样式最后得到的结果如下,还是比较不错的。明白了原理以后,使用badgeview时就需要考虑一下为target新创建一个framelayout后是否会对原来的布局产生影响,这样就不会出错了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/684018
推荐阅读
相关标签
  

闽ICP备14008679号