• 注解数据类型
    注解是写在.java文件中,使用@interface作为关键字, 所以注解也是Java的一种数据类型,从广泛的定义来说,Class、Interface、Enum、Annotation都属于Class类型。

@Documented: 用于标记在生成javadoc时是否将注解包含进去

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

@Target:用于定义注解可以在什么地方使用

TYPE : 类、接口或enum声明
		FIELD: 域(属性)声明
		METHOD: 方法声明
		PARAMETER: 参数声明
		CONSTRUCTOR: 构造方法声明
		LOCAL_VARIABLE:局部变量声明
		ANNOTATION_TYPE:注释类型声明
		PACKAGE: 包声明

@Retention:注解的保留位置(枚举RetentionPolicy),RetentionPolicy可选值:

SOURCE:注解仅存在于源码中,在class字节码文件中不包含
CLASS:默认的保留策略,注解在class字节码文件中存在,但运行时无法获得
RUNTIME:注解在class字节码文件中存在,在运行时可以通过反射获取到

@Inherited:声明子类可以继承此注解,如果一个类A使用此注解,则类A的子类也继承此注解,可以看到@Target(ElementType.ANNOTATION_TYPE),它只可以作用在注释类型的声明

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

下面是一个自定义注解的例子。底部弹出dialog里边是一个ListView,通过传入接口返回不同的bean对象添加注解,方便展示,不用再处理不用接口返回的数据。
adapter和一些动画就不贴出来了有需要的可以下载demo

1:需要展示的item

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ShowItemAnn {

}

2:bean类

class User {
    @ShowItemAnn //列表中想展示name属性
    var name: String? = null
    var age: String? = null
    var sex: String? = null
}

3:Dialog ,建造者模式,默认最多底部弹框4个item 可以通过设置pageShowItems 属性改变,通过获取并识别对应的注解,parseList通过反射获取要获取的值。

/**
 * 注:
 * bean需要显示的字段上添加 @ShowItemAnn 注解 并需要写 该字段的 get 方法
 */
public class BottomListDialog extends Dialog {
    private Context context;

    private BottomListDialog(@NonNull Context context) {
        this(context, R.style.bottom_list_dialog_theme);
    }

    public BottomListDialog(@NonNull Context context, int themeResId) {
        super(context, themeResId);
        this.context = context;
        setParams();
        initView();
    }

    private void setParams() {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.dialog_bottom_list);
    }


    private TextView mTitleTv;
    private ListView mListView;

    private void initView() {
        mTitleTv = findViewById(R.id.bottom_title_tv);
        mListView = findViewById(R.id.dialog_bottom_list);
    }

    /**
     * 封装参数类
     */
    private static class P<T> {
        private Context context;
        private String title = null;
        private boolean cancelable = true;
        private boolean canceledOnTouchOutside = true;
        private AdapterView.OnItemClickListener onItemClickListener;
        private List<T> items;
        private int pageShowItems = 4;//组多同时展示几条列表数据,多的可以滑动
        private int activePosition = -1;
    }

    public static class Builder {
        private P p;

        public Builder(Context context) {
            p = new P();
            p.context = context;
        }

        public Builder setActivePosition(int activePosition) {
            p.activePosition = activePosition;
            return this;
        }

        public Builder setSiglePageShowItems(int num) {
            p.pageShowItems = num;
            return this;
        }

        public Builder setTitle(String title) {
            p.title = title;
            return this;
        }

        public <T> Builder setItems(List<T> items) {
            p.items = items;
            return this;
        }

        public Builder setCancelable(boolean setCancelable) {
            p.cancelable = setCancelable;
            return this;
        }

        public Builder setCanceledOnTouchOutside(boolean setCanceledOnTouchOutside) {
            p.canceledOnTouchOutside = setCanceledOnTouchOutside;
            return this;
        }

        public Builder setOnItemClickListener(AdapterView.OnItemClickListener onItemClickListener) {
            p.onItemClickListener = onItemClickListener;
            return this;
        }

        private BottomListDialog create() {
            BottomListDialog bottomDialog = new BottomListDialog(p.context);
            bottomDialog.setCancelable(p.cancelable);
            bottomDialog.setCanceledOnTouchOutside(p.canceledOnTouchOutside);

            if (p.title == null) {
                bottomDialog.mTitleTv.setVisibility(View.GONE);
            } else {
                bottomDialog.mTitleTv.setVisibility(View.VISIBLE);
                bottomDialog.mTitleTv.setText(p.title);
            }
            if (p.items != null && p.items.size() > 0) {
                BottomListDialogAdapter adapter = new BottomListDialogAdapter(p.context, parseList(p.items), p.activePosition);
                int totalHeight = 0;
                int num = adapter.getCount() > p.pageShowItems ? p.pageShowItems : adapter.getCount();
                for (int i = 0; i < num; i++) {
                    View listItem = adapter.getView(i, null, bottomDialog.mListView);
                    //计算子项View 的宽高 //统计所有子项的总高度
                    listItem.measure(0, 0);
                    totalHeight += listItem.getMeasuredHeight() + bottomDialog.mListView.getDividerHeight();
                }

                ViewGroup.LayoutParams params = bottomDialog.mListView.getLayoutParams();
                params.height = totalHeight;
                bottomDialog.mListView.setLayoutParams(params);
                bottomDialog.mListView.setAdapter(adapter);
                bottomDialog.mListView.setOnItemClickListener(p.onItemClickListener);
            }
            Window window = bottomDialog.getWindow();
            WindowManager.LayoutParams lp = window.getAttributes();
            lp.gravity = Gravity.BOTTOM;
            lp.width = WindowManager.LayoutParams.MATCH_PARENT;
            lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
            lp.gravity = Gravity.BOTTOM;
            bottomDialog.getWindow().setAttributes(lp);

            return bottomDialog;
        }


        public BottomListDialog show() {
            BottomListDialog dialog = create();
            dialog.show();
            return dialog;
        }
    }


    private static <T> List<ItemBean> parseList(List<T> lists) {
        if (lists == null) {
            return null;
        }

        List<ItemBean> items = new ArrayList<>();
        for (int i = 0; i < lists.size(); i++) {
            T t = lists.get(i);
            Class clazz = t.getClass();

            ItemBean bean = new ItemBean();
            if (t instanceof String) {
                bean.setItem((String) lists.get(i));//如果是String类型的集合 直接添加到list
                items.add(bean);
            } else {
                Field[] fields = clazz.getDeclaredFields();
                if (fields != null) {
                    for (Field field : fields) {
                        boolean b = field.isAnnotationPresent(ShowItemAnn.class);
                        if (b) {
                            String fieldName = field.getName();
                            String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                            try {
                                Method getMethod = clazz.getMethod(getMethodName);
                                String invokeStr = (String) getMethod.invoke(t);
                                bean.setItem(invokeStr);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }

                    }
                }
                items.add(bean);
            }
        }
        return items;
    }

    /**
     * 可以在里面添加其他属性 通过注解获取。不需要可以直接删除。list add  String即可
     */
    static class ItemBean {
        String item;


        public String getItem() {
            return item;
        }

        public void setItem(String item) {
            this.item = item;
        }

    }
}

最后在activity中使用

private fun showDialog() {
        val userList = ArrayList<User>()
        val user = User()
        user.name = "Tom"
        user.age = "100"
        val user1 = User()
        user1.name = "Jim"
        user1.age = "20"
        val user2 = User()
        user2.name = "Tim"
        user2.age = "100"
        val user3 = User()
        user3.name = "Hello"
        user3.age = "100"
        val user4 = User()
        user4.name = "Hi"
        user4.age = "100"

        userList.add(user)
        userList.add(user1)
        userList.add(user2)
        userList.add(user3)
        userList.add(user4)

        bottomListDialog = BottomListDialog.Builder(this).setTitle("请选择").setItems(userList).setActivePosition(activePosition).setOnItemClickListener { parent, view, position, id ->
        	//点击item回调
            activePosition = position
            Toast.makeText(this, userList.get(position).name, Toast.LENGTH_SHORT).show()
            bottomListDialog!!.dismiss()
        }.show()
    }

最后展示如下

使用androidx glide生成注解 不是x包 android自定义注解_注解基本用法


点击跳转demo下载地址

补充
  • 获取注解的参数
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyAnn {
    String value();
}
public class MyBean {
    @MyAnn("age")
    private String name;
    private int age;

    public MyBean(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 省略 get set 方法
}
MyAnn annotation = field.getAnnotation(MyAnn.class);
if (annotation != null) {
	// 获取到 value 之后就可以做自己的事情了
	String value = annotation.value();
	System.out.println(value);
}