android知识点——ButterKnife以及Android ButterKnife Zelezny

2024-05-16 14:08

本文主要是介绍android知识点——ButterKnife以及Android ButterKnife Zelezny,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

先扯两句

原本这篇博客是要继续写《一个Android工程的从零开始》的,不过看到了0502Leeyuu丶在简书上给我指出的问题。

你好,为什么要用compile ‘com.jakewharton:butterknife:5.1.1’,而不用最新版的?

为什么我使用这个版本的原因,正文中会予以说明,下面我就将自己解决的方法,以及0502Leeyuu丶为我提供的方法一同展示出来,也方便大家多角度选择。
还是厚着脸皮先将自己的github地址贴出来,大家可以去看一下我的源码。
MyBaseApplication (https://github.com/BanShouWeng/MyBaseApplication)

并给大家展示个神器,叫Android知识点——目录,好了,闲言少叙,下面进入正题。

正文

###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:

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() {@Overridepublic 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;@Overrideprotected 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();}}}}@Overrideprotected void onDestroy() {super.onDestroy();activities.remove(this);}/*** 网络变化回调方法** @param mobileNetState 当前的网络状态*/@Overridepublic void onNetChanged(int mobileNetState) {}/*** 显示加载提示框*/public void showLoadDialog() {runOnUiThread(new Runnable() {@Overridepublic void run() {customProgressDialog.show();}});}/*** 隐藏加载提示框*/public void hideLoadDialog() {runOnUiThread(new Runnable() {@Overridepublic 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();}
}

这篇关于android知识点——ButterKnife以及Android ButterKnife Zelezny的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/995124

相关文章

基本知识点

1、c++的输入加上ios::sync_with_stdio(false);  等价于 c的输入,读取速度会加快(但是在字符串的题里面和容易出现问题) 2、lower_bound()和upper_bound() iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。 iterator upper_bou

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容

1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为00的,其次是01(没被访问但被修改过)的,之后是10(被访问了但没被修改过),最后是11。 2.内聚的类型 功能内聚:完成一个单一功能,各个部分协同工作,缺一不可。 顺序内聚:

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR