android开发相关——ButterKnife以及Android ButterKnife Zelezny
2017-07-12 16:11
330 查看
先扯两句
原本这篇博客是要继续写《一个Android工程的从零开始》的,不过看到了0502Leeyuu丶在简书上给我指出的问题。你好,为什么要用compile ‘com.jakewharton:butterknife:5.1.1’,而不用最新版的?
为什么我使用这个版本的原因,正文中会予以说明,下面我就将自己解决的方法,以及0502Leeyuu丶为我提供的方法一同展示出来,也方便大家多角度选择。
还是厚着脸皮先将自己的github地址贴出来,大家可以去看一下我的源码。
MyBaseApplication (https://github.com/BanShouWeng/MyBaseApplication)
正文
ButterKnife集成
其实呢,看了我之前博客的朋友应该知道,我前面实际上并没有使用到ButterKnife,可项目中为什么会有这个呢,还是因为我一贯偷懒的一个尝试,也就是Android ButterKnife Zelezny插件的运用。不过这个插件暂且不提,在文章后面会与大家分享,先说一下使用这个插件的一个前提,就是需要我们添加一下ButterKnife的库。
而Android Studio为了照顾我这种比较喜欢偷懒的人,专门给提供了一些添加开源库的方式。
按以上五步操作,会出现如下对话框。
在搜索框中输入我们想要查询的控件,点Shift+Enter(这个是鼠标移动到放大镜提示的,但是操作中,我点Enter也是可以的),就可以进行搜索,然后在所有搜索结果中选择出我们想要的开源库,点击OK即可。
好了博客原本的内容到这里就应该结束了,可是Android Studio实在是给我这样的懒人出了一个大难题啊,那就是如下图:
当我输入了“butter”时,下面的提示是Nothing to show,如果输入bu呢:
当然现在我的Android Studio出现的情况是输入ButterKnife或者butterknife的时候都可以找到我们要找到的开源库,当时当时出现的却是上面那个5.1.1的版本,具体原因暂时未知。
于是偷懒的我呢就直接拿来尝试了一下Android ButterKnife Zelezny,可用。不过由于没有到ButterKnife的部分就没有去搜索最新版。
这里呢,为了这次粗心向大家道歉,希望大家发现我博客中存在的问题以及不足也能同样提出来,谢谢大家了,更要感谢0502Leeyuu丶的认真严谨。
下面呢,就给出0502Leeyuu丶和我个人的两种解决方式:
1、贴出0502Leeyuu丶给出的解决方法:
0502Leeyuu丶: @半寿翁 一起学习,我也弄android没多久,要不你试试把全称com.jakewharton:butterknife:8.7.0放进去搜索一下,我之前弄cardview的时候也搜索不到,输入全称搜到了,不知道会不会起作用。而且最新版本的ButterKnife中的inject方法没了。
其中说到的inject类似理解为当前新版本中的bind,我尝试的过程中发现,将版本好去掉,也可以搜出结果。
2、GitHub上找到对应运用:
其中给我们提供了一个链接:http://jakewharton.github.io/butterknife/但是只在其中讲解了ButterKnife如何使用,并没有找到最新版本的相关信息。
不过返回到https://github.com/JakeWharton/butterknife页面向下翻,可以看到如下部分:
将dependencies中的代码粘到我们build.gradle(module: app)文件中的dependencies中。
可以看到文件上方出现如下提示:
点击右上角的Sync Now即可完成开源库的加载。
当然,以上两种方式都是应急时使用,还是希望大家可以直接在Library Dependency中添加成功。
ButterKnife使用
既然已经集成了,那么下面我们就来看看费这么到力气去集成ButterKnife,它会怎么帮我偷懒,才值得这么折腾。它的作用,在http://jakewharton.github.io/butterknife/中可以查到,一言以蔽之就是资源的绑定,包括图片、文字等,也有控件和点击事件。
当然,一般常用的情况还是控件的绑定,以及点击事件。
使用之前,需要我们先将ButterKnife与当前的Activity或者Fragment绑定,也就是在onCreate方法中添加如下代码:
ButterKnife.bind(this);
控件绑定
//系统绑定 TextView firstName = (TextView)findViewById( R.id.first_name); //ButterKnife绑定 //绑定方法1 @BindView(R.id.first_name) TextView firstName; //绑定方法2 TextView firstName = ButterKnife.findById(view, R.id.first_name);
关于以上两种绑定的方法,还是有所不同的(好吧, 我承认这句是废话),至于如何不同,绑定方法1还是比较简单的,只要直接用就好,只是简单自然有简单的代价,那就是绑定方法1所使用的方法不能绑定私有控件或者是静态控件,所以有一些要求封装严谨的这种方法也就不适用了。
而绑定方法2,我尝试了创建私有控件,没有问题,静态的没有尝试,有兴趣的可以自己尝试一下,也可以看得出来,相对于系统提供的方法,他省去的部分是强转,可是这也就带来了另一个问题,那就是findById中的第一个参数——view:
4000
baseScrollView = ButterKnife.findById(getLayoutInflater().inflate(R.layout.activity_base, null), R.id.base_scroll_view);
这部分代码我是将整体的内容合在了一起写,而view也就相当于getLayoutInflater().inflate(R.layout.activity_base, null),这自然就是我们整个布局的解析。
当然,如果在Fragment中,毕竟在onCreateView中原本也是需要解析一下布局的,就直接保存下来,在onViewCreated方法中直接使用解析。
在Activity中,就建议使用传递Activity参数的方式了,至于第三中Dialog的暂时没有尝试过,需要大家自行去探索了。
点击事件:
//系统点击事件 findViewById( R.id.first_name).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast("点击了"); } }); // @OnClick(R.id.first_name) public void sayHi(TextView firstName) { Toast("点击了"); }
当然,点击事件也是允许我们设置多个id的,如下:
@OnClick({R.id.first_name, R.id.last_name}) private void click(View view) { switch (view.getId()){ case R.id.first_name: break; case R.id.last_name: break; } }
对应做处理即可,如果需要对所点击控件操作的话,强转view即可。
其他更灵活的运用大家还是看一下官方提供的说明吧。
Android ButterKnife Zelezny
Android ButterKnife Zelezny插件安装
扯了这么多,终于该上我们的终极大Boss了,偷懒神器Android ButterKnife Zelezny。首先第一步,自然是需要将这个插件安装到我们的Android Studio中。
快捷键 Ctrl + Alt + S打开设置页面:
依图打开Browse Repositories
如图找到我们要添加的插件Android ButterKnife Zelezny(这搜索才是我要的生活),点击install后会下载安装,成功后会提示重启Android Studio:
点击Restart Android Studio后会出现如下弹窗:
点击Restart,之后坐等Android Studio自动重启就好。
Android ButterKnife Zelezny的使用
使用的部分我就在自己的BaseActivity中进行了,首先是将之前创建的initView方法注释掉,因为Android ButterKnife Zelezny完成的就是控件初始化的操作。在对应需要使用Activity或者Fragment中,将光标放置在layout对应的名称上,如下图的“activity_base”,然后点击Alt + Insert快捷键(光标在其他位置找不到所需要的选项):
可以看到出现了Generate ButterKnife Injections的选项,点击打开对话框(可以看到其后也有快捷键,不过与搜狗输入法的颜文字冲突,关闭后再次点击,还与其他软件冲突,一个一个关实在太费事了,也就放弃了直接一步到位,对于我这种懒人来说,这个绝对也是含泪完成的啊)
可以看到对应的命名都已经帮我们按照驼峰规则完成,同时也可以自行选择那些需要创建OnClick方法,我这里选择了四个。
其左下角有两个可选项:第一个是是否创建ViewHolder,这里暂时不需要;第二个是是否将点击事件的方法分开,自然也没有必要,所以就直接点击了Confirm。
处理完成后,可以看到我们的代码中多出了如下两部分代码:
//控件绑定 @BindView(R.id.base_back) ImageView baseBack; @BindView(R.id.base_title) TextView baseTitle; @BindView(R.id.base_right_icon2) ImageView baseRightIcon2; @BindView(R.id.base_right_icon1) ImageView baseRightIcon1; @BindView(R.id.base_right_text) TextView baseRightText; @BindView(R.id.base_title_layout) RelativeLayout baseTitleLayout; @BindView(R.id.base_main_layout) LinearLayout baseMainLayout; @BindView(R.id.base_scroll_view) ScrollView baseScrollView; //点击事件 @OnClick({R.id.base_back, R.id.base_right_icon2, R.id.base_right_icon1, R.id.base_right_text}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.base_back: break; case R.id.base_right_icon2: break; case R.id.base_right_icon1: break; case R.id.base_right_text: break; } }
可以看得出来,明显要比之前使用的方法要简单的多,为了配合这部分使用,我将BaseActivity中的返回键也做了接口监听,代码参见附录2。
ps:不过由于前面说过,绑定方法1、2的利弊,所以这里只是演示了一下ButterKnife的使用效果,在BaseActivity的封装中,使用的还是原本的系统的方法解析控件,不过在后续的Activity和 Fragment中,如果对封装要求没有那么严谨的时候,使用ButterKnife确实是一个不错的选择,毕竟可以偷懒嘛。
附录
附录1
《一个Android工程的从零开始》- 目录附录2
package com.banshouweng.mybaseapplication.base; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; import com.banshouweng.mybaseapplication.R; import com.banshouweng.mybaseapplication.event.NetBroadcastReceiver; import com.banshouweng.mybaseapplication.ui.activity.MainActivity; import com.banshouweng.mybaseapplication.widget.CustomProgressDialog; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; public class BaseActivity extends AppCompatActivity implements NetBroadcastReceiver.NetEvevt { /** * 网络状态监听接受者 */ private static NetBroadcastReceiver.NetEvevt evevt; /** * 用于传递的上下文信息 */ public Context context; public Activity activity; @BindView(R.id.base_back) ImageView baseBack; @BindView(R.id.base_title) TextView baseTitle; @BindView(R.id.base_right_icon2) ImageView baseRightIcon2; @BindView(R.id.base_right_icon1) ImageView baseRightIcon1; @BindView(R.id.base_right_text) TextView baseRightText; @BindView(R.id.base_title_layout) RelativeLayout baseTitleLayout; @BindView(R.id.base_main_layout) LinearLayout baseMainLayout; @BindView(R.id.base_scroll_view) ScrollView baseScrollView; /** * 是否重置返回按钮点击事件 */ private boolean isResetBack = false; /** * 点击回调方法 */ private OnClickRightIcon1CallBack onClickRightIcon1; private OnClickRightIcon2CallBack onClickRightIcon2; private OnClickRightTextCallBack onClickRightText; private OnClickBackCallBack onClickBack; /** * 当前打开Activity存储List */ private static List<Activity> activities = new ArrayList<>(); /** * 加载提示框 */ private CustomProgressDialog customProgressDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_base); if (!(this instanceof MainActivity)) { activities.add(this); } ButterKnife.bind(this); context = getApplicationContext(); activity = this; customProgressDialog = new CustomProgressDialog(activity, R.style.progress_dialog_loading, "玩命加载中。。。"); // initView(); } /** * 隐藏返回键 */ private void hideBack() { baseBack.setVisibility(View.GONE); } /** * 设置标题 * * @param title 标题的文本 */ public void setTitle(String title) { baseTitle.setText(title); } public void setBaseBack(OnClickBackCallBack onClickBack) { this.onClickBack = onClickBack; isResetBack = true; } /** * 设置右侧图片1(最右侧) * * @param resId 图片的资源id * @param alertText 提示文本 * @param onClickRightIcon1 点击处理接口 */ public void setBaseRightIcon1(int resId, String alertText, OnClickRightIcon1CallBack onClickRightIcon1) { this.onClickRightIcon1 = onClickRightIcon1; baseRightIcon1.setImageResource(resId); baseRightIcon1.setVisibility(View.VISIBLE); //语音辅助提示的时候读取的信息 baseRightIcon1.setContentDescription(alertText); } /** * 设置右侧图片2(右数第二个图片) * * @param resId 图片的资源id * @param alertText 提示文本 */ public void setBaseRightIcon2(int resId, String alertText, OnClickRightIcon2CallBack onClickRightIcon2) { this.onClickRightIcon2 = onClickRightIcon2; baseRightIcon2.setImageResource(resId); baseRightIcon2.setVisibility(View.VISIBLE); //语音辅助提示的时候读取的信息 baseRightIcon2.setContentDescription(alertText); } /** * 设置右侧文本信息 * * @param text 所需要设置的文本 */ public void setBaseRightText(String text, OnClickRightTextCallBack onClickRightText) { this.onClickRightText = onClickRightText; baseRightText.setText(text); baseRightText.setVisibility(View.VISIBLE); } /** * 引用头部布局 * * @param layoutId 布局id */ public void setBaseContentView(int layoutId) { //当子布局高度值不足ScrollView时,用这个方法可以充满ScrollView,防止布局无法显示 ((ScrollView) findViewById(R.id.base_scroll_view)).setFillViewport(true); LinearLayout layout = (LinearLayout) findViewById(R.id.base_main_layout); //获取布局,并在BaseActivity基础上显示 final View view = getLayoutInflater().inflate(layoutId, null); //关闭键盘 hideKeyBoard(); //给EditText的父控件设置焦点,防止键盘自动弹出 view.setFocusable(true); view.setFocusableInTouchMode(true); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); layout.addView(view, params); } /** * 隐藏键盘 */ public void hideKeyBoard() { View view = activity.getWindow().peekDecorView(); if (view != null) { InputMethodManager inputmanger = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); inputmanger.hideSoftInputFromWindow(view.getWindowToken(), 0); } } /** * 跳转页面 * * @param clz 所跳转的目的Activity类 */ public void startActivity(Class<?> clz) { startActivity(new Intent(this, clz)); } /** * 跳转页面 * * @param clz 所跳转的目的Activity类 * @param bundle 跳转所携带的信息 */ public void startActivity(Class<?> clz, Bundle bundle) { Intent intent = new Intent(this, clz); if (bundle != null) { intent.putExtra("bundle", bundle); } startActivity(intent); } /** * 跳转页面 * * @param clz 所跳转的Activity类 * @param requestCode 请求码 */ public void startActivityForResult(Class<?> clz, int requestCode) { startActivityForResult(new Intent(this, clz), requestCode); } /** * 跳转页面 * * @param clz 所跳转的Activity类 * @param bundle 跳转所携带的信息 * @param requestCode 请求码 */ public void startActivityForResult(Class<?> clz, int requestCode, Bundle bundle) { Intent intent = new Intent(this, clz); if (bundle != null) { intent.putExtra("bundle", bundle); } startActivityForResult(intent, requestCode); } /** * 消息提示框 * * @param message 提示消息文本 */ public void showToast(String message) { Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } /** * 消息提示框 * * @param messageId 提示消息文本ID */ public void showToast(int messageId) { Toast.makeText(context, messageId, Toast.LENGTH_SHORT).show(); } /** * 关闭所有Activity(除MainActivity以外) */ public void finishActivity() { for (Activity activity : activities) { activity.finish(); } } /** * 跳转到指定的Activity * * @param clz 指定的Activity对应的class */ public void goTo(Class<?> clz) { if (clz.equals(MainActivity.class)) { finishActivity(); } else { for (int i = activities.size() - 1; i >= 0; i--) { if (clz.equals(activities.get(i).getClass())) { break; } else { activities.get(i).finish(); } } } } @Override protected void onDestroy() { super.onDestroy(); activities.remove(this); } /** * 网络变化回调方法 * * @param mobileNetState 当前的网络状态 */ @Override public void onNetChanged(int mobileNetState) { } /** * 显示加载提示框 */ public void showLoadDialog() { runOnUiThread(new Runnable() { @Override public void run() { customProgressDialog.show(); } }); } /** * 隐藏加载提示框 */ public void hideLoadDialog() { runOnUiThread(new Runnable() { @Override public void run() { if (customProgressDialog != null && customProgressDialog.isShowing()) { customProgressDialog.dismiss(); } } }); } @OnClick({R.id.base_back, R.id.base_right_icon2, R.id.base_right_icon1, R.id.base_right_text}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.base_back: if (isResetBack) { onClickBack.clickBack(); } else { finish(); } break; case R.id.base_right_icon2: onClickRightIcon2.clickRightIcon2(); break; case R.id.base_right_icon1: onClickRightIcon1.clickRightIcon1(); break; case R.id.base_right_text: onClickRightText.clickRightText(); break; } } /** * 图片一点击回调接口 */ public interface OnClickRightIcon1CallBack { void clickRightIcon1(); } /** * 图片二点击回调接口 */ public interface OnClickRightIcon2CallBack { void clickRightIcon2(); } /** * 右侧文字点击回调接口 */ public interface OnClickRightTextCallBack { void clickRightText(); } /** * 返回键点击回调接口 */ public interface OnClickBackCallBack { void clickBack(); } }
相关文章推荐
- butterknife注解框架的偷懒插件Android Butterknife Zelezny
- Butter Knife View注入 以及 插件Android Butterknife Zelezny使用
- (2016.5.26更新8.0.1失效问题)Android Studio上使用Butterknife注解框架与插件Android Butterknife Zelezny
- Android Studio中设置ButterKnife、android butterknife zelezny 注意事项,ButterKnife按钮点击无效原因
- Android-ButterKnife不能注解RatingBar(含ButterKnife部分原理以及View传递机制)
- Android Studio上方便使用butterknife注解框架的偷懒插件Android Butterknife Zelezny
- Android Butterknife 8.4.0 ButterKnife是一个专注于Android系统的View注入框架,可以减少大量的findViewById以及setOnClickListene
- Android Studio上方便使用butterknife注解框架的偷懒插件Android Butterknife Zelezny
- Android Studio上方便使用butterknife注解框架的偷懒插件Android Butterknife Zelezny
- Android Studio上方便使用butterknife注解框架的偷懒插件Android Butterknife Zelezny
- Android Studio上方便使用butterknife注解框架的偷懒插件Android Butterknife Zelezny
- Android Studio上方便使用butterknife注解框架的偷懒插件Android Butterknife Zelezny
- Android Studio上方便使用butterknife注解框架的偷懒插件Android Butterknife Zelezny
- Android Studio上方便使用butterknife注解框架的偷懒插件Android Butterknife Zelezny
- Android快速开发工具ButterKnife Zelezny注解框架使用教程
- Android Studio上方便使用butterknife注解框架的偷懒插件Android Butterknife Zelezny
- Android Studio上方便使用butterknife注解框架的偷懒插件Android Butterknife Zelezny
- the latest ButterKnife and Android-Butterknife-Zelezny
- Android Studio中设置ButterKnife、android butterknife zelezny 注意事项,ButterKnife按钮点击无效原因