Android 高效开发——浅谈BaseActivity写法

前言

在Android开发中,activity再常用不过了,为了高效开发,我们会将一些常用的功能和页面统一实现的效果放在基类,这样就不用写每个页面时再重新实现这些功能。

基本功能

  1. 屏幕横竖屏切换
  2. 沉浸式实现
  3. 携带数据的页面跳转
  4. 点击Edittext弹出软键盘,点击空白区域让软键盘消失
  5. 标题栏统一实现
  6. Loading页面统一实现
  7. ButterKnife绑定页面
  8. EventBus订阅与解除订阅

 

1.屏幕横竖屏切换

在日常开发的app,一般情况下都是手机上的应用,我们经常设置了强制竖屏,因为横屏没有特殊要求没有必要去设置,设置了反而会出现更多问题,其次说一下8.0更新问题,页面同时设置了android:screenOrientation="portrait"和透明属性,8.0运行会出现Only fullscreen opaque activities can request orientation异常,大概意思为“只有不透明的全屏activity可以自主设置界面方向”,我们或许会引用一些第三方SDK到项目中,也许第三方会用到透明属性,所以建议在BaseActivity设置横竖屏。

    /**
     * 设置屏幕横竖屏切换
     *
     * @param screenRoate true  竖屏     false  横屏
     */
    private void setScreenRoate(Boolean screenRoate) {
        if (screenRoate) {
            //设置竖屏模式
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        } else {
            //设置横屏模式
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setScreenRoate(true);
    }

2.沉浸式实现

为了让用户感受更好的体验效果,所以我们会选择设置沉浸式,每个页面大多数都会设置一种效果,所以直接在BaseActivity设置即可

    /**
     * 沉浸式实现
     */
    protected void setStatusBar() {
        StatusBarUtils.transparencyBar(this)
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStatusBar();
    }

关于沉浸式实现可以查看Android 状态栏工具类——修改状态栏颜色以及状态栏字体颜色

 

3.携带数据的页面跳转

     /**
     * [页面跳转]
     *
     * @param clz
     */
    public void startActivity(Class<?> clz) {
        startActivity(clz, null);
    }
    /**
     * [携带数据的页面跳转]
     *
     * @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);
    }

可以少写几个代码,没错程序员就是这么懒 。

4.点击Edittext弹出软键盘,点击空白区域让软键盘消失

在我们使用Edittext时,软键盘弹出了,写完字之后,想让它消失,不去处理想让软键盘消失需要点击软键盘中的消失按钮,显然不是很方便的方法,我们想点击非Edittext任何地方都让软键盘消失。

    /**
     * 以下是关于软键盘的处理
     */

    /**
     * 清除editText的焦点
     *
     * @param v   焦点所在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;
                }
            }
        }
    }

    /**
     * 收起键盘
     */
    protected void hideKeyboard() {
        InputMethodManager imm = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
        // 隐藏软键盘
        imm.hideSoftInputFromWindow(this.getWindow().getDecorView().getWindowToken(), 0);
    }

    /**
     * 当前获得的焦点是否是需要处理的EditText
     *
     * @param v   焦点所在View
     * @param ids 输入框
     * @return true代表焦点在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上面,对某个控件过滤
    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())) {
                hideKeyboard();
                clearViewFocus(v, hideSoftByEditViewIds());
            }
        }
        return super.dispatchTouchEvent(ev);
    }


    /**
     * 传入EditText的Id
     * 没有传入的EditText不做处理
     *
     * @return id 数组
     */
    public int[] hideSoftByEditViewIds() {
        return null;
    }

    /**
     * 传入要过滤的View
     * 过滤之后点击将不会有隐藏软键盘的操作
     *
     * @return id 数组
     */
    public View[] filterViewByIds() {
        return null;
    }

使用方法:在对应的Activity重写hideSoftByEditViewIds()和filterViewByIds(),传入需要弹出的软键盘的ID。

    //传入EditText的Id
    @Override
    public int[] hideSoftByEditViewIds() {
        int[] ids = {R.id.et_company_name, R.id.et_address};
        return ids;
    }
    //传入要过滤的View,过滤之后点击将不会有隐藏软键盘的操作
    @Override
    public View[] filterViewByIds() {
        View[] views = {mEtCompanyName, mEtAddress};
        return views;
    }

 

5.标题栏统一实现

新建一个关于title的xml,title_back.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="85dp"
    android:background="#FF0F58A3">

    <TextView
        android:id="@+id/tv_title_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="17dp"
        android:gravity="center"
        android:text="个人中心"
        android:textColor="#FFFFFFFF"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <ImageView
        android:id="@+id/iv_title_back"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        app:layout_constraintBottom_toBottomOf="@+id/tv_title_title"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/tv_title_title"
        app:srcCompat="@mipmap/ico_back_white"
        android:paddingLeft="20dp" />

    <ImageView
        android:id="@+id/iv_title_menu"
        android:layout_width="25dp"
        android:layout_height="25dp"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="@+id/tv_title_title"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@+id/tv_title_title"
        android:layout_marginRight="18dp" />


</androidx.constraintlayout.widget.ConstraintLayout>

根布局,common_activity_root.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

        <include
            android:id="@+id/titleLayout"
            layout="@layout/title_back"
            android:visibility="gone" />
        <FrameLayout
            android:id="@+id/contentContainer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/titleLayout" />
        <ViewStub
            android:id="@+id/view_stub_trans_loading"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout="@layout/common_stub_trans_loading"/>

</RelativeLayout>

BaseActivity.java实现

/**
 * @Author matt.Ljp
 * @Time 2019/8/26  15:32
 * @Description This is BaseActivity
 */
public abstract class BaseActivity extends AppCompatActivity {

    @BindView(R.id.iv_title_back)
    ImageView mivBack;
    @BindView(R.id.tv_title_title)
    TextView mTitle;
    @BindView(R.id.titleLayout)
    ConstraintLayout mTitleLayout;
    @BindView(R.id.iv_title_menu)
    ImageView ivTitleRight;

   


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.common_activity_root);
        mContext = this;
    
    }


    //设置标题
    protected void setTitleText(String title) {
        mTitleLayout.setVisibility(View.VISIBLE);
        mTitle.setText(title);
    }




    //设置标题
    protected void setTitleText(String title, int imgId, final OnRightImageClickListener onRightImageClickListener) {
        mTitleLayout.setVisibility(View.VISIBLE);
        ivTitleRight.setVisibility(View.VISIBLE);
        mTitle.setText(title);
        ivTitleRight.setImageResource(imgId);
        ivTitleRight.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onRightImageClickListener.onImageClick(mContext);
            }
        });
    }

    @OnClick(R.id.iv_title_back)
    public void onBackClicked() {
        finish();
    }


    protected void setOnLeftImageClickListener(OnLeftImageClickListener onLeftImageClickListener) {
        this.mOnLeftImageClickListener = onLeftImageClickListener;
    }

    //title右侧图片监听接口
    public interface OnRightImageClickListener {
        void onImageClick(Context context);
    }

}

6.Loading页面统一实现

Loading加载动画界面common_view_trans_loading.xml 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#80000000"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <View
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:background="@drawable/loading_bg"
        android:layout_centerInParent="true"
        />
    <ImageView
        android:id="@+id/img_trans_loading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/loading_anim"
        android:layout_centerInParent="true"
        />
</RelativeLayout>
common_stub_trans_loading.xml 
<?xml version="1.0" encoding="utf-8"?>
<com.matt.changeavatar.LoadingTransView
    android:id="@+id/view_trans_loading"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:android="http://schemas.android.com/apk/res/android"/>

根布局,common_activity_root.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include
        android:id="@+id/titleLayout"
        layout="@layout/title_back"
        android:visibility="gone" />

    <FrameLayout
        android:id="@+id/contentContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/titleLayout" />

    <ViewStub
        android:id="@+id/view_stub_trans_loading"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout="@layout/common_stub_trans_loading" />

</RelativeLayout>

Loading的控制器

/**
 * Description: <LoadingView><br>
 * Author:      mxdl<br>
 * Date:        2019/3/25<br>
 * Version:     V1.0.0<br>
 * Update:     <br>
 */
public class LoadingTransView extends RelativeLayout {
    private final AnimationDrawable mAnimationDrawable;
    public LoadingTransView(Context context, AttributeSet attrs) {
        super(context, attrs);
        inflate(context, R.layout.common_view_trans_loading,this);
        ImageView imgLoading = findViewById(R.id.img_trans_loading);
        mAnimationDrawable = (AnimationDrawable) imgLoading.getDrawable();
    }
    public void startLoading(){
        mAnimationDrawable.start();
    }
    public void stopLoading(){
        mAnimationDrawable.stop();
    }
    public void loading(boolean b){
        if(b){
            startLoading();
        }else{
            stopLoading();
        }
    }
}

 BaseActivity.java实现

/**
 * @Author matt.Ljp
 * @Time 2019/8/26  15:32
 * @Description This is BaseActivity
 */
public abstract class BaseActivity extends AppCompatActivity {

    protected Context mContext;
    protected LoadingTransView mLoadingTransView;
    private ViewStub mViewTransLoading;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.common_activity_root);
        mContext = this;
        initCommonView();
    }


 
    protected void initCommonView() {
        FrameLayout contentContainer = findViewById(R.id.contentContainer);
        // 加载内容布局
        View.inflate(mContext, onBindLayout(), contentContainer);
        mViewTransLoading = findViewById(R.id.view_stub_trans_loading);
    }


    protected void showTransLoadingView(boolean show) {
        if (mLoadingTransView == null) {
            View view = mViewTransLoading.inflate();
            mLoadingTransView = view.findViewById(R.id.view_trans_loading);
        }
        mLoadingTransView.setVisibility(show ? View.VISIBLE : View.GONE);
        mLoadingTransView.loading(show);
    }


}

7.ButterKnife绑定页面

具体的使用方式可以参考Android Butterknife使用方法

再BaseActivity中onCreate绑定页面 onDestroy取消绑定,子类就不需要再去注册和取消注册

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ButterKnife.bind(this);
    }
  @Override
    protected void onDestroy() {
        super.onDestroy();
        ButterKnife.bind(this).unbind();
    }

    

8.EventBus订阅与解除订阅

具体的使用方式可以参考Android事件传递——EventBus框架的使用

再BaseActivity中onCreate绑定页面 onDestroy取消绑定,子类就不需要再去订阅与解除订阅

public abstract class BaseActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getDefault().register(this);
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }
}

 

发布了63 篇原创文章 · 获赞 1 · 访问量 2101

猜你喜欢

转载自blog.csdn.net/weixin_42046829/article/details/104611597