歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 百度貼吧布局框架的研究與實現(Android版本)

百度貼吧布局框架的研究與實現(Android版本)

日期:2017/3/1 10:13:06   编辑:Linux編程

還記得幾個月前剛接觸“百度貼吧”這款應用時,瞬間就被它的懸浮式標題欄以及標簽欄所吸引,雖然當時身邊有個UI的MM說懸浮式一般都是具備隱藏的功能時才設計成這樣的,一般情況下還是用直通式的好,在這裡我也不討論孰優孰劣,截取兩個圖,大家自己品味下。

懸浮式標題欄和標簽欄:(百度貼吧);直通式標題欄和標簽欄:(QQ空間)

本文的目的就是研究下百度貼吧的這個標題欄和標簽欄的實現原理;

1、 懸浮式標題欄的實現

實現原理有兩種:1)在布局文件中設置標題欄的layout_margin屬性;2)給標題欄設置一個9-patch格式的background圖片,在這種圖片上設置上下左右的空白間隔,如下圖所示,背景圖片的top、left和right分別有一個像素的空白,bottom則是兩個像素。

使用第二種方式實現的標題欄的布局文件如下:

  1. <!-- 標題欄 -->
  2. <LinearLayout
  3. Android:id="@+id/home_layout_bar"
  4. android:layout_width="fill_parent"
  5. android:layout_height="wrap_content"
  6. android:layout_alignParentTop="true"
  7. android:layout_gravity="top"
  8. android:background="@drawable/title_bg"
  9. android:gravity="center" >
  10. <LinearLayout
  11. android:layout_width="fill_parent"
  12. android:layout_height="wrap_content"
  13. android:background="@drawable/home_topbar_bg"
  14. android:gravity="center"
  15. android:orientation="horizontal" >
  16. <!-- 我的貼吧 -->
  17. <ImageButton
  18. android:id="@+id/home_bt_like"
  19. android:layout_width="fill_parent"
  20. android:layout_height="fill_parent"
  21. android:layout_gravity="center"
  22. android:layout_margin="0.0dip"
  23. android:layout_weight="1.0"
  24. android:background="@null"
  25. android:padding="0.0dip"
  26. android:paddingBottom="2.0dip"
  27. android:scaleType="center"
  28. android:src="@drawable/home_bt_like_on" />
  29. <!-- 我的標簽 -->
  30. <ImageButton
  31. android:id="@+id/home_bt_mark"
  32. android:layout_width="fill_parent"
  33. android:layout_height="fill_parent"
  34. android:layout_gravity="center"
  35. android:layout_margin="0.0dip"
  36. android:layout_weight="1.0"
  37. android:background="@null"
  38. android:padding="0.0dip"
  39. android:paddingBottom="2.0dip"
  40. android:scaleType="center"
  41. android:src="@drawable/home_bt_mark" />
  42. </LinearLayout>
  43. </LinearLayout>
其中title_bg就是用來實現懸浮效果的9-patch背景圖片,這裡為了優化視覺上的效果,在背景圖片上又加了一層圖片,也就是home_topbar_bg,加與不加的對比效果如圖:

我的貼吧和我的書簽這兩個按鈕的按下與松開的是通過切換android:background和android:src的圖片資源來實現的,而沒有采用通常的selector方式,代碼中設置按鈕的單擊響應函數,更換按鈕圖片資源的關鍵代碼如下:

  1. mButtonLike.setBackgroundResource(R.drawable.home_topbar_bt);
  2. mButtonLike.setImageResource(R.drawable.home_bt_like_on);
  3. mButtonMark.setBackgroundDrawable(null);
  4. mButtonMark.setImageResource(R.drawable.home_bt_mark);

2、 懸浮式標簽欄的實現

標簽欄的實現有很多種組合,比較省事的是使用系統提供的TabHost+TabWidget,比較自由的是使用TabHost+RadioGroup,下面使用第二種方式。

標簽欄懸浮效果同樣是通過9-patch背景圖片實現的,如下圖:

標簽欄的實現必須具備三個基本元素,如下圖所示,分別是1)id為@android:id/tabhost的<TabHost>標簽;2)id為@android:id/tabcontent的<FrameLayout>標簽;3)id為@android:id/tabs的<TabWidget>標簽。如下圖所示:

由於這裡我們使用TabHost+RadioGroup的方式,也就是使用RadioGroup代替TabWidget,所以布局文件中TabWidget的可見性設置為gone,緊接上面布局的是RadioGroup的布局:

  1. <FrameLayout
  2. android:layout_width="fill_parent"
  3. android:layout_height="wrap_content"
  4. android:layout_gravity="bottom"
  5. android:layout_marginTop="-10.0dip"
  6. android:background="@drawable/maintab_toolbar_bg"
  7. android:paddingLeft="7.0dip"
  8. android:paddingRight="7.0dip" >
  9. <RadioGroup
  10. android:id="@+id/main_radio"
  11. android:layout_width="fill_parent"
  12. android:layout_height="wrap_content"
  13. android:gravity="center_vertical"
  14. android:orientation="horizontal" >
  15. <RadioButton
  16. android:id="@+id/radio_home"
  17. android:drawableTop="@drawable/tabs_home"
  18. android:text="@string/bar" />
  19. <RadioButton
  20. android:id="@+id/radio_mention"
  21. android:drawableTop="@drawable/tabs_sort"
  22. android:text="@string/remind" />
  23. <RadioButton
  24. android:id="@+id/radio_person_info"
  25. android:drawableTop="@drawable/tabs_search"
  26. android:text="@string/person_info" />
  27. <RadioButton
  28. android:id="@+id/radio_more"
  29. android:drawableTop="@drawable/tabs_more"
  30. android:text="@string/more" />
  31. </RadioGroup>
  32. <TextView
  33. android:id="@+id/message_mention"
  34. android:layout_width="wrap_content"
  35. android:layout_height="wrap_content"
  36. android:layout_gravity="top|left|center"
  37. android:layout_marginLeft="115.0dip"
  38. android:layout_marginTop="-5.0dip"
  39. android:background="@drawable/message_tips"
  40. android:gravity="center"
  41. android:text=""
  42. android:textColor="#ffffffff"
  43. android:textSize="13.0sp"
  44. android:visibility="visible" />
  45. <TextView
  46. android:id="@+id/message_person"
  47. android:layout_width="wrap_content"
  48. android:layout_height="wrap_content"
  49. android:layout_gravity="top|left|center"
  50. android:layout_marginLeft="190.0dip"
  51. android:layout_marginTop="-5.0dip"
  52. android:background="@drawable/message_tips"
  53. android:gravity="center"
  54. android:text=""
  55. android:textColor="#ffffffff"
  56. android:textSize="13.0sp"
  57. android:visibility="visible" />
  58. </FrameLayout>

其中

1) maintab_toolbar_bg 是標簽欄的背景圖,實現懸浮效果;

2) RadioButton中的

android:drawableTop="@drawable/tabs_sort"

android:text="@string/remind"

組合可以輕松實現圖片上文字下的效果;

3) FrameLayout中的android:layout_marginTop="-10.0dip"實現標簽欄與上方id為tabcontent的FrameLayout部分重疊的效果(10.0dip);

4)兩個TextView和FrameLayout配合實現下圖中標簽右上角的消息個數提示功能

接下來就是代碼如何實現標簽的添加,標簽的點擊響應等等,直接看代碼了:

  1. package com.hust.iprai.wen;
  2. import android.app.AlertDialog;
  3. import android.app.TabActivity;
  4. import android.content.DialogInterface;
  5. import android.content.Intent;
  6. import android.os.Bundle;
  7. import android.view.KeyEvent;
  8. import android.widget.CompoundButton;
  9. import android.widget.RadioButton;
  10. import android.widget.TabHost;
  11. import android.widget.TextView;
  12. public class TiebaActivity extends TabActivity implements
  13. CompoundButton.OnCheckedChangeListener {
  14. private static final String HOME_TAB = "home_tab";
  15. private static final String MENTION_TAB = "mention_tab";
  16. private static final String PERSON_TAB = "person_tab";
  17. private static final String MORE_TAB = "more_tab";
  18. private Intent mHomeIntent = null;
  19. private Intent mMentionIntent = null;
  20. private Intent mPersonIntent = null;
  21. private Intent mMoreIntent = null;
  22. private TabHost mTabHost = null;
  23. private TextView mMessageTipsMention = null;
  24. private TextView mMessageTipsPerson = null;
  25. @Override
  26. public void onCreate(Bundle savedInstanceState) {
  27. super.onCreate(savedInstanceState);
  28. setContentView(R.layout.maintabs_activity);
  29. mTabHost = getTabHost();
  30. initIntents();
  31. initTips();
  32. initRadios();
  33. setupIntents();
  34. }
  35. private void initIntents() {
  36. mHomeIntent = new Intent(this, HomeActivity.class);
  37. mMentionIntent = new Intent(this, MentionActivity.class);
  38. mPersonIntent = new Intent(this, PersonInfoActivity.class);
  39. mMoreIntent = new Intent(this, MoreActivity.class);
  40. }
  41. private void initTips() {
  42. mMessageTipsMention = (TextView) findViewById(R.id.message_mention);
  43. mMessageTipsPerson = (TextView) findViewById(R.id.message_person);
  44. mMessageTipsMention.setText("2");
  45. mMessageTipsPerson.setText("4");
  46. }
  47. private void initRadios() {
  48. ((RadioButton) findViewById(R.id.radio_home))
  49. .setOnCheckedChangeListener(this);
  50. ((RadioButton) findViewById(R.id.radio_mention))
  51. .setOnCheckedChangeListener(this);
  52. ((RadioButton) findViewById(R.id.radio_person_info))
  53. .setOnCheckedChangeListener(this);
  54. ((RadioButton) findViewById(R.id.radio_more))
  55. .setOnCheckedChangeListener(this);
  56. }
  57. private void setupIntents() {
  58. ((RadioButton) findViewById(R.id.radio_home)).setChecked(true);
  59. mTabHost.addTab(buildTabSpec(HOME_TAB, mHomeIntent));
  60. mTabHost.addTab(buildTabSpec(MENTION_TAB, mMentionIntent));
  61. mTabHost.addTab(buildTabSpec(PERSON_TAB, mPersonIntent));
  62. mTabHost.addTab(buildTabSpec(MORE_TAB, mMoreIntent));
  63. mTabHost.setCurrentTabByTag(HOME_TAB);
  64. }
  65. private TabHost.TabSpec buildTabSpec(String tag, Intent intent) {
  66. TabHost.TabSpec tabSpec = mTabHost.newTabSpec(tag);
  67. tabSpec.setContent(intent).setIndicator("",
  68. getResources().getDrawable(R.drawable.icon));
  69. return tabSpec;
  70. }
  71. public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
  72. if (isChecked) {
  73. switch (buttonView.getId()) {
  74. case R.id.radio_home:
  75. mTabHost.setCurrentTabByTag(HOME_TAB);
  76. break;
  77. case R.id.radio_mention:
  78. mTabHost.setCurrentTabByTag(MENTION_TAB);
  79. break;
  80. case R.id.radio_person_info:
  81. mTabHost.setCurrentTabByTag(PERSON_TAB);
  82. break;
  83. case R.id.radio_more:
  84. mTabHost.setCurrentTabByTag(MORE_TAB);
  85. break;
  86. default:
  87. break;
  88. }
  89. }
  90. }
  91. @Override
  92. public boolean dispatchKeyEvent(KeyEvent event) {
  93. if ((event.getAction() == KeyEvent.ACTION_DOWN)
  94. && (event.getKeyCode() == KeyEvent.KEYCODE_BACK)) {
  95. quitDialog();
  96. }
  97. return super.dispatchKeyEvent(event);
  98. }
  99. private void quitDialog() {
  100. new AlertDialog.Builder(this)
  101. .setTitle(R.string.alerm_title)
  102. .setIcon(null)
  103. .setCancelable(false)
  104. .setMessage(R.string.alert_quit_confirm)
  105. .setPositiveButton(R.string.alert_yes_button,
  106. new DialogInterface.OnClickListener() {
  107. public void onClick(DialogInterface dialog,
  108. int which) {
  109. TiebaActivity.this.finish();
  110. }
  111. })
  112. .setNegativeButton(R.string.alert_no_button,
  113. new DialogInterface.OnClickListener() {
  114. public void onClick(DialogInterface dialog,
  115. int which) {
  116. dialog.dismiss();
  117. }
  118. }).create().show();
  119. }
  120. }
Copyright © Linux教程網 All Rights Reserved