這是我自己封裝的一個activity,主要作為所有Activity的基類,可以一鍵關掉所有的activity, 並共享一個自定義actionbar.直接切入主題吧。
第一步就是創建自定義標題的布局文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rel_bar_container" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/left_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="8dp" android:visibility="gone" /> <TextView android:id="@+id/bar_left_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="4dp" android:layout_toRightOf="@id/left_icon" android:text="" android:textColor="@android:color/white" android:textSize="18sp" /> <TextView android:id="@+id/bar_second_left_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="6dp" android:layout_toRightOf="@id/bar_left_btn" android:text="" android:textColor="@android:color/white" android:textSize="18sp" /> <TextView android:id="@+id/bar_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:ellipsize="end" android:maxWidth="150dp" android:singleLine="true" android:text="" android:textColor="@android:color/white" android:textSize="18sp" /> <TextView android:id="@+id/bar_right_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toLeftOf="@+id/right_icon" android:textColor="@android:color/white" android:textSize="18sp" android:visibility="gone" /> <ImageView android:id="@+id/right_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="8dp" /> </RelativeLayout>
從左至右,依次分為左圖標,左標題,標題,右標題,右圖標。。。可以根據需要來顯示或隱藏
再來代碼實現自定義標題
ActionBar actionBar = this.getSupportActionBar(); actionBar.setDisplayOptions(16); actionBar.setDisplayShowCustomEnabled(true); actionBar.setCustomView(layout.action_bar_layout1); //這個當然是上面定義的布局文件咯 this.mRelBarContainer = (RelativeLayout)actionBar.getCustomView().findViewById(id.rel_bar_container); this.mTvLeft = (TextView)actionBar.getCustomView().findViewById(id.bar_left_btn); this.mTitle = (TextView)actionBar.getCustomView().findViewById(id.bar_title); this.mIvLeftIcon = (ImageView)actionBar.getCustomView().findViewById(id.left_icon); this.mIvRightIcon = (ImageView)actionBar.getCustomView().findViewById(id.right_icon); this.mTvRight = (TextView)actionBar.getCustomView().findViewById(id.bar_right_btn); this.mTvSecLeft = (TextView)actionBar.getCustomView().findViewById(id.bar_second_left_btn); this.initBarButtonListener(); //為每個按鈕定義監聽事件接收方法
activity繼承support.v7的activity, 用到的actionbar也就是android.support.v7.app.ActionBar。接着再來看監聽事件方法實現
import android.support.v7.app.AppCompatActivity; /** * Created by 28205 on 2016/6/3. */ public class CustomActionBarActivity extends AppCompatActivity { ... private void initBarButtonListener() { View.OnClickListener leftListener = new View.OnClickListener() { @Override public void onClick(View v) { onLeftClick(); } }; View.OnClickListener leftSecListener = new View.OnClickListener() { @Override public void onClick(View v) { onLeftSecondClick(); } }; View.OnClickListener leftIconListener = new View.OnClickListener() { @Override public void onClick(View v) { onLeftIconClick(); } }; View.OnClickListener rightListener = new View.OnClickListener() { @Override public void onClick(View v) { onRightClick(); } }; View.OnClickListener rightIconListener = new View.OnClickListener() { @Override public void onClick(View v) { onRightIconClick(); } }; //set listener mTvLeft.setOnClickListener(leftListener); mIvLeftIcon.setOnClickListener(leftIconListener); mTvSecLeft.setOnClickListener(leftSecListener); mTvRight.setOnClickListener(rightListener); mIvRightIcon.setOnClickListener(rightIconListener); }
public void setBarBg(int resid) {
mRelBarContainer.setBackgroundResource(resid);
}
}
很明顯,該類還得要定義幾個空的事件監聽方法來讓子類繼承,以達到子類來重寫自己的監聽方法。不過這里並沒有將其設為接口或虛方法來強制用戶來重寫這幾個方法,而是記子類根據需要自己來決定重寫,如不重寫,當然就是點擊不響應咯。
public void onLeftClick() { } public void onLeftSecondClick() { } public void onLeftIconClick() { } public void onRightClick() { } public void onRightIconClick() { }
好了,標題這塊基本上完了,再來看一鍵關所有activity,這個在面試的時候經常會被問到,我之前就在這上面吃了大虧,傷心。。。在這我是通過廣播的方式來做到,只要收到自定義的“關閉所有”的廣播就將自己關掉,而所有的activity都是繼承這個基類,所以
也就是能做到所有的activity能同時關閉了。代碼簡單,一目了然
public class CustomActionBarActivity extends AppCompatActivity { public static final String ACTION = "FINISH_ALL"; private FinishReceiver mFinishReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... mFinishReceiver = new FinishReceiver(); startMonitoring(); } protected void startMonitoring() { IntentFilter intentFilter = new IntentFilter(ACTION); registerReceiver(mFinishReceiver, intentFilter); //簡單的廣播注冊 } protected void stopMonitoring() { unregisterReceiver(mFinishReceiver); } /** * 關閉所有的Activity */ public void finishAll() { // 只要在子類調用該方法,就能關閉所有activity了,除非你不是該類的子類 sendBroadcast(new Intent(ACTION)); } @Override protected void onDestroy() { super.onDestroy(); stopMonitoring(); } /** * 退出監聽 */ class FinishReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 監聽退出消息 if (intent.getAction() == ACTION) { finish(); } } }
上面的代碼可以做成jar包供自己使用,以后就不需要每次都要重寫了,最后看看怎么使用。這里只說說自定義的標題的使用和配置,首先得為標題設置一個自己的theme, 不然就會用系統默認的
<resources xmlns:tools="http://schemas.android.com/tools"> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> </style> <style name="Theme.Custom.AppCompat" parent="@style/Theme.AppCompat.Light"> <item name="android:actionBarSize">50dp</item> //actionbar高度 <item name="android:windowContentOverlay">@null</item> <item name="actionBarStyle">@style/bc</item> </style> <style name="bc" parent="@style/Widget.AppCompat.ActionBar"> <item name="background">@android:color/holo_blue_dark</item> <item name="contentInsetStart">10dp</item> //以下4個選項必須為0, 否則會在兩邊留白,這里我故意設為10dp,對比下效果 <item name="contentInsetEnd">0dp</item> <item name="android:paddingLeft">0dp</item> <item name="android:paddingRight">0dp</item> <item name="elevation">0dp</item> </style> </resources>
例子
public class BaseActionBarActivity extends CustomActionBarActivity { private static final String TAG = "BaseActionBarActivity"; Dialog dialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTheme(R.style.Theme_Custom_AppCompat); setBarBg(R.color.red); // 這個方法就是指定標題的背景色,如果沒有指定,背景色就使用上一句的theme里定義的顏色,如果有則會覆蓋。 // setStatusBarColor(R.color.app_theme_color); setLeftTitle("左標題"); } @Override public void onLeftClick() { super.onLeftClick(); Log.d(TAG, "onLeftClick 左標題被點了"); } }
效果是這樣的
很顯然,actionbar左邊有10dp的沒有覆蓋住,這就是在theme里定義的<item name="contentInsetStart">10dp</item> 的效果。
最后再美化一下界面,加入沉浸式狀態欄,讓狀態欄背景與actionbar顏色一致。這個功能是谷歌在android4.4版本后推出的。這里使用三方庫SystemBarTint
鏈接:https://github.com/jgilfelt/SystemBarTint
android studio導入方法
// 沉侵模式菜單
compile 'com.readystatesoftware.systembartint:systembartint:1.0.3'
代碼塊實現
package com.blueto.cn.myutils.activity; import com.readystatesoftware.systembartint.SystemBarTintManager; /** * Created by 28205 on 2016/6/3. */ public class CustomActionBarActivity extends AppCompatActivity { private SystemBarTintManager tintManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... initSystemBar(this); } private void initSystemBar(Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (!showSystemBar) return; setTranslucentStatus(activity, true); tintManager = new SystemBarTintManager(activity); tintManager.setStatusBarTintEnabled(true); } } public void setStatusBarColor(int color) { tintManager.setStatusBarTintResource(color); } @TargetApi(19) private void setTranslucentStatus(Activity activity, boolean on) { Window win = activity.getWindow(); WindowManager.LayoutParams winParams = win.getAttributes(); final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; if (on) { winParams.flags |= bits; } else { winParams.flags &= ~bits; } win.setAttributes(winParams); } }
之后在子類中就可以隨意指定狀態欄的顏色了
public class BaseActionBarActivity extends CustomActionBarActivity { private static final String TAG = "BaseActionBarActivity"; Dialog dialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTheme(R.style.Theme_Custom_AppCompat); setBarBg(R.color.red); setStatusBarColor(R.color.red); setLeftTitle("左標題"); } }
值得注意的是,在使用沉浸式狀態欄的時候,對actionbarsize這個屬性有硬性要求,如果沒有配置就會報錯 : android.content.Resources$NotFoundException ..., 我是在這被坑了好久,最后才找到原因,因為原碼里有這么一段
@TargetApi(14) private int getActionBarHeight(Context context) { int result = 0; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { TypedValue tv = new TypedValue(); context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true); result = context.getResources().getDimensionPixelSize(tv.resourceId); } return result; }
在初始化statusbar的時候,首先需要去獲取actionBarSize的值,如果找不到那肯定就報錯資源未找到,不過資源未找到讓我把所有資源文件都確認了一次。。。
<style name="Theme.Custom.AppCompat" parent="@style/Theme.AppCompat.Light"> <item name="actionBarSize">50dp</item> //報錯前,這里寫成了 android:actionBarSize, 郁悶啊,這錯找了我一晚上 <item name="android:windowContentOverlay">@null</item> <item name="actionBarStyle">@style/bc</item> </style>
最終效果是這樣的,測試機是ZTE5.1.1版本,圖中與actionbar顏色有點差異,但是在其他機型上則是完全一樣的。可能還需要對這個機型做些特殊處理才能達到完全一樣的效果,不過目前這個效果還是挺美的,我感覺比全一個色要好看,這樣更有層次感,除非產品非要搞成一樣。。