Android封装含有通用标题栏的基类BaseActivity
安卓開發中,經常會遇到項目的標題欄基本樣式都是一致的,只有個別界面需要定制化,而TitltBar或許跟我們的業務需求不是很相符,所以很多時候我們都想要去封裝一個含有通用標題欄并且可定制化的BaseActivity。本文希望對有這方面需求的童鞋提供一種參考。效果圖類似于這樣
首先很多開發者比較喜歡的一種做法是寫一份通用的標題欄布局,然后在每次創建的Activity的布局文件中去選擇include的方式加入布局,這種方式其實在我看來工作量其實還是挺大,為了使用的時候更方便,可以將寫好的標題欄布局作為一個View添加到根布局中。
下面先貼出標題欄的布局:
<?xml version="1.0" encoding="utf-8"?> <!-- 默認TitleBar布局文件 --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="44dp"android:background="@color/white"><TextViewandroid:id="@+id/tv_titlebar_name"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:paddingLeft="90dp"android:paddingRight="90dp"android:singleLine="true"android:text="@string/app_name"android:textColor="@color/color_333333"android:textSize="18sp" /><TextViewandroid:id="@+id/tv_titlebar_left"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_alignParentLeft="true"android:drawableLeft="@mipmap/icon_back"android:gravity="center"android:paddingLeft="8dp"android:paddingRight="8dp"android:layout_centerVertical="true"android:textColor="@color/white"android:textSize="14sp" /><TextViewandroid:id="@+id/tv_titlebar_right"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_alignParentRight="true"android:gravity="center"android:paddingLeft="5dp"android:paddingRight="15dp"android:text="@string/app_name"android:textColor="@color/color_333333"android:textSize="14sp" /><TextViewandroid:id="@+id/tv_titlebar_more"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_toLeftOf="@id/tv_titlebar_right"android:gravity="center"android:paddingLeft="5dp"android:paddingRight="5dp"android:text="@string/app_name"android:textColor="@color/color_333333"android:textSize="14sp" /></RelativeLayout></LinearLayout>這里講一下為什么返回按鍵,中間標題,右邊兩個小標題都選用了TextView,因為我的想法是為了讓標題欄按鈕是圖標的時候,可以更快捷的使用。畢竟TextView還可以在它的上下左右動態添加Drawable嘛。還有一點,為什么選用線性布局中嵌套了一個相對布局,那是因為我考慮到以后可能會存在需要在標題欄下面添加一些類似于間隔啊之類的布局,所以就給預留出來了,如果不需要的話,可以選擇去掉外層的線性布局。標題欄的右側我自己是添加了兩個預留的按鈕,可以方便右上角存在比如保存、分享之類的操作。
下面貼一下不含標題欄的基類BaseActivity的代碼:
/*** Activity基類*/ public class BaseActivity extends FragmentActivity {protected int mResultCode = RESULT_CANCELED;private int mStatusHeight;// 狀態欄高度private int mTitleHeight;// 標題欄高度private int mScreenWidth, mScreenHeight;// 屏幕寬度、高度protected boolean mIsFirst = true;// true-界面第一次聚焦private RequestUploadDialog mUploadDialog;// 加載框@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityStackUtils.getInstance().pushActivity(this);// activity入棧管理}@Overrideprotected void onResume() {super.onResume();}@Overrideprotected void onPause() {super.onPause();}@Overrideprotected void onStart() {super.onStart();}@Overrideprotected void onStop() {super.onStop();}@Overrideprotected void onDestroy() {super.onDestroy();ActivityStackUtils.getInstance().finishActivity(this);// activity出棧管理}/*** 隱藏鍵盤*/public void hideKeyBoard() {try {View rootView = this.getWindow().getDecorView();View focusView = rootView.findFocus();if (focusView != null) {int viewId = focusView.getId();View view = findViewById(viewId);if (view instanceof EditText) {InputMethodManager manager = (InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);manager.hideSoftInputFromWindow(view.getWindowToken(), 0);}}} catch (Exception e) {e.printStackTrace();}}/*** 獲取狀態欄高度* @return 狀態欄高度(px)*/public int statusHeight() {if (mStatusHeight == 0) {try {Class<?> c = Class.forName("com.android.internal.R$dimen");int x = Integer.parseInt(c.getField("status_bar_height").get(c.newInstance()).toString());mStatusHeight = getResources().getDimensionPixelSize(x);} catch (Exception e1) {e1.printStackTrace();}}return mStatusHeight;}/*** 獲取屏幕寬度* @return 屏幕寬度(px)*/public int screenWidth() {if (mScreenWidth == 0) {DisplayMetrics displayMetrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);mScreenWidth = displayMetrics.widthPixels;}return mScreenWidth;}/*** 獲取屏幕高度* @return 屏幕高度(px)*/public int screenHeight() {if (mScreenHeight == 0) {DisplayMetrics displayMetrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);mScreenHeight = displayMetrics.heightPixels;}return mScreenHeight;}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK) {return executeKeyDownBack(keyCode, event);}return super.onKeyDown(keyCode, event);}/*** 監聽返回鍵* @param keyCode 鍵值* @param event 事件* @return true-消耗事件,false-不消耗事件*/protected boolean executeKeyDownBack(int keyCode, KeyEvent event) {return super.onKeyDown(keyCode, event);}/*** Home鍵監聽回調方法* @param context 上下文環境* @param intent 意圖*/public void onHomeWatcherReceiver(Context context, Intent intent) {}/*** 顯示加載框* @param uploadResId 資源ID*/public void showUpload(int uploadResId) {showUpload(getString(uploadResId));}/*** 顯示加載框* @param uploadContent 文本*/public void showUpload(String uploadContent) {if (mUploadDialog == null)mUploadDialog = new RequestUploadDialog(this);mUploadDialog.showText(uploadContent).show();}/*** 隱藏加載框*/public void hideUpload() {if (mUploadDialog == null)return;mUploadDialog.dismiss();}/*** 顯示提示語* @param toastResId 資源ID*/public void showToast(int toastResId) {Toast.makeText(this, toastResId, Toast.LENGTH_SHORT).show();}/*** 顯示提示語* @param toastText 文本*/public void showToast(String toastText) {Toast.makeText(this, toastText, Toast.LENGTH_SHORT).show();}/*** 設置TextView的left圖片(不添加文字)* @param textView 控件* @param resIds 資源ID*/public void drawableLeft(TextView textView, int resIds) {textView.setVisibility(TextView.VISIBLE);textView.setText("");Drawable drawable = getResources().getDrawable(resIds);drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());textView.setCompoundDrawables(drawable, null, null, null);}/*** 設置TextView的right圖片(不添加文字)* @param textView 控件* @param resIds 資源ID*/public void drawableRight(TextView textView, int resIds) {textView.setVisibility(TextView.VISIBLE);textView.setText("");Drawable drawable = getResources().getDrawable(resIds);drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());textView.setCompoundDrawables(null, null, drawable, null);}/*** 設置TextView顏色* @param textView 控件* @param resId 資源ID*/public void textColor(TextView textView, int resId) {textView.setTextColor(getResources().getColor(resId));}/*** 著色狀態欄(4.4以上系統有效)*/protected void SetStatusBarColor() {StatusBarCompat.setStatusBarColor(this, ContextCompat.getColor(this, R.color.base_color));}/*** 著色狀態欄(4.4以上系統有效)*/protected void SetStatusBarColor(int color) {StatusBarCompat.setStatusBarColor(this, color);}/*** 沉浸狀態欄(4.4以上系統有效),全屏模式*/protected void SetTranslanteBar() {StatusBarCompat.translucentStatusBar(this);}@Overridepublic void startActivity(Intent intent) {super.startActivity(intent);overridePendingTransition(R.anim.anim_right2enter, R.anim.anim_left2exit);}/*** 通過 Class 跳轉界面,不含參數**/public void startActivity(Class<?> cls) {startActivity(cls, null);}/*** 含有 Bundle 通過 Class 跳轉界面* 帶有跳轉動畫**/public void startActivity(Class<?> cls, Bundle bundle) {Intent intent = new Intent();intent.setClass(this, cls);if (bundle != null) {intent.putExtras(bundle);}startActivity(intent);overridePendingTransition(R.anim.anim_right2enter, R.anim.anim_left2exit);}/*** 通過 Class 跳轉界面**/public void startActivityForResult(Class<?> cls, int requestCode) {startActivityForResult(cls, null, requestCode);overridePendingTransition(R.anim.anim_right2enter, R.anim.anim_left2exit);}/*** 含有Bundle通過Class跳轉界面**/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);overridePendingTransition(R.anim.anim_right2enter, R.anim.anim_left2exit);}/*** 跳轉到登錄界面*/public void jumpToLoginActivity(int requestCode) {Intent intent = new Intent(IntentAction.ACTION_LOGIN);startActivityForResult(intent, requestCode);overridePendingTransition(R.anim.anim_bottom_in, R.anim.anim_bottom_window);}@Overridepublic void finish() {super.finish();}/*** finish 當前界面,手動控制頁面關閉動畫** @param closeAnim true:關閉時有動畫,false:關閉是無動畫*/public void finish(boolean closeAnim) {super.finish();if (closeAnim) {overridePendingTransition(R.anim.anim_left2enter, R.anim.anim_right2exit);}}}里面封裝了一些其他比較常用的方法,有幾個細節的點可以描述一下
1.里面封裝了通用的彈toast和彈加載框的方法,當然加載框大家也可以封裝到網絡請求模塊和本地數據庫操作中去,這個看個人的喜好
2.基類中包含有軟鍵盤的關閉操作,因為安卓的軟鍵盤一直是一個比較頭疼的問題,所以我選擇直接封裝到基類中,如果需要用到某些操作需要關閉軟鍵盤的可以直接調用
3.封裝的有對某個TextView添加Drawable的方法,這樣標題欄需要加載圖標的時候,方便調用
4.封裝的有修改狀態欄顏色和主題的方法,但是StatusBarCompat這個工具類我沒有貼出來,不知道其中操作細節的可以去網上自行搜索查看
下面就是對含有標題欄的Activity的封裝了,思路文章開頭已經提到過,就直接上代碼吧:
/*** Activity基類:含TitleBar*/ public class BaseTitleBarActivity extends BaseViewStubActivity {protected TextView mTvCenter, mTvLeft, mTvRight, mTvMore;protected View mViewTitleBar;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}@Overridepublic void setContentView(int layoutResID) {super.setContentView(layoutResID);}@Overrideprotected void addTitleBarView() {mViewTitleBar = View.inflate(this, addTitleBarLayout(), null);mTvCenter = mViewTitleBar.findViewById(R.id.tv_titlebar_name);mTvLeft = mViewTitleBar.findViewById(R.id.tv_titlebar_left);mTvRight = mViewTitleBar.findViewById(R.id.tv_titlebar_right);mTvMore = mViewTitleBar.findViewById(R.id.tv_titlebar_more);mTvLeft.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {onTitleBarClickLeft(v);}});mTvRight.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {onTitleBarClickRight(v);}});mTvCenter.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {onTitleBarClickCenter(v);}});mTvMore.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {onTitleBarClickMore(v);}});onChangedTitleBar(mTvLeft, mTvCenter, mTvRight);mLayoutContent.addView(mViewTitleBar);}/*** 設置TitleBar布局* @return TitleBar布局*/protected int addTitleBarLayout() {return R.layout.layout_base_titlebar;}/*** 修改TitleBar* @param left 左邊按鈕* @param center 中間文本* @param right 右邊按鈕,默認隱藏*/protected void onChangedTitleBar(TextView left, TextView center, TextView right) {right.setVisibility(View.GONE);mTvMore.setVisibility(View.GONE);}/*** TitleBar左邊按鈕點擊事件* @param view 控件*/protected void onTitleBarClickLeft(View view) {setResult(mResultCode);finish();}/*** TitleBar右邊按鈕點擊事件* @param view 控件*/protected void onTitleBarClickRight(View view) {}/*** TitleBar右邊(更多)按鈕點擊事件* @param view 控件*/protected void onTitleBarClickMore(View view) {}/*** TitleBar中間按鈕點擊事件* @param view 控件*/protected void onTitleBarClickCenter(View view) {}/*** 獲取焦點* @param view 控件*/public void requestFocus(final View view) {view.postDelayed(new Runnable() {@Overridepublic void run() {view.setFocusable(true);view.setFocusableInTouchMode(true);view.requestFocus();}}, 100);} }BaseViewStubActivity的代碼如下:
/*** Activity基類:不含TitleBar*/ public class BaseViewStubActivity extends BaseActivity {protected LinearLayout mLayoutContent;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}@Overridepublic void setContentView(int layoutResID) {// 設置狀態欄顏色 // SetTranslanteBar();super.setContentView(R.layout.activity_base_titlebar);mLayoutContent = findViewById(R.id.ll_content_view);addTitleBarView(); // 添加TitleBaraddContentView(layoutResID);// 添加ContentView}/*** 添加TitleBar*/protected void addTitleBarView() {}/*** 添加ContentView* @param layoutResID 布局*/protected void addContentView(int layoutResID) {View.inflate(this, layoutResID, mLayoutContent);} }這里相關的activity_base_titlebar布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <!-- Activity基類默認加載的布局文件 --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:id="@+id/ll_content_view"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"></LinearLayout></RelativeLayout>這樣一來,使用的時候只需要繼承自BaseTitlebarActivity并實現onChangedTitleBar就可以隨意對標題欄進行定制化了,對左上角的按鈕點擊方法是默認的對出操作,如果需要重寫,也可以自己重新對該方法進行實現,標題欄每個按鈕的點擊操作都是單獨出來的,需要點擊操作的時候再進行重寫。
效果圖就不上了,談一談封裝過程中遇到的一個最主要的問題吧
最初在封裝BaseViewStubActivity的時候addContentView方法中我是使用的
mLayoutContent.addView(View.inflate(this, layoutResID, null));這種方式進行添加,運行起來最初沒有發現什么問題,但是一旦遇到相對布局的時候,需要在底部添加一個按鈕的時候,發現最底部的控件的margin_bottom會失效,后來查閱了很多資料,原來是執行這句代碼的時候,子布局其實并沒有掛載到父布局中,所以造成了控件的布局寬高屬性都為默認的LayoutParams.WRAP_CONTENT自適應,不清楚的可以去閱讀以下addView的源碼,所以解決這個的方法有兩種:
第一種:修改添加子布局的方式為View.inflate(this, layoutResID, mLayoutContent);
第二種:掛載的方式修改為
mLayoutContent.addView(View.inflate(this, layoutResID, null), new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
也就是手動賦予子布局一個布局參數。
?
補充:
在繼承自BaseTitlebarActivity的activity中同樣也可以調用addTitleBarLayout方法來加載另外的標題欄布局,但是此時由于在上一級基類Activity中已經對標題欄進行了操作,所以請務必保持加載的新標題欄布局的每個控件id和通用標題欄的控件id一致,否則會造成空指針異常,當然如果只是對標題欄的顏色或者字體顏色那些修改的話,也提供兩種思路,一種是定義另外一個主題顏色的標題欄布局,但是id與通用標題欄每個控件id一致;第二種是在上一級基類Activity中開放另外一個方法,調用時動態更新主題顏色等。
如果有問題歡迎指出,非常感謝!
?
總結
以上是生活随笔為你收集整理的Android封装含有通用标题栏的基类BaseActivity的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新硬盘稳定性测试软件,硬盘及整机稳定性测
- 下一篇: java ssi_java SSI id