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() {
            @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();
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章