在Android开发中,activity再常用不过了,为了高效开发,我们会将一些常用的功能和页面统一实现的效果放在基类,这样就不用写每个页面时再重新实现这些功能。
在日常开发的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);
}
为了让用户感受更好的体验效果,所以我们会选择设置沉浸式,每个页面大多数都会设置一种效果,所以直接在BaseActivity设置即可
/**
* 沉浸式实现
*/
protected void setStatusBar() {
StatusBarUtils.transparencyBar(this)
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStatusBar();
}
关于沉浸式实现可以查看Android 状态栏工具类——修改状态栏颜色以及状态栏字体颜色
/**
* [页面跳转]
*
* @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);
}
可以少写几个代码,没错程序员就是这么懒 。
在我们使用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;
}
新建一个关于title的xml,title_back.xml
根布局,common_activity_root.xml
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);
}
}
Loading加载动画界面common_view_trans_loading.xml
common_stub_trans_loading.xml
根布局,common_activity_root.xml
Loading的控制器
/**
* Description:
* Author: mxdl
* Date: 2019/3/25
* Version: V1.0.0
* Update:
*/
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);
}
}
具体的使用方式可以参考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();
}
具体的使用方式可以参考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);
}
}