自定义轻量级android控件注解工具--金剪刀(自己命名的)(大家都在用)


自定义轻量级android控件注解工具(大家都在用吐舌头)


金剪刀(
GoldenScissors
)注解工具,是本人写的一个轻量级的android开发页面注解工具,代码量少,非常轻量级.之所以起这

个名字,主要是他jar
包非
常小,源码也非常少,使用方便,性能高,基本能满足大部分开发者的需求.字面意思,剪刀嘛也象征着锋利,

快速.
    其中此注解工具用到的主要的技术是反射,并且是暴力反射发火.

接下来我主要介绍一下此注解工具怎么使用以及代码实现的原理,水平有限,如有不妥或错误,请同仁纠正之!

本工具涵盖三个最主要的注解类型,也是我们开发最常用到的,如下

@LayoutViewCut 绑定activity布局

@ViewCut 绑定控件资源 省去繁琐的findViewById

@OnClickCut 控件点击事件

使用方法:

项目源码已托管到本人github上,地址:  https://github.com/jiangzhengyan/GoldenScissorsViewInject/  请多多关注哦

(1) 把libs下面的GoldenScissors.jar导进自己的项目中或者把library下的源码防盗自己的项目中

(2) 在onCreate方法中绑定此工具

 GoldenScissors.cut(this); 

(3) 根据需要,按照以下的方式去使用

1,@LayoutViewCut 注解绑定布局,(省去setContentView)

在继承activity的类位置添加注解(如 @LayoutViewCut(R.layout.activity_main)),例如

@LayoutViewCut(R.layout.activity_main)
public class MainActivity extends Activity {
    @ViewCut({R.id.tv_1, R.id.tv_2})
    private TextView tv1, tv2;

       

2,@ViewCut,可以代替findviewbyid找控件,在成员变量上面添加

        1,@ViewCut(R.id.tv_1).//单个控件

        2,@ViewCut({R.id.tv_1})  //单个控件

        3,@ViewCut({R.id.tv_1, R.id.tv_2}) //多个控件

        如下

    @ViewCut({R.id.tv_1, R.id.tv_2})
    private TextView tv1, tv2;

    @ViewCut(R.id.tv_3)
    private TextView tv3;

    @ViewCut({R.id.tv_4})
    private TextView tv4;

    @ViewCut({R.id.tv_5, R.id.tv_6, R.id.tv_7, R.id.tv_8,})
    private TextView tv5, tv6, tv7, tv8;

   

3, @OnClickCut 点击事件

注:方法的的命名参数名必须为View,方法名只要符合基本命名规则就行

 @OnClickCut({R.id.tv_1, R.id.tv_2, R.id.tv_3, R.id.tv_4, R.id.btn})
private void click(View view) {
    switch (view.getId()) {
        case R.id.tv_1:
            Toast.makeText(this, "点击了" + "tv1", Toast.LENGTH_SHORT).show();
            break;
        case R.id.tv_2:
            Toast.makeText(this, "点击了" + "tv2", Toast.LENGTH_SHORT).show();
            break;
        case R.id.tv_3:
            Toast.makeText(this, "点击了" + "tv3", Toast.LENGTH_SHORT).show();
            break;
        case R.id.tv_4:
            Toast.makeText(this, "点击了" + "tv4", Toast.LENGTH_SHORT).show();
            break;
        case R.id.btn:
            Toast.makeText(this, "点击了" + "按钮 5", Toast.LENGTH_SHORT).show();
            break;

    }


}

源代码解析

1, GoldenScissors这个类里面定义了一个cut方法,里面包含了三个工具最主要的三个处理注解逻辑的方法.
上源码
public static void cut(final Activity activity) {

		bindLayout(activity);//布局
		bindFields(activity);//控件
		bindMethod(activity);//点击

	}

首先要介绍一个自定义的异常(InjectException), 因为本项目要用到:就是直接继承异常的一个父类(RuntimeException)

public class InjectException extends RuntimeException {
	private static final long serialVersionUID = -8782914729012957108L;

	public InjectException() {

	}

	public InjectException(String detailMessage, Throwable throwable) {
		super(detailMessage, throwable);
	}

	public InjectException(String detailMessage) {
		super(detailMessage);
	}

	public InjectException(Throwable throwable) {
		super(throwable);
	}

}


下面介绍主要的三个地方法: 

布局
	/**
	 * 绑定布局
	 * 
	 * @param activity
	 *             所在对象
	 */
	private static void bindLayout(Activity activity) {
		final Class<? extends Context> clazz = activity.getClass();

		LayoutViewCut layoutViewCut = clazz.getAnnotation(LayoutViewCut.class);
		if (layoutViewCut != null) {
			int layoutResId = layoutViewCut.value();
			try {
				Method method = clazz.getMethod("setContentView",
						new Class[] { Integer.TYPE });
				method.invoke(activity, layoutResId);
			} catch (Throwable th) {
				throw new InjectException(new Throwable(th.getMessage() + " : "
						+ th));
			}
		}
	}

控件
	/**
	 * 绑定多个成员变量
	 * 
	 * @param activity
	 *            所在对象
	 */
	private static void bindFields(Activity activity) {

		final Class<? extends Context> clazz = activity.getClass();
		Field[] declaredFields = clazz.getDeclaredFields();

		ArrayList<Integer> filedResIdList = new ArrayList<Integer>();
		ArrayList<String> filedNameList = new ArrayList<String>();
		for (int i = 0; i < declaredFields.length; i++) {
			Field field = declaredFields[i];
			ViewCut injectFiled = field.getAnnotation(ViewCut.class);
			if (injectFiled != null) {

				String filedName = field.getName();
				if (!filedNameList.contains(filedName)) {
					filedNameList.add(filedName);
				}
				int[] resIds = injectFiled.value();

				for (int x = 0; x < resIds.length; x++) {
					int k = resIds[x];
					if (!filedResIdList.contains(k)) {
						filedResIdList.add(k);
					}
				}
			}
		}

		int declaredFieldsLength = filedNameList.size();
		int resIdsLength = filedResIdList.size();

		if (declaredFieldsLength > resIdsLength) {
			throw new InjectException(
					new Throwable(
							"DeclaredFileds' counts  cannot be more than inject ResIds'  counts"));
		} else if (declaredFieldsLength < resIdsLength) {
			throw new InjectException(
					new Throwable(
							"Inject ResIds' counts  cannot be more than DeclaredFileds' counts"));
		}

		for (int i = 0; i < declaredFields.length; i++) {
			Field field = declaredFields[i];
			ViewCut injectFiled = field.getAnnotation(ViewCut.class);
			if (injectFiled != null) {

				int resId = filedResIdList.get(i);
				View view = activity.findViewById(resId);
				field.setAccessible(true);
				try {
					field.set(activity, view);
				} catch (Throwable th) {
					throw new InjectException(
							new Throwable(
									"Inject failed ,maybe your context is null or recorrect"));
				}

			}
		}
	}



点击事件

	/**
	 * 绑定方法,即点击事件
	 * 
	 * @param activity
	 *            所在对象
	 */
	private static void bindMethod(final Activity activity) {
		final Class<? extends Context> clazz = activity.getClass();
		Method[] methods = clazz.getDeclaredMethods();
		for (final Method method : methods) {
			OnClickCut injectMetheds = method.getAnnotation(OnClickCut.class);
			method.setAccessible(true);
			if (injectMetheds != null) {
				int[] resIds = injectMetheds.value();
				for (int i = 0; i < resIds.length; i++) {
					final View view = activity.findViewById(resIds[i]);
					view.setOnClickListener(new OnClickListener() {

						@Override
						public void onClick(View arg0) {
							try {
								method.invoke(activity, view);
							} catch (Throwable th) {
								throw new InjectException(
										new Throwable(
												"Inject method failed,please checked you methed inject names"));
							}

						}
					});
				}

			}

		}
	}



定义的三个@interface如下

@LayoutViewCut 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LayoutViewCut {

	int  value();
 
}

@ViewCut

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

	int[] value();

}



@OnClickCut

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public   @interface  OnClickCut {

	int[] value();
}











  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九千行代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值