日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android 自定义标题栏

發(fā)布時(shí)間:2023/12/20 Android 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android 自定义标题栏 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

背景

在大多數(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)

  • 將標(biāo)題欄寫成通用型的布局文件,在主布局文件中inclide
    新建titlebar_view.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="@dimen/titlebar_height"android:background="#CCCCCC"android:orientation="vertical"><LinearLayout android:layout_width="wrap_content"android:layout_height="match_parent"android:background="#AAAAAA"android:gravity="center_vertical"android:orientation="horizontal"><ImageView android:layout_width="36dp"android:layout_height="36dp"android:src="@android:drawable/ic_menu_compass"/><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="首頁"/></LinearLayout><TextView android:id="@+id/titlebar_title_tv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:text="title text"/><LinearLayout android:layout_width="wrap_content"android:layout_height="match_parent"android:background="#AAAAAA"android:layout_alignParentRight="true"android:gravity="center_vertical"android:orientation="horizontal"><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="重設(shè)"/><ImageView android:layout_width="36dp"android:layout_height="36dp"android:src="@android:drawable/ic_menu_add"/></LinearLayout> </RelativeLayout>

  • 在主布局文件activity_main.xml 中include titlebar_view.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 layout="@layout/titlebar_view"/><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World!" /> </RelativeLayout>

    使用

    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)

  • 自定義titleBarView
    對(duì)外提供操作子元素方法 如 setTitle();
  • public class TitleBarView extends FrameLayout {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));}/*** 設(shè)置標(biāo)題欄文字*/public void setTitle(CharSequence text){((TextView)findViewById(R.id.titlebar_title_tv)).setText(text);} }
  • 自定義根布局RootLinearLayout
    初始化的時(shí)候,把TitleBarView添加到第一個(gè)元素的位子
  • public class RootLinearLayout extends LinearLayout {public RootLinearLayout(Context context, AttributeSet attrs) {super(context, attrs);init();}public RootLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}@TargetApi(Build.VERSION_CODES.LOLLIPOP)public RootLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);}private void init() {addView(new TitleBarView(getContext()), 0, new LinearLayoutCompat.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, getResources().getDimensionPixelSize(R.dimen.titlebar_height)));} }

    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)

  • 新建根視圖布局layout_root.xml,作為根容器,被所有Activity加載
  • ?xml version="1.0" encoding="utf-8"?> <miao.t5.RootLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"><!-- setContentView()的容器,將xml填充其中 --><FrameLayout android:id="@+id/root_content_fl"android:layout_width="match_parent"android:layout_height="match_parent"></FrameLayout> </miao.t5.RootLinearLayout>

    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)

  • 創(chuàng)建接口TitleBar 來規(guī)范我們的標(biāo)題欄能夠支持哪些操作
  • public interface TitleBar {void setNavigationContentDescription(CharSequence navigationContentDescription);void setTitle(CharSequence title);void setBackground(@DrawableRes int backgroundRes);... }

    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>
  • 在BaseActivity的setContentView函數(shù)中處理
  • @Overridepublic void setContentView(@LayoutRes int layoutResID) {//讀取當(dāng)前activity中的NoTitleBar屬性值TypedArray a = obtainStyledAttributes(R.styleable.CustomThemeAttrs);boolean hasTitleBar = a.getBoolean(R.styleable.CustomThemeAttrs_NoTitleBar, false);a.recycle();//加載不同的根布局if(hasTitleBar) {super.setContentView(R.layout.layout_root);titleBar = (TitleBarView)findViewById(R.id.titlebar_view);}else{super.setContentView(R.layout.layout_root_no_titlebar);}//將頁面的布局加載根布局的root_content_fl容器中 LayoutInflater.from(this).inflate(layoutResID, (ViewGroup) findViewById(R.id.root_content_fl), true);}

    延展

    結(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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。