Android 自定义标题栏
背景
在大多數(shù)應(yīng)用的頁面頂部,都會(huì)有標(biāo)題欄,這種業(yè)務(wù)相關(guān)性不大,通用性很強(qiáng)的視圖,第一直覺,是要把它抽取,做成通用的。
最先想到的是使用google推薦的ActionBar 和 ToolBar。但要標(biāo)題文字居中就特別麻煩,ActionBar得使用自定義布局setCustomView(),設(shè)置后,它提供的其它api就相當(dāng)于廢棄了,原有的api無法操作自定義的布局,相當(dāng)于只能用它當(dāng)作容器,view的操作還得自己寫;ToolBar更奇怪,得用TextView覆蓋在ToolBar視圖之上,再給ToolBar 的標(biāo)題文字清空,它的setTitle函數(shù)這就算是廢掉了,,后續(xù)都操作自己加入的title TextView。唉,標(biāo)題居中都這么麻煩,原諒我我不擅長使用這個(gè)輪子,… 那就按照項(xiàng)目中的要求自己造一個(gè)吧。
方法一 include 通用型布局
這是早期項(xiàng)目中的比較原始的一般做法
實(shí)現(xiàn)
新建titlebar_view.xml 大致代碼如下:
使用
Activity中對(duì)view進(jìn)行操作。設(shè)置標(biāo)題,控制右側(cè)操作圖標(biāo)的展示隱藏等
public void setTitle(CharSequence title) {((TextView)findViewById(R.id.titlebar_title_tv)).setText(title);}缺陷
每個(gè)頁面的布局得include這個(gè)文件,很繁瑣,Activity中直接操作titlebar的子視圖id,學(xué)習(xí)成本過高,而且團(tuán)隊(duì)開發(fā)中不易維護(hù)。
能否在xml中不用include 標(biāo)題欄布局,只關(guān)注自己特有的一些布局。而且也不希望調(diào)用者關(guān)注標(biāo)題欄中的各子視圖的具體id
方法二 在根布局中動(dòng)態(tài)添加標(biāo)欄視圖
自定義標(biāo)題欄View 和 根容器View,在根容器中動(dòng)態(tài)的把標(biāo)題欄視圖添加進(jìn)去,這樣,布局中就不需要標(biāo)題欄了。
實(shí)現(xiàn)
對(duì)外提供操作子元素方法 如 setTitle();
初始化的時(shí)候,把TitleBarView添加到第一個(gè)元素的位子
3.在布局文件中使用RootLinearLayout 做為跟布局就可以了
<?xml version="1.0" encoding="utf-8"?> <miao.t5.RootLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World!" /> </miao.t5.RootLinearLayout>使用
public TitleBarView getTitleBar(){return (TitleBarView)findViewById(R.id.titlebar_view);}public void setTitle(CharSequence title) {getTitleBar().setText(title);}缺陷
這種方法對(duì)于方法一有了很大進(jìn)步,也解決了繁瑣的include和需要知道標(biāo)題欄子視圖viewId的問題
但根布局必須是自定的RootLinearLayout,實(shí)際使用有局限性
方法三 根視圖中加入自定義的xml布局
將通用型視圖抽離(rootview + titlebarView + innerLoadingView + emptyView…)作為容器,各個(gè)頁面的布局作為子視圖被rootView動(dòng)態(tài) include,這樣,各頁面只需要處理自有的主業(yè)務(wù)布局了。類似于android窗口的構(gòu)建方式。
圖片來源于http://blog.csdn.net/cauchyweierstrass/article/details/44303657
我們?cè)谏蠄Did/content-Fragment 里,局部再構(gòu)建類似于DecroWindow的視圖結(jié)構(gòu)
實(shí)現(xiàn)
2.重寫B(tài)aseActivity的setContentView( )函數(shù),將activity_main.xml作為子視圖add進(jìn)root_content_fl 中
@Overridepublic void setContentView(@LayoutRes int layoutResID) {super.setContentView(R.layout.layout_root);LayoutInflater.from(this).inflate(layoutResID, (ViewGroup) findViewById(R.id.root_content_fl), true);}3.activity_main.xml就不需要關(guān)心titlebar了,正常編寫自有的布局即可
<?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"><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World!" /> </LinearLayout>使用方式和圖二一致
優(yōu)化
對(duì)外TitleBar接口可見
方法二和方法三中,標(biāo)題欄是以自定義組合控件 TitleBarView 的方式進(jìn)行封裝的,繼承自FrameLayout,也就繼承了所有父類的非私有函數(shù)。調(diào)用者可對(duì)其removeView,setVisable對(duì)外的安全性也降低了,使用起來也不方便。
實(shí)現(xiàn)
2.TitleBar來實(shí)現(xiàn)這些接口
public class TitleBarView extends FrameLayout implements TitleBar{public TitleBarView(Context context) {super(context);init();}private void init() {this.setId(R.id.titlebar_view);this.removeAllViewsInLayout();LayoutInflater layoutInflater = LayoutInflater.from(getContext());View view = layoutInflater.inflate(R.layout.titlebar_view, this, false);addView(view, new RelativeLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,FrameLayout.LayoutParams.WRAP_CONTENT));}@Overridepublic void setNavigationContentDescription(CharSequence navigationContentDescription) {((TextView)findViewById(R.id.titlebar_back_tv)).setText(navigationContentDescription);}@Overridepublic void setTitle(CharSequence title) {((TextView)findViewById(R.id.titlebar_title_tv)).setText(title);}@Overridepublic void setBackground(@DrawableRes int backgroundRes) {this.setBackgroundResource(backgroundRes);} }在BaseActivity中得到TitleBar接口的實(shí)例TitleBarView,子Activity只對(duì)接口可見
public class BaseActivity extends AppCompatActivity {private TitleBar titleBar;@Overridepublic void setContentView(@LayoutRes int layoutResID) {super.setContentView(R.layout.layout_root);titleBar = (TitleBarView)findViewById(R.id.titlebar_view);LayoutInflater.from(this).inflate(layoutResID, (ViewGroup) findViewById(R.id.root_content_fl), true);}protected TitleBar getTitleBar(){return titleBar;} }調(diào)用也方便了許多
部分界面不需要標(biāo)題欄
1.使用java注解的方式
在對(duì)類進(jìn)行聲明是否需要標(biāo)題欄,然后加載不同的layout_root視圖,注解的簡單使用介紹,注意:自定義的運(yùn)行時(shí)注解,在獲取值時(shí)會(huì)用到反射
2.通過不同的theme加載不同的根視圖
類似源碼中AppCompatDelegateImplV7.java#createSubDecor()函數(shù)實(shí)現(xiàn)
private ViewGroup createSubDecor() {TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);//...//得到theme中windowIsFloating 的值mIsFloating = a.getBoolean(R.styleable.AppCompatTheme_android_windowIsFloating, false);a.recycle();final LayoutInflater inflater = LayoutInflater.from(mContext);ViewGroup subDecor = null;//判斷不同的style屬性值加載不同的根布局if (!mWindowNoTitle) {if (mIsFloating) {// If we're floating, inflate the dialog title decorsubDecor = (ViewGroup) inflater.inflate(R.layout.abc_dialog_title_material, null);} else if (mHasActionBar) {subDecor = (ViewGroup) LayoutInflater.from(themedContext).inflate(R.layout.abc_screen_toolbar, null);} else {if (mOverlayActionMode) {subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple_overlay_action_mode, null);} else {subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);}//... }// }實(shí)現(xiàn)
自定義attrs來標(biāo)注是否需要titleBarView
<declare-styleable name="CustomThemeAttrs"><attr name="NoTitleBar" format="boolean" /></declare-styleable>自定義theme
<!-- Base application theme. --><style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"></style><!--沒有標(biāo)題欄的theme --><style name="AppTheme.NoTitleBar"><item name="NoTitleBar">false</item></style>延展
結(jié)合上圖中Android的窗口結(jié)構(gòu),我們?cè)倏纯碅ctionBar在這個(gè)結(jié)構(gòu)中的位置
ActionBar是插入DectorView下面,和我們contentView平級(jí)
最近看了標(biāo)題欄和狀態(tài)欄一體化/沉浸式狀態(tài)欄 在Android 4.0~5.0上的解決方案
也是在DectorView中添加空的View占據(jù)statusbar
那么我們完全可以將titleBarView add進(jìn)DectorView 中,和contentView平級(jí),構(gòu)造和上圖一樣的視圖結(jié)構(gòu),這樣 contentView 和 titeBarView完全隔離,可以達(dá)到和ActionBar同樣的效果,我們就自己做了一個(gè)ActionBar!哈哈…
總結(jié)
以上是生活随笔為你收集整理的Android 自定义标题栏的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 3DMax 基础课程-2
- 下一篇: android程序如何联网,如何判断软件