淺談BaseActivity寫法换帜,促使我們更高效開發(fā)

抓住人生中的一分一秒楔壤,勝過虛度中的一月一年!

前言

在Android開發(fā)中,activity再常用不過了惯驼,為了高效開發(fā)蹲嚣,我們會(huì)將一些常用的功能和頁面統(tǒng)一實(shí)現(xiàn)的效果放在基類,這樣就不用寫每個(gè)頁面時(shí)再重新實(shí)現(xiàn)這些功能祟牲,下面是我總結(jié)了些內(nèi)容與大家共享一下隙畜,有不足的地方希望大家提出我將進(jìn)行再次完善。

實(shí)現(xiàn)目標(biāo)

1说贝、屏幕橫豎屏切換议惰,AndroidManifest中將不用再寫android:screenOrientation="portrait"
2、ButterKnife綁定頁面
3乡恕、沉浸式實(shí)現(xiàn)
4言询、攜帶數(shù)據(jù)的頁面跳轉(zhuǎn)
5、應(yīng)用被強(qiáng)殺檢測(cè)
6傲宜、標(biāo)題欄統(tǒng)一實(shí)現(xiàn)
7运杭、仿IOS側(cè)滑finish頁面實(shí)現(xiàn)
8、Loading頁面統(tǒng)一實(shí)現(xiàn)(可替換成骨架圖)
9函卒、點(diǎn)擊Edittext彈出軟鍵盤辆憔,點(diǎn)擊空白區(qū)域讓軟鍵盤消失
10、結(jié)合MVP模式下的BaseActivity


1谆趾、屏幕橫豎屏切換躁愿,AndroidManifest中將不用再寫android:screenOrientation="portrait"

我們經(jīng)常開發(fā)的app,一般情況下都是手機(jī)上的應(yīng)用沪蓬,我想大家已經(jīng)設(shè)置了強(qiáng)制豎屏彤钟,因?yàn)闄M屏沒有特殊要求沒有必要去設(shè)置,設(shè)置了反而會(huì)出現(xiàn)更多問題跷叉,其次說一下8.0更新問題逸雹,頁面同時(shí)設(shè)置了android:screenOrientation="portrait"和透明屬性,8.0運(yùn)行會(huì)出現(xiàn)Only fullscreen opaque activities can request orientation異常云挟,大概意思為“只有不透明的全屏activity可以自主設(shè)置界面方向”梆砸,我們或許會(huì)引用一些第三方SDK到項(xiàng)目中,也許第三方會(huì)用到透明屬性园欣,我們可能在AndroidManifest中會(huì)申明android:screenOrientation="portrait"后導(dǎo)致莫名其妙的奔潰(小概率事件帖世,但不排除),所以建議在BaseActivity設(shè)置比較優(yōu)(當(dāng)你做側(cè)滑返回以后就不會(huì)覺得我說這么啰嗦了)

 /**
     * 設(shè)置屏幕橫豎屏切換
     *
     * @param screenRoate true  豎屏     false  橫屏
     */
    private void setScreenRoate(Boolean screenRoate) {
        if (screenRoate) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//設(shè)置豎屏模式
        } else {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }
    }

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setScreenRoate(true);
    }
2沸枯、ButterKnife綁定頁面

ButterKnife這個(gè)快速申明控件省了我們多少findViewById的時(shí)間日矫,推薦使用赂弓,詳細(xì)寫一寫可能有人沒用過此控件
1、依賴

compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

2哪轿、onCreate綁定頁面 onDestroy取消綁定

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ButterKnife.bind(this);
    }
  @Override
    protected void onDestroy() {
        super.onDestroy();
        ButterKnife.bind(this).unbind();
    }
3盈魁、沉浸式實(shí)現(xiàn)

為了讓用戶感受更好的體驗(yàn)效果,所以我們會(huì)選擇設(shè)置沉浸式窃诉,每個(gè)頁面大多數(shù)都會(huì)設(shè)置一種效果杨耙,所以直接在BaseActivity設(shè)置即可

 /**
     * 沉浸式實(shí)現(xiàn)
     */
    protected void setStatusBar() {
        StatusBarUtil.setColor(this, getResources().getColor(R.color.colorWhite), 0);
//        StatusBarUtil.setTranslucentForImageViewInFragment(this, 0, null);
    }
   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStatusBar();
    }

問:如果有頁面不想設(shè)置此效果
答:在對(duì)應(yīng)Activity重寫setStatusBar(),做自定義操作

4飘痛、攜帶數(shù)據(jù)的頁面跳轉(zhuǎn)

跳轉(zhuǎn)頁面 startActivity(new Intent(this, MainActivity.class));不改裝這已經(jīng)是最簡(jiǎn)潔了珊膜,你要記住,程序員是比較懶的宣脉,能少寫就少寫

 /**
     * [頁面跳轉(zhuǎn)]
     *
     * @param clz
     */
    public void startActivity(Class<?> clz) {
        startActivity(clz, null);
    }
    /**
     * [攜帶數(shù)據(jù)的頁面跳轉(zhuǎn)]
     *
     * @param clz
     * @param bundle
     */
    public void startActivity(Class<?> clz, Bundle bundle) {
        Intent intent = new Intent();
        intent.setClass(this, clz);
        if (bundle != null) {
            intent.putExtras(bundle);
        }
        startActivity(intent);
    }

    /**
     * [含有Bundle通過Class打開編輯界面]
     *
     * @param cls
     * @param bundle
     * @param requestCode
     */
    public void startActivityForResult(Class<?> cls, Bundle bundle, int requestCode) {
        Intent intent = new Intent();
        intent.setClass(this, cls);
        if (bundle != null) {
            intent.putExtras(bundle);
        }
        startActivityForResult(intent, requestCode);
    }

跳轉(zhuǎn)頁面startActivity(MainActivity.class);嗯辅搬。。脖旱。少寫了幾個(gè)字母

5、應(yīng)用被強(qiáng)殺檢測(cè)

手機(jī)開了N多個(gè)應(yīng)用介蛉,可能導(dǎo)致內(nèi)存不足萌庆,所以GC就出來工作了,也許你的App就是被殺的對(duì)象(北揖桑活處理移步其他文章)践险,我們需要檢測(cè)到APP是否被殺
思路:
(1)APP被殺,可以跳轉(zhuǎn)到閃屏頁吹菱,再跳轉(zhuǎn)到MainActivity巍虫,但可能MainActivity還存在,我想讓MainActivity徹底消失鳍刷,所以我的思路是跳轉(zhuǎn)到MainActivity占遥,將MainActivity finish再跳轉(zhuǎn)到閃屏頁,再往其他頁面跳轉(zhuǎn)
(2)那怎么樣檢測(cè)APP是否被殺呢输瓜,我進(jìn)入到APP后將一個(gè)參數(shù)設(shè)置個(gè)值瓦胎,如果APP被殺,也就是說我們當(dāng)時(shí)設(shè)置的值已經(jīng)不存在了尤揣,當(dāng)我們檢測(cè)到這個(gè)值和我們當(dāng)時(shí)設(shè)置的值不匹配說明APP被殺了
1搔啊、新建個(gè)常量類AppStatusConstant

/**
 * File descripition:   APP狀態(tài)跟蹤器常量碼
 *
 * @author lp
 * @date 2018/9/29
 */

public class AppStatusConstant {
    public static final int STATUS_FORCE_KILLED=-1; //應(yīng)用放在后臺(tái)被強(qiáng)殺了
    public static final int STATUS_NORMAL=2;  //APP正常態(tài)
    //intent到MainActivity 區(qū)分跳轉(zhuǎn)目的
    public static final String KEY_HOME_ACTION="key_home_action";//返回到主頁面
    public static final int ACTION_BACK_TO_HOME=6; //默認(rèn)值
    public static final int ACTION_RESTART_APP=9;//被強(qiáng)殺
}

2、新建個(gè)單例模式北戏,用來保存值

/**
 * File descripition:
 *
 * @author lp
 * @date 2018/9/29
 */

public class AppStatusManager {
    public int appStatus= AppStatusConstant.STATUS_FORCE_KILLED;        //APP狀態(tài) 初始值為沒啟動(dòng) 不在前臺(tái)狀態(tài)

    public static AppStatusManager appStatusManager;

    private AppStatusManager() {

    }

    public static AppStatusManager getInstance() {
        if (appStatusManager == null) {
            appStatusManager = new AppStatusManager();
        }
        return appStatusManager;
    }

    public int getAppStatus() {
        return appStatus;
    }

    public void setAppStatus(int appStatus) {
        this.appStatus = appStatus;
    }
}

3负芋、進(jìn)入到閃屏頁我便給appStatus賦值

/**
 * File descripition:   閃屏頁
 *
 * @author lp
 * @date 2018/10/16
 */

public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        AppStatusManager.getInstance().setAppStatus(AppStatusConstant.STATUS_NORMAL); //進(jìn)入應(yīng)用初始化設(shè)置成未登錄狀態(tài)
        super.onCreate(savedInstanceState);
    }
}

4、在BaseActivity的onCreate中去檢測(cè)這個(gè)值是否是我們?cè)O(shè)置過的值

 private void initAppStatus() {
        switch (AppStatusManager.getInstance().getAppStatus()) {
            /**
             * 應(yīng)用被強(qiáng)殺
             */
            case AppStatusConstant.STATUS_FORCE_KILLED:
                //跳到主頁,主頁lauchmode SINGLETASK
                protectApp();
                break;
        }
    }
 protected void protectApp() {
        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtra(AppStatusConstant.KEY_HOME_ACTION, AppStatusConstant.ACTION_RESTART_APP);
        startActivity(intent);
    }
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initAppStatus();
    }

5嗜愈、MainActivity中接收傳過來的信息旧蛾,然后調(diào)整到閃屏頁

  @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        int action = intent.getIntExtra(AppStatusConstant.KEY_HOME_ACTION, AppStatusConstant.ACTION_BACK_TO_HOME);
        switch (action) {
            case AppStatusConstant.ACTION_RESTART_APP:
                protectApp();
                break;
        }
    }
 @Override
    protected void protectApp() {
        Toast.makeText(getApplicationContext(), "應(yīng)用被回收重新啟動(dòng)", Toast.LENGTH_LONG).show();
        startActivity(new Intent(this, SplashActivity.class));
        finish();
    }
6莽龟、標(biāo)題欄統(tǒng)一實(shí)現(xiàn)

每個(gè)頁面大多數(shù)都會(huì)有個(gè)標(biāo)題欄,實(shí)現(xiàn)方式我們都會(huì)蚜点,下面我介紹另一種方式轧房,我把標(biāo)題欄寫到BaseActivity布局中,這樣在對(duì)應(yīng)的Activity就不用一遍一遍的寫了绍绘,但是弊端是多了一層嵌套
思路:我們?cè)贐aseActivity申明一個(gè)布局奶镶,其子Activity的xml塞入到父布局的一個(gè)控件中,這樣就每個(gè)子Activity都會(huì)有統(tǒng)一的控件了(標(biāo)題欄)
1陪拘、首先新建個(gè)關(guān)于title的xml厂镇,app_title.xml(供參考)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rlt_base"
    android:layout_width="match_parent"
    android:layout_height="44dp"
    android:background="@color/colorWhite">
    <LinearLayout
        android:id="@+id/back"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:paddingLeft="@dimen/padding_12"
        android:paddingRight="@dimen/padding_12">
        <TextView
            android:id="@+id/back_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="@dimen/margin_8"
            android:drawableLeft="@mipmap/zuojiantou"
            android:drawablePadding="@dimen/padding_8"
            android:gravity="center"
            android:textColor="@color/colorBlack"
            android:visibility="visible" />
    </LinearLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true"
        android:layout_marginLeft="80dp"
        android:layout_marginRight="80dp">
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:layout_centerInParent="true"
            android:ellipsize="end"
            android:gravity="center"
            android:lines="1"
            android:textColor="@color/colorBlack"
            android:textSize="@dimen/text_18" />
    </RelativeLayout>
    <TextView
        android:id="@+id/tv_right"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:drawablePadding="@dimen/padding_6"
        android:ellipsize="end"
        android:gravity="center"
        android:lines="1"
        android:paddingLeft="14dp"
        android:paddingRight="14dp"
        android:textColor="@color/colorBlack"
        android:textSize="@dimen/text_16"
        android:visibility="visible" />
    <View
        style="@style/View_o_5"
        android:layout_alignParentBottom="true" />
</RelativeLayout>

2、創(chuàng)建父布局的xml左刽,activity.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <include layout="@layout/app_title" />
    <FrameLayout
        android:id="@+id/fl_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

3捺信、都創(chuàng)建好了就該給BaseActivity設(shè)置布局了

public abstract class BaseActivityNall extends AppCompatActivity {
    public TextView mBackName;
    public LinearLayout mBack;
    public TextView mTvTitle;
    public TextView mTvRight;
    public RelativeLayout mRltBase;

    protected View rootView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        rootView = View.inflate(this, R.layout.activity_title, null);
        setContentView(getLayoutId());
        addContent();
        setContentView(rootView);
    }
    private void addContent() {
        mBackName = (TextView) rootView.findViewById(R.id.back_name);
        mBack = (LinearLayout) rootView.findViewById(R.id.back);
        mTvTitle = (TextView) rootView.findViewById(R.id.tv_title);
        mTvRight = (TextView) rootView.findViewById(R.id.tv_right);
        mRltBase = (RelativeLayout) rootView.findViewById(R.id.rlt_base);
        FrameLayout flContent = (FrameLayout) rootView.findViewById(R.id.fl_content);

        mTvTitle.setText(getContentTitle() == null ? "" : getContentTitle());
        mBack.setOnClickListener(v -> finish());//java8寫法,特此備注一下

        View content = View.inflate(this, getLayoutId(), null);
        if (content != null) {
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                    FrameLayout.LayoutParams.MATCH_PARENT);
            flContent.addView(content, params);
            ButterKnife.bind(this, rootView);
        }
    }
    /**
     * 獲取布局ID
     *
     * @return
     */
    protected abstract int getLayoutId();
    /**
     * title賦值
     *
     * @return
     */
    protected abstract String getContentTitle();
}
7欠痴、仿IOS側(cè)滑finish頁面實(shí)現(xiàn)

實(shí)現(xiàn)側(cè)滑會(huì)有很多弊端迄靠,在此就不細(xì)講實(shí)現(xiàn)方式了,給大家演示一種喇辽,但是想完美實(shí)現(xiàn)還需進(jìn)一步完善掌挚,第三方庫實(shí)現(xiàn),方法在BaseActivity寫

implementation 'com.r0adkll:slidableactivity:2.0.6'

/**
     * 初始化滑動(dòng)返回
     */
    protected void initSlidable() {
        int isSlidable = SettingUtil.getInstance().getSlidable();
        if (isSlidable != Constants.SLIDABLE_DISABLE) {
            SlidrConfig config = new SlidrConfig.Builder()
                    .edge(isSlidable == Constants.SLIDABLE_EDGE)
                    .build();
            slidrInterface = Slidr.attach(this, config);
        }
    }
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initSlidable();
    }

// Base application theme. 
    <style name="MyAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
       // <item name="android:windowAnimationStyle">@style/activityAnimation</item>

        <item name="android:windowIsTranslucent">true</item>
        <!--<item name="android:windowDisablePreview">true</item>-->
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>

有很多類似的開源框架 暫舉四個(gè)
  1. SwipeBackLayout
  2. Slidr
  3. Snake
  4. and_swipeback
8菩咨、Loading頁面統(tǒng)一實(shí)現(xiàn)(可替換成骨架圖)

看了一個(gè)大神寫的一個(gè)框架吠式,超級(jí)來感覺呀 spruce-android劳秋,在BaseActivity封裝簡(jiǎn)單的給大家演示下滩褥,具體封裝大家去實(shí)現(xiàn)

/**
 * File descripition: activity基類
 * <p>
 *
 * @author lp
 * @date 2018/5/16
 */
public abstract class BaseActivityNall extends AppCompatActivity implements BaseView {
    public TextView mBackName;
    public LinearLayout mBack;
    public TextView mTvTitle;
    public TextView mTvRight;
    public RelativeLayout mRltBase;

    public int mIndex = BaseContent.baseIndex;

    protected View rootView;
    protected LoadService mBaseLoadService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        rootView = View.inflate(this, R.layout.activity_title, null);
        setContentView(getLayoutId());
        addContent();
        setContentView(rootView);

        this.initData();
        this.getData();

    }

    private void addContent() {
        mBackName = (TextView) rootView.findViewById(R.id.back_name);
        mBack = (LinearLayout) rootView.findViewById(R.id.back);
        mTvTitle = (TextView) rootView.findViewById(R.id.tv_title);
        mTvRight = (TextView) rootView.findViewById(R.id.tv_right);
        mRltBase = (RelativeLayout) rootView.findViewById(R.id.rlt_base);
        FrameLayout flContent = (FrameLayout) rootView.findViewById(R.id.fl_content);

        mTvTitle.setText(getContentTitle() == null ? "" : getContentTitle());
        mBack.setOnClickListener(v -> finish());//java8寫法胸懈,特此備注一下

        View content = View.inflate(this, getLayoutId(), null);
        if (content != null) {
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                    FrameLayout.LayoutParams.MATCH_PARENT);
            flContent.addView(content, params);
            ButterKnife.bind(this, rootView);
            mBaseLoadService = LoadSir.getDefault().register(content, new Callback.OnReloadListener() {
                @Override
                public void onReload(View v) {
                    onNetReload(v);
                }
            });
        }
    }
    protected void onNetReload(View v) {
        mBaseLoadService.showCallback(LoadingCallback.class);
        mIndex = BaseContent.baseIndex;
        getData();
    }
    /**
     * 獲取布局ID
     *
     * @return
     */
    protected abstract int getLayoutId();
    /**
     * title賦值
     *
     * @return
     */
    protected abstract String getContentTitle();
    /**
     * 數(shù)據(jù)初始化操作
     */
    protected abstract void initData();
    /**
     * 請(qǐng)求數(shù)據(jù)
     */
    protected abstract void getData();
}
9胁后、點(diǎn)擊Edittext彈出軟鍵盤贬蛙,點(diǎn)擊空白區(qū)域讓軟鍵盤消失

在我們使用Edittext時(shí)鹰晨,軟鍵盤彈出了忧侧,寫完字之后年枕,想讓它消失标捺,不去處理想讓軟鍵盤消失需要點(diǎn)擊軟鍵盤中的消失按鈕胖笛,顯然不是很方便的方法,我們想點(diǎn)擊非Edittext任何地方都讓軟鍵盤(也可以點(diǎn)擊Edittext讓軟鍵盤消失)宜岛,請(qǐng)往下看长踊,有倆種實(shí)現(xiàn)方法
(1)、第一種實(shí)現(xiàn)方法萍倡,擴(kuò)展性差

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            View v = getCurrentFocus();
            if (isShouldHideKeyboard(v, ev)) {
                hideKeyboard(v.getWindowToken());
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    /**
     * 根據(jù)EditText所在坐標(biāo)和用戶點(diǎn)擊的坐標(biāo)相對(duì)比身弊,來判斷是否隱藏鍵盤,因?yàn)楫?dāng)用戶點(diǎn)擊EditText時(shí)則不能隱藏
     *
     * @param v
     * @param event
     * @return
     */
    private boolean isShouldHideKeyboard(View v, MotionEvent event) {
        if (v != null && (v instanceof EditText)) {
            int[] l = {0, 0};
            v.getLocationInWindow(l);
            int left = l[0],
                    top = l[1],
                    bottom = top + v.getHeight(),
                    right = left + v.getWidth();
            if (event.getX() > left && event.getX() < right
                    && event.getY() > top && event.getY() < bottom) {
                // 點(diǎn)擊EditText的事件,忽略它阱佛。
                return false;
            } else {
                return true;
            }
        }
        // 如果焦點(diǎn)不是EditText則忽略帖汞,這個(gè)發(fā)生在視圖剛繪制完,第一個(gè)焦點(diǎn)不在EditText上凑术,和用戶用軌跡球選擇其他的焦點(diǎn)
        return false;
    }

    /**
     * 獲取InputMethodManager翩蘸,隱藏軟鍵盤
     *
     * @param token
     */
    private void hideKeyboard(IBinder token) {
        if (token != null) {
            InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            im.hideSoftInputFromWindow(token, InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

(2)、第二種實(shí)現(xiàn)方法(推薦使用)


    /**
     * 以下是關(guān)于軟鍵盤的處理
     */

    /**
     * 清除editText的焦點(diǎn)
     *
     * @param v   焦點(diǎn)所在View
     * @param ids 輸入框
     */
    public void clearViewFocus(View v, int... ids) {
        if (null != v && null != ids && ids.length > 0) {
            for (int id : ids) {
                if (v.getId() == id) {
                    v.clearFocus();
                    break;
                }
            }
        }
    }

    /**
     * 隱藏鍵盤
     *
     * @param v   焦點(diǎn)所在View
     * @param ids 輸入框
     * @return true代表焦點(diǎn)在edit上
     */
    public boolean isFocusEditText(View v, int... ids) {
        if (v instanceof EditText) {
            EditText et = (EditText) v;
            for (int id : ids) {
                if (et.getId() == id) {
                    return true;
                }
            }
        }
        return false;
    }

    //是否觸摸在指定view上面,對(duì)某個(gè)控件過濾
    public boolean isTouchView(View[] views, MotionEvent ev) {
        if (views == null || views.length == 0) {
            return false;
        }
        int[] location = new int[2];
        for (View view : views) {
            view.getLocationOnScreen(location);
            int x = location[0];
            int y = location[1];
            if (ev.getX() > x && ev.getX() < (x + view.getWidth())
                    && ev.getY() > y && ev.getY() < (y + view.getHeight())) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            if (isTouchView(filterViewByIds(), ev)) {
                return super.dispatchTouchEvent(ev);
            }
            if (hideSoftByEditViewIds() == null || hideSoftByEditViewIds().length == 0) {
                return super.dispatchTouchEvent(ev);
            }
            View v = getCurrentFocus();
            if (isFocusEditText(v, hideSoftByEditViewIds())) {
                KeyBoardUtils.hideInputForce(this);
                clearViewFocus(v, hideSoftByEditViewIds());
            }
        }
        return super.dispatchTouchEvent(ev);
    }


    /**
     * 傳入EditText的Id
     * 沒有傳入的EditText不做處理
     *
     * @return id 數(shù)組
     */
    public int[] hideSoftByEditViewIds() {
        return null;
    }

    /**
     * 傳入要過濾的View
     * 過濾之后點(diǎn)擊將不會(huì)有隱藏軟鍵盤的操作
     *
     * @return id 數(shù)組
     */
    public View[] filterViewByIds() {
        return null;
    }

使用方法:在對(duì)應(yīng)的Activity重寫hideSoftByEditViewIds()和filterViewByIds()淮逊,傳入需要彈出的軟鍵盤的ID

 /*實(shí)現(xiàn)案例===============================================================================================*/

    @Override
    public int[] hideSoftByEditViewIds() {
        int[] ids = {R.id.et_company_name, R.id.et_address};
        return ids;
    }

    @Override
    public View[] filterViewByIds() {
        View[] views = {mEtCompanyName, mEtAddress};
        return views;
    }

10催首、結(jié)合MVP模式下的BaseActivity,傳送地址
/**
 * File descripition: activity基類
 * <p>
 *
 * @author lp
 * @date 2018/5/16
 */
public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements BaseView {
    protected final String TAG = this.getClass().getSimpleName();
    public View mViewStatusBar;
    public TextView mBackName;
    public LinearLayout mBack;
    public TextView mTvTitle;
    public TextView mTvRight;
    public RelativeLayout mRltBase;

    public Activity mContext;
    protected P mPresenter;

    private LoadingDialog mLodingDialog;

    protected abstract P createPresenter();

    //錯(cuò)誤提示框  警告框  成功提示框
    private PromptDialog promptDialog;

    public int mIndex = BaseContent.baseIndex;

    protected View rootView;
    protected LoadService mBaseLoadService;

    /**
     * 是否顯示初始Loading
     */
    private Boolean isShow = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//設(shè)置豎屏模式
        mContext = this;
        rootView = View.inflate(this, R.layout.activity_title, null);
        setContentView(getLayoutId());
        addContent();
        setContentView(rootView);
        mPresenter = createPresenter();
        AppManager.getAppManager().addActivity(this);
        setStatusBar();
        initAppStatus();
        ButterKnife.bind(this);

        this.initData();

    }

    private void initAppStatus() {
        switch (AppStatusManager.getInstance().getAppStatus()) {
            /**
             * 應(yīng)用被強(qiáng)殺
             */
            case AppStatusConstant.STATUS_FORCE_KILLED:
                //跳到主頁,主頁lauchmode SINGLETASK
                protectApp();
                break;
        }
    }

    private void addContent() {
        mViewStatusBar = (View) rootView.findViewById(R.id.view_status_bar);
        mBackName = (TextView) rootView.findViewById(R.id.back_name);
        mBack = (LinearLayout) rootView.findViewById(R.id.back);
        mTvTitle = (TextView) rootView.findViewById(R.id.tv_title);
        mTvRight = (TextView) rootView.findViewById(R.id.tv_right);
        mRltBase = (RelativeLayout) rootView.findViewById(R.id.rlt_base);
        FrameLayout flContent = (FrameLayout) rootView.findViewById(R.id.fl_content);

        mTvTitle.setText(getContentTitle() == null ? "" : getContentTitle());
        mBack.setOnClickListener(v -> finish());

        View content = View.inflate(this, getLayoutId(), null);
        if (content != null) {
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                    FrameLayout.LayoutParams.MATCH_PARENT);
            flContent.addView(content, params);
            ButterKnife.bind(this, rootView);
            mBaseLoadService = LoadSir.getDefault().register(content, new Callback.OnReloadListener() {
                @Override
                public void onReload(View v) {
                    showLoadingLayout();
                    mIndex = BaseContent.baseIndex;
                    getData();
                }
            });
            if (isShow) {
                showLoadingLayout();
            } else {
                PostUtil.postSuccessDelayed(mBaseLoadService, 0);
            }
        }
    }

    protected void protectApp() {
        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtra(AppStatusConstant.KEY_HOME_ACTION, AppStatusConstant.ACTION_RESTART_APP);
        startActivity(intent);
    }

    private void showLoadingLayout() {
        mBaseLoadService.showCallback(LoadingCallback.class);
    }

    public void showLoadingLayout(boolean isShow) {
        this.isShow = isShow;
    }

    /**
     * 獲取布局ID
     *
     * @return
     */
    protected abstract int getLayoutId();

    /**
     * title賦值
     *
     * @return
     */

    protected abstract String getContentTitle();

    /**
     * 數(shù)據(jù)初始化操作
     */
    protected abstract void initData();

    /**
     * 請(qǐng)求數(shù)據(jù)
     */
    protected abstract void getData();

    /**
     * 沉浸式實(shí)現(xiàn)
     */
    protected void setStatusBar() {
        StatusBarUtil.setColor(this, getResources().getColor(R.color.colorWhite), 0);
//        StatusBarUtil.setTranslucentForImageViewInFragment(this, 0, null);
    }

    public void showToast(String str) {
        showToast(str, Toast.LENGTH_SHORT);
    }

    public void showLongToast(String str) {
        showToast(str, Toast.LENGTH_LONG);
    }

    /**
     * 封裝toast方法
     *
     * @param str
     * @param dur
     */
    void showToast(String str, int dur) {
        ToastUtils.showToastS(this, str, dur);
    }

    @Override
    public void showError(String msg) {
        showToast(msg);
    }

    @Override
    public void onErrorCode(BaseModel model) {
        if (model.getErrcode() == BaseObserver.NETWORK_ERROR) {//網(wǎng)絡(luò)連接失敗  無網(wǎng)
            PostUtil.postCallbackDelayed(mBaseLoadService, NetWorkErrorCallback.class);
        } else if (model.getErrcode() == BaseObserver.CONNECT_ERROR ||//連接錯(cuò)誤
                model.getErrcode() == BaseObserver.CONNECT_TIMEOUT ||//連接超時(shí)
                model.getErrcode() == BaseObserver.BAD_NETWORK ||//網(wǎng)絡(luò)超時(shí)
                model.getErrcode() == BaseObserver.CONNECT_NULL//數(shù)據(jù)為空,顯示異常
                ) {
            PostUtil.postCallbackDelayed(mBaseLoadService, ErrorCallback.class);
        } else if (model.getErrcode() == BaseObserver.CONNECT_NOT_LOGIN) {//沒有登錄泄鹏,去登錄
            startLogin();
        }
    }

    private void startLogin() {
        AppUMS.mIsLogin = false;
        AppUMS.setToken("");
        startActivity(LoginActivity.class);
    }
    @Override
    public void showLoading() {
        showLoadingDialog();
    }
    @Override
    public void hideLoading() {
        closeLoadingDialog();
    }
    public void closeLoadingDialog() {
        if (mLodingDialog != null && mLodingDialog.isShowing()) {
            mLodingDialog.dismiss();
        }
    }
    /**
     * 加載...
     */
    public void showLoadingDialog() {
        if (mLodingDialog == null) {
            mLodingDialog = new LoadingDialog(this).setMessage(getString(R.string.app_loding));
        }
        mLodingDialog.show();
    }
    /**
     * 警告框
     */
    public void showInfoDialog(String msg) {
        if (promptDialog == null) {
            promptDialog = new PromptDialog(this);
        }
        promptDialog.showInfo(msg);
    }
    /**
     * 錯(cuò)誤提示框
     */
    public void showErrorDialog(String msg) {
        if (promptDialog == null) {
            promptDialog = new PromptDialog(this);
        }
        promptDialog.showError(msg);
    }
    /**
     * 成功提示框
     */
    public void showSuccessDialog(String msg) {
        if (promptDialog == null) {
            promptDialog = new PromptDialog(this);
        }
        promptDialog.showSuccess(msg);
    }
    @Override
    protected void onResume() {
        super.onResume();
        MobclickAgent.onResume(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        MobclickAgent.onPause(this);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        ButterKnife.bind(this).unbind();
        AppManager.getAppManager().finishActivity(this);
        if (mPresenter != null) {
            mPresenter.detachView();
        }
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
                && event.getAction() == KeyEvent.ACTION_DOWN) {
            finishActivity();
            return false;
        }
        return super.dispatchKeyEvent(event);
    }
    public void finishActivity() {
        finish();
    }
    /**
     * [頁面跳轉(zhuǎn)]
     *
     * @param clz
     */
    public void startActivity(Class<?> clz) {
        startActivity(clz, null);
    }
    /**
     * [攜帶數(shù)據(jù)的頁面跳轉(zhuǎn)]
     *
     * @param clz
     * @param bundle
     */
    public void startActivity(Class<?> clz, Bundle bundle) {
        Intent intent = new Intent();
        intent.setClass(this, clz);
        if (bundle != null) {
            intent.putExtras(bundle);
        }
        startActivity(intent);
    }
    /**
     * [含有Bundle通過Class打開編輯界面]
     *
     * @param cls
     * @param bundle
     * @param requestCode
     */
    public void startActivityForResult(Class<?> cls, Bundle bundle, int requestCode) {
        Intent intent = new Intent();
        intent.setClass(this, cls);
        if (bundle != null) {
            intent.putExtras(bundle);
        }
        startActivityForResult(intent, requestCode);
    }
    /**
     * 以下是關(guān)于軟鍵盤的處理
     */
    /**
     * 清除editText的焦點(diǎn)
     *
     * @param v   焦點(diǎn)所在View
     * @param ids 輸入框
     */
    public void clearViewFocus(View v, int... ids) {
        if (null != v && null != ids && ids.length > 0) {
            for (int id : ids) {
                if (v.getId() == id) {
                    v.clearFocus();
                    break;
                }
            }
        }
    }

    /**
     * 隱藏鍵盤
     *
     * @param v   焦點(diǎn)所在View
     * @param ids 輸入框
     * @return true代表焦點(diǎn)在edit上
     */
    public boolean isFocusEditText(View v, int... ids) {
        if (v instanceof EditText) {
            EditText et = (EditText) v;
            for (int id : ids) {
                if (et.getId() == id) {
                    return true;
                }
            }
        }
        return false;
    }
    //是否觸摸在指定view上面,對(duì)某個(gè)控件過濾
    public boolean isTouchView(View[] views, MotionEvent ev) {
        if (views == null || views.length == 0) {
            return false;
        }
        int[] location = new int[2];
        for (View view : views) {
            view.getLocationOnScreen(location);
            int x = location[0];
            int y = location[1];
            if (ev.getX() > x && ev.getX() < (x + view.getWidth())
                    && ev.getY() > y && ev.getY() < (y + view.getHeight())) {
                return true;
            }
        }
        return false;
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            if (isTouchView(filterViewByIds(), ev)) {
                return super.dispatchTouchEvent(ev);
            }
            if (hideSoftByEditViewIds() == null || hideSoftByEditViewIds().length == 0) {
                return super.dispatchTouchEvent(ev);
            }
            View v = getCurrentFocus();
            if (isFocusEditText(v, hideSoftByEditViewIds())) {
                KeyBoardUtils.hideInputForce(this);
                clearViewFocus(v, hideSoftByEditViewIds());
            }
        }
        return super.dispatchTouchEvent(ev);
    }
    /**
     * 傳入EditText的Id
     * 沒有傳入的EditText不做處理
     *
     * @return id 數(shù)組
     */
    public int[] hideSoftByEditViewIds() {
        return null;
    }
    /**
     * 傳入要過濾的View
     * 過濾之后點(diǎn)擊將不會(huì)有隱藏軟鍵盤的操作
     *
     * @return id 數(shù)組
     */
    public View[] filterViewByIds() {
        return null;
    }
    /*實(shí)現(xiàn)案例===============================================================================================*/
    /*
    @Override
    public int[] hideSoftByEditViewIds() {
        int[] ids = {R.id.et_company_name, R.id.et_address};
        return ids;
    }
    @Override
    public View[] filterViewByIds() {
        View[] views = {mEtCompanyName, mEtAddress};
        return views;
    }
    */
}

最后郎任,祝大家開發(fā)順利!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市备籽,隨后出現(xiàn)的幾起案子舶治,更是在濱河造成了極大的恐慌,老刑警劉巖车猬,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件霉猛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡珠闰,警方通過查閱死者的電腦和手機(jī)韩脏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铸磅,“玉大人,你說我怎么就攤上這事杭朱≡淖校” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵弧械,是天一觀的道長(zhǎng)八酒。 經(jīng)常有香客問我,道長(zhǎng)刃唐,這世上最難降的妖魔是什么羞迷? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮画饥,結(jié)果婚禮上衔瓮,老公的妹妹穿的比我還像新娘。我一直安慰自己抖甘,他們只是感情好热鞍,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般薇宠。 火紅的嫁衣襯著肌膚如雪偷办。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天澄港,我揣著相機(jī)與錄音椒涯,去河邊找鬼。 笑死回梧,一個(gè)胖子當(dāng)著我的面吹牛废岂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播漂辐,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼泪喊,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了髓涯?” 一聲冷哼從身側(cè)響起袒啼,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纬纪,沒想到半個(gè)月后蚓再,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡包各,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年摘仅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片问畅。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡娃属,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出护姆,到底是詐尸還是另有隱情矾端,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布卵皂,位于F島的核電站秩铆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏灯变。R本人自食惡果不足惜殴玛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望添祸。 院中可真熱鬧滚粟,春花似錦、人聲如沸刃泌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鲤遥,卻和暖如春沐寺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盖奈。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工混坞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人钢坦。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓究孕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親爹凹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子厨诸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容