一行代码实现vip标志的显示

news2025/4/27 19:20:03

需求说明

在项目中,后期添加了一种用户类型。需要再用户头像右下角显示一个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);
        }


    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1681585.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二进制部署Kubernetes集群——单Master和Node组件

前言 本文将介绍如何使用二进制文件手动搭建 Kubernetes v1.20 集群。通过这种方法&#xff0c;我们可以更好地理解 Kubernetes 的内部工作原理&#xff0c;并具备更大的灵活性和控制权。下面将逐步构建 Kubernetes 集群&#xff0c;并进一步了解其各个组件之间的交互和配置。…

【python量化交易】—— 双均线择时策略 - Qteasy自定义交易策略【附源码】

使用qteasy自定义并回测双均线交易策略 使用qteasy自定义并回测一个双均线择时策略策略思想导入qteasy模块创建一个新的策略回测交易策略&#xff0c;查看结果 使用qteasy自定义并回测一个双均线择时策略 我们今天使用qteasy来回测一个双均线择时交易策略&#xff0c;qteasy是…

kettle从入门到精通 第六十一课 ETL之kettle 任务调度器,轻松使用xxl-job调用kettle中的job和trans

想真正学习或者提升自己的ETL领域知识的朋友欢迎进群&#xff0c;一起学习&#xff0c;共同进步。若二维码失效&#xff0c;公众号后台加我微信入群&#xff0c;备注kettle。 1、大家都知道kettle设计的job流程文件有个缺点&#xff1a;只能设置简单的定时任务&#xff0c;无法…

React 第三十七章 Scheduler 最小堆算法

在 Scheduler 中&#xff0c;使用最小堆的数据结构在对任务进行排序。 // 两个任务队列 var taskQueue: Array<Task> []; var timerQueue: Array<Task> [];push(timerQueue, newTask); // 像数组中推入一个任务 pop(timerQueue); // 从数组中弹出一个任务 time…

HNU-算法设计与分析-作业3

第三次作业【动态规划】 文章目录 第三次作业【动态规划】<1>算法实现题 3-1 独立任务最优解问题<2>算法实现题 3-4 数字三角形问题<3>算法实现题 3-8 最小m段和问题<4>算法实现题 3-25 m处理器问题 <1>算法实现题 3-1 独立任务最优解问题 ▲问…

Windows 安装mysql 和 Redis

mysql Windows 图形界面安装&#xff1a; 下载mysql https://dev.mysql.com/downloads/ 1.下载完成后,找到文件双击安装程序 2. 等待一段时间&#xff0c; 选择默认&#xff0c;点击next 3. 选择安装目录 下载mysql产品 安装mysql产品 产品配置向导 安装…

数据库-索引结构(B-Tree,B+Tree,Hash,二叉树)

文章目录 索引结构有哪些&#xff1f;二叉树详解&#xff1f;B-Tree详解?BTree详解&#xff1f;Hash详解&#xff1f;本篇小结 更多相关内容可查看 索引结构有哪些&#xff1f; MySQL的索引是在存储引擎层实现的&#xff0c;不同的存储引擎有不同的索引结构&#xff0c;主要包…

Echart-折线图根据区间设置折线的样式

根据X轴区间设置折线样式 完整配置如下&#xff1a; option {xAxis: {type: category,data: [Mon, Tue, Wed, Thu, Fri, Sat, Sun]},yAxis: {type: value},series: [{data: [150, 230, 224, 218, 135, 147, 260],type: line}],//【注】&#xff1a;如果一个图中有多个折线&a…

ROS从入门到精通4-3:制作Docker镜像文件Dockerfile

目录 0 专栏介绍1 为什么需要Dockerfile&#xff1f;2 Dockerfile书写原则3 Dockerfile常用指令3.1 FROM3.2 MAINTAINER3.3 RUN3.4 ADD3.5 COPY3.6 CMD3.7 ENV3.8 EXPOSE3.9 WORKDIR3.10 ARG 4 Dockerfile构建ROS工程实例 0 专栏介绍 本专栏旨在通过对ROS的系统学习&#xff0…

springboot3.2.5+mybatis-plus导致启动报错

公司新的项目升级到了springboot3.x后&#xff0c;步步是坑&#xff0c;坑坑不同&#xff0c;各种疑难杂症层出不穷&#xff0c;让老中医也也苦不堪言&#xff0c;java的生态圈真让人无语&#xff0c;你们升级能不能认真些互相兼顾一下&#xff1f; 这次的项目用了springboot3…

Python自学之路--004:Python使用注意点(原始字符串‘r’\字符转换\‘wb’与‘w区别’\‘\‘与‘\\’区别)

目录 1、原始字符串‘r’ 2、字符转换问题 3、open与write函数’wb’与’w’区分 4、Python里面\与\\的区别 1、原始字符串‘r’ 以前的脚本通过Python2.7写的&#xff0c;通过Python3.12去编译发现不通用了&#xff0c;其实也是从一个初学者的角度去看待这些问题。 其中的\…

春风拂面,深入浅出:Bean 处理器揭秘 Spring Boot 启动之谜

春风拂面&#xff0c;深入浅出&#xff1a;Bean 处理器揭秘 Spring Boot 启动之谜 在 Spring Boot 开发中&#xff0c;Bean 处理器扮演着至关重要的角色&#xff0c;犹如幕后英雄般默默地为应用启动过程添砖加瓦。然而&#xff0c;对于许多开发者来说&#xff0c;Bean 处理器依…

文档分类FastText模型 (pytorch实现)

文档分类FastText FastText简介层次softmaxN-gram特征FastText代码&#xff08;文档分类&#xff09; FastText简介 FastText与之前介绍过的CBOW架构相似&#xff0c;我们先来会议一下CBOW架构&#xff0c;如下图&#xff1a; CBOW的任务是通过上下文去预测中间的词&#xff0…

项目管理重点及笔记【太原理工大学24年】

为了自己复习写的&#xff0c;可能会有不清楚&#xff0c;可以选择性看可以讨论&#xff0c;但别骂我写的什么烂东西&#xff0c;&#xff0c;&#xff0c;&#xff08;电脑看排版更好看些&#xff09; 目录 一、IT项目管理概述 二、IT项目组织环境与管理过程 三、整体管理 四、…

使用httpx异步获取高校招生信息:一步到位的代理配置教程

概述 随着2024年中国高考的临近&#xff0c;考生和家长对高校招生信息的需求日益增加。了解各高校的专业、课程设置和录取标准对于高考志愿填报至关重要。通过爬虫技术&#xff0c;可以高效地从各高校官网获取这些关键信息。然而&#xff0c;面对大量的请求和反爬机制的挑战&a…

【汇编】算术指令

一、加法指令 &#xff08;一&#xff09;各加法指令的格式及操作 加法指令可做字或字节运算 &#xff08;1&#xff09;加法指令 ADD 格式&#xff1a;ADD DST,SRC执行的操作&#xff1a;(DST) ← (SRC)(DST) &#xff08;2&#xff09;带进位加法指令 ADC 格式&#xf…

【C语言】自定义类型之---结构体超详解(结构体的定义使用、指针结构体,内存对齐,......代码详解)

目录 前言&#xff1a; 一&#xff1a;结构体 1.1&#xff1a;什么是结构体&#xff1f; 1.2&#xff1a;结构体类型的声明 1.3&#xff1a;结构体变量的定义 1.4&#xff1a;结构体的内存对齐 1.5&#xff1a;结构体传参 二&#xff1a;位段 2.1&#xff1a;位段是什…

反爬-简单滑块思路,秒了~

文章目录 找图片的返回包curl 大法获取图片链接ddddocr分析距离看结果秒了~ 本文仅供参考学习&#xff0c;如有侵权&#xff0c;请联系作者删。 目标地址&#xff1a;aHR0cHM6Ly9pZHMuZ2RpdC5lZHUuY24vYXV0aHNlcnZlci9sb2dpbj9zZXJ2aWNlPWh0dHBzOi8vd2JkdC5nZGl0LmVkdS5jbi9zaG…

2024 Google I/O Android 相关内容汇总

2024 Google I/O Android 相关内容汇总 本次 Google I/O 的核心虽然是 AI &#xff0c;但是 Android 也是作为主要议题出现&#xff0c; Android 部分可以简单分为产品和开发相关内容&#xff0c;接下来主要介绍这两部分的相关更新。 重点开始开发相关&#xff0c;内容不少 产…

2010-2024年各地级市社会信用体系建设匹配DID数据

2010-2024年各地级市社会信用体系建设匹配DID数据 1、时间&#xff1a;2010-2024年 2、指标&#xff1a;行政区划代码、年份、所属省份、地区、社会信用体系建设示范区 3、范围&#xff1a;310个地级市 4、来源&#xff1a;国家发改委 5、指标解释&#xff1a; 社会信用体…