需求说明
在项目中,后期添加了一种用户类型。需要再用户头像右下角显示一个vip的标志。问题是只要有头像的地方都要显示。而有头像的地方很多,设置到的接口也很多。后面考虑通过一个工具类,将这个功能外挂到原来的业务需要的地方。
实现效果
使用方式
WzhVipView.show(ivAvatar,info);
效果如下,可以在不同大小的头像的右下角添加一个vip的标志还不影响原来的布局
实现原理
以下方法中,有两个参数。第一个是头像对应的控件,第二个是是否是特殊角色的javabean。
通过在ivAvatar外面包裹relativeLayout和添加一个显示vip图片的imageView来实现。第二个参数,通过反射获取其中的字段来判断是否需要显示vip标志。如果第二个参数是boolean类型的就直接用来控制vip标志的显示,兼容性更好。
WzhVipView.show(ivAvatar,info);
相关代码
没什么难度,重点是对ivAvatar的父容器是RelativeLayout的情况下,替换以后。需要对兄弟控件的布局规则进行更新。为什么不直接把替换的布局的id设置为ivAvatar的id。因为在recycleView中。可能需要通过id来复用ivaAvatar。还有个需要注意的地方就是对ivAvatar没有宽高的时候的处理。通过添加监听器实现重新布局。最后还有个就是对反射的处理,需要通过递归的方式来判断第二个对象的父类中有没有需要的字段。提高代码的健壮性。
package com.trs.v8.wzh;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.trs.news.R;
import java.lang.reflect.Field;
/**
* <pre>
* Created by zhuguohui
* Date: 2024/5/15
* Time: 10:29
* Desc:用来显示温州号顶部vip标志的
* </pre>
*/
public class WzhVipView {
/**
* 根据是否是温州号来实现vip标志的显示
*
* @param headView 用户显示头像的view
* @param obj 用户判断是否是温州号的javabean
* 通过判断其内部是否包含mediaAccountId字段,并且值不为空也不为0来实现
* 如果obj是boolean类型的,就直接作为是否是温州号的判断
*/
public static void show(View headView, Object obj) {
//wrap view,通过在headView的外部包裹RelativeLayout来实现
ImageView vipView = wrapViewIfNeed(headView);
boolean isVip = isWzh(obj);
vipView.setVisibility(isVip ? View.VISIBLE : View.GONE);
}
private static boolean isWzh(Object obj) {
if (obj == null) {
return false;
}
if (obj instanceof Boolean) {
return (boolean) obj;
}
try {
Field idField = getFiled(obj.getClass());
idField.setAccessible(true);
Object idObj = idField.get(obj);
if (idObj instanceof String) {
String idStr = (String) idObj;
if (!"".equals(idStr) && !"0".equals(idStr)) {
return true;
}
} else if (idObj instanceof Integer) {
Integer idInt = (Integer) idObj;
return idInt != 0;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private static Field getFiled(Class clazz) {
if (clazz == null || clazz == Object.class) {
return null;
}
try {
return clazz.getDeclaredField("mediaAccountId");
} catch (NoSuchFieldException e) {
e.printStackTrace();
return getFiled(clazz.getSuperclass());
}
}
private static ImageView wrapViewIfNeed(View headView) {
VipParentView wrapLayout = null;
if (headView instanceof VipParentView) {
wrapLayout = (VipParentView) headView;
} else {
ViewParent parent = headView.getParent();
if (parent instanceof VipParentView) {
wrapLayout = (VipParentView) parent;
}
if (wrapLayout == null) {
//没有被适配过。开始适配
wrapLayout = new VipParentView(headView.getContext());
wrapLayout.setClipChildren(false);
if (parent instanceof ViewGroup) {
//获取headView的宽高
int width = headView.getWidth();
if (width == 0) {
addListenerToReSizeVipView(headView, wrapLayout);
}
//根据宽高计算vip需要显示的宽高
int vipSize = (int) (width * 0.46);
ViewGroup group = (ViewGroup) parent;
group.setClipChildren(false);
ViewGroup.LayoutParams layoutParams = headView.getLayoutParams();
wrapLayout.setLayoutParams(layoutParams);
int index = group.indexOfChild(headView);
group.removeView(headView);
RelativeLayout.LayoutParams headParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
headParams.addRule(RelativeLayout.CENTER_IN_PARENT);
headView.setLayoutParams(headParams);
wrapLayout.addView(headView);
ImageView vipView = new ImageView(headView.getContext());
vipView.setImageResource(R.drawable.ic_header_vip);
vipView.setId(R.id.vip_view);
RelativeLayout.LayoutParams vipParams = new RelativeLayout.LayoutParams(vipSize, vipSize);
vipParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
vipParams.addRule(RelativeLayout.ALIGN_PARENT_END);
vipView.setLayoutParams(vipParams);
wrapLayout.addView(vipView);
wrapLayout.setId(R.id.vip_parent_view);
updateRulesIfGroupIsRelativeLayout(group, headView.getId(), wrapLayout.getId());
group.addView(wrapLayout, index);
} else {
return new ImageView(headView.getContext());
}
}
}
return (ImageView) wrapLayout.findViewById(R.id.vip_view);
}
private static void updateRulesIfGroupIsRelativeLayout(ViewGroup group, int headViewId, int wrapLayoutId) {
if (!(group instanceof RelativeLayout)) {
return;
}
int count = group.getChildCount();
for (int i = 0; i < count; i++) {
View childAt = group.getChildAt(i);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) childAt.getLayoutParams();
RelativeLayout.LayoutParams newLayoutPrams = new RelativeLayout.LayoutParams(layoutParams.width, layoutParams.height);
newLayoutPrams.setMargins(layoutParams.leftMargin, layoutParams.topMargin,
layoutParams.rightMargin, layoutParams.bottomMargin);
int[] rules = layoutParams.getRules();
for (int j = 0; j < rules.length; j++) {
if (rules[j] == headViewId) {
newLayoutPrams.addRule(j, wrapLayoutId);
} else if (rules[j] != 0) {
newLayoutPrams.addRule(j, rules[j]);
}
}
childAt.setLayoutParams(newLayoutPrams);
}
}
private static void addListenerToReSizeVipView(View headView, RelativeLayout wrapLayout) {
headView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int width = headView.getWidth();
if (width == 0) {
return;
}
int vipSize = (int) (width * 0.46);
View vipView = wrapLayout.findViewById(R.id.vip_view);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) vipView.getLayoutParams();
layoutParams.width = vipSize;
layoutParams.height = vipSize;
vipView.setLayoutParams(layoutParams);
headView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
private static class VipParentView extends RelativeLayout {
public VipParentView(Context context) {
super(context);
}
}
}