在上一節(jié)中我們對(duì)Fragment進(jìn)行了一個(gè)初步的了解,學(xué)習(xí)了概念,生命周期,F(xiàn)ragment管理與 Fragment事務(wù),以及動(dòng)態(tài)與靜態(tài)加載Fragment。從本節(jié)開始我們會(huì)講解一些Fragment在實(shí)際開發(fā) 中的一些實(shí)例!而本節(jié)給大家講解的是底部導(dǎo)航欄的實(shí)現(xiàn)!而基本的底部導(dǎo)航欄方法有很多種, 比如全用TextView做,或者用RadioButton,又或者使用TabLayout + RadioButton,當(dāng)然復(fù)雜 的情況還是得走外層套布局的方法!本節(jié)我們用TextView來做一個(gè)底部導(dǎo)航欄的效果,也熟悉 下Fragment的使用!好的,開始本節(jié)內(nèi)容!
先看看效果圖吧:
接著看看我們的工程的目錄結(jié)構(gòu):
我們從圖上可以看到,我們底部的每一項(xiàng)點(diǎn)擊的時(shí)候都有不同的效果是吧! 我們是通過是否selected來判定的!我們要寫的資源文件有:首先是圖片,然后是文字,接著是背景!
圖片Drawable資源:tab_menu_channel.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/tab_channel_pressed" android:state_selected="true" />
<item android:drawable="@mipmap/tab_channel_normal" />
</selector>
其他三個(gè)照葫蘆畫瓢!
文字資源:tab_menu_text.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/text_yellow" android:state_selected="true" />
<item android:color="@color/text_gray" />
</selector>
背景資源:tab_menu_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape>
<solid android:color="#FFC4C4C4" />
</shape>
</item>
<item>
<shape>
<solid android:color="@color/transparent" />
</shape>
</item>
</selector>
activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<RelativeLayout
android:id="@+id/ly_top_bar"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/bg_topbar">
<TextView
android:id="@+id/txt_topbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:textSize="18sp"
android:textColor="@color/text_topbar"
android:text="信息"/>
<View
android:layout_width="match_parent"
android:layout_height="2px"
android:background="@color/div_white"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
<LinearLayout
android:id="@+id/ly_tab_bar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:background="@color/bg_white"
android:orientation="horizontal">
<TextView
android:id="@+id/txt_channel"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/tab_menu_bg"
android:drawablePadding="3dp"
android:drawableTop="@drawable/tab_menu_channel"
android:gravity="center"
android:padding="5dp"
android:text="@string/tab_menu_alert"
android:textColor="@drawable/tab_menu_text"
android:textSize="16sp" />
<TextView
android:id="@+id/txt_message"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/tab_menu_bg"
android:drawablePadding="3dp"
android:drawableTop="@drawable/tab_menu_message"
android:gravity="center"
android:padding="5dp"
android:text="@string/tab_menu_profile"
android:textColor="@drawable/tab_menu_text"
android:textSize="16sp" />
<TextView
android:id="@+id/txt_better"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/tab_menu_bg"
android:drawablePadding="3dp"
android:drawableTop="@drawable/tab_menu_better"
android:gravity="center"
android:padding="5dp"
android:text="@string/tab_menu_pay"
android:textColor="@drawable/tab_menu_text"
android:textSize="16sp" />
<TextView
android:id="@+id/txt_setting"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/tab_menu_bg"
android:drawablePadding="3dp"
android:drawableTop="@drawable/tab_menu_setting"
android:gravity="center"
android:padding="5dp"
android:text="@string/tab_menu_setting"
android:textColor="@drawable/tab_menu_text"
android:textSize="16sp"/>
</LinearLayout>
<View
android:id="@+id/div_tab_bar"
android:layout_width="match_parent"
android:layout_height="2px"
android:background="@color/div_white"
android:layout_above="@id/ly_tab_bar"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/ly_top_bar"
android:layout_above="@id/div_tab_bar"
android:id="@+id/ly_content">
</FrameLayout>
</RelativeLayout>
代碼解析:
首先定義頂部標(biāo)題欄的樣式,48dp的LinearLayout中間加上一個(gè)TextView作為標(biāo)題!
接著定義一個(gè)大小為56dp的LinerLayout對(duì)其底部,在這個(gè)里面加入四個(gè)TextView,比例1:1:1:1, 并且設(shè)置相關(guān)屬性,接著在這個(gè)LinearLayout上加一條線段!
最后以標(biāo)題欄和底部導(dǎo)航欄為邊界,寫一個(gè)FrameLayout,寬高match_parent,用做Fragment的容器!
PS:這里四個(gè)TextView屬性是重復(fù)的,你也可以自行抽取出來,編寫一個(gè)style,設(shè)置下~
意外發(fā)現(xiàn)以前的在Activity中調(diào)用requestWindowFeature(Window.FEATURE_NO_TITLE);可以隱藏手機(jī) 自帶頂部導(dǎo)航欄,但是寫demo時(shí)候發(fā)現(xiàn)會(huì)報(bào)錯(cuò),即使這句話寫在了setContentView()之前!可能是因?yàn)?繼承的是AppCompatActivity而非Activity類!
當(dāng)然以前的getSupportActionbar().hide()隱藏掉Actionbar,但是他還是會(huì)在界面上! 最后還有一種方法就是自己編寫一個(gè)style,然后在AndroidManifest.xml中為Application設(shè)置這個(gè)Theme:
接著AndroidManifest.xml設(shè)置下theme屬性:
android:theme="@style/Theme.AppCompat.NoActionBar"
PS:上述"良心代碼"由好程序員曹神贊助~
fg_content.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_white">
<TextView
android:id="@+id/txt_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="呵呵"
android:textColor="@color/text_yellow"
android:textSize="20sp"/>
</LinearLayout>
MyFragment.java:
/**
* Created by Coder-pig on 2015/8/28 0028.
*/
public class MyFragment extends Fragment {
private String content;
public MyFragment(String content) {
this.content = content;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fg_content,container,false);
TextView txt_content = (TextView) view.findViewById(R.id.txt_content);
txt_content.setText(content);
return view;
}
}
代碼解析:
就是簡(jiǎn)單的重寫了一個(gè)onCreateView()方法,其他方法可以按需重寫!
先說說我們要考慮的一些關(guān)鍵問題:
- Fragment什么時(shí)候初始化和add到容器中?什么時(shí)候hide和show?
- 如何讓TextView被選中?選中一個(gè)TextView后,要做一些什么操作?
- 剛進(jìn)入MainActivity怎么樣讓一個(gè)TextView處于Selected的狀態(tài)?
嗯,接下來一一解答上面這些問題:
- 我們選中TextView后對(duì)對(duì)應(yīng)的Fragment進(jìn)行判空,如果為空,初始化,并添加到容器中; 而hide的話,我們定義一個(gè)方法hide所有的Fragment,每次觸發(fā)點(diǎn)擊事件就先調(diào)用這個(gè)hideAll方法, 講所有Fragment隱藏起來,然后如果TextView對(duì)應(yīng)的Fragment不為空,我們就將這個(gè)Fragment顯示出來;
- 這個(gè)我們通過點(diǎn)擊事件來實(shí)現(xiàn),點(diǎn)擊TextView后先重置所有TextView的選中狀態(tài)為false,然后設(shè)置點(diǎn)擊的 TextView的選中狀態(tài)為true;
- 這個(gè)更簡(jiǎn)單,我們是通過點(diǎn)擊事件來設(shè)置選中的,那么在onCreate()方法里加個(gè)觸發(fā)點(diǎn)擊事件的 方法不就可以了嘛~txt_channel.performClick();
邏輯都弄懂了,直接上代碼咯:
MainActivity.java:
/**
* Created by Coder-pig on 2015/8/28 0028.
*/
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
//UI Object
private TextView txt_topbar;
private TextView txt_channel;
private TextView txt_message;
private TextView txt_better;
private TextView txt_setting;
private FrameLayout ly_content;
//Fragment Object
private MyFragment fg1,fg2,fg3,fg4;
private FragmentManager fManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
fManager = getFragmentManager();
bindViews();
txt_channel.performClick(); //模擬一次點(diǎn)擊,既進(jìn)去后選擇第一項(xiàng)
}
//UI組件初始化與事件綁定
private void bindViews() {
txt_topbar = (TextView) findViewById(R.id.txt_topbar);
txt_channel = (TextView) findViewById(R.id.txt_channel);
txt_message = (TextView) findViewById(R.id.txt_message);
txt_better = (TextView) findViewById(R.id.txt_better);
txt_setting = (TextView) findViewById(R.id.txt_setting);
ly_content = (FrameLayout) findViewById(R.id.ly_content);
txt_channel.setOnClickListener(this);
txt_message.setOnClickListener(this);
txt_better.setOnClickListener(this);
txt_setting.setOnClickListener(this);
}
//重置所有文本的選中狀態(tài)
private void setSelected(){
txt_channel.setSelected(false);
txt_message.setSelected(false);
txt_better.setSelected(false);
txt_setting.setSelected(false);
}
//隱藏所有Fragment
private void hideAllFragment(FragmentTransaction fragmentTransaction){
if(fg1 != null)fragmentTransaction.hide(fg1);
if(fg2 != null)fragmentTransaction.hide(fg2);
if(fg3 != null)fragmentTransaction.hide(fg3);
if(fg4 != null)fragmentTransaction.hide(fg4);
}
@Override
public void onClick(View v) {
FragmentTransaction fTransaction = fManager.beginTransaction();
hideAllFragment(fTransaction);
switch (v.getId()){
case R.id.txt_channel:
setSelected();
txt_channel.setSelected(true);
if(fg1 == null){
fg1 = new MyFragment("第一個(gè)Fragment");
fTransaction.add(R.id.ly_content,fg1);
}else{
fTransaction.show(fg1);
}
break;
case R.id.txt_message:
setSelected();
txt_message.setSelected(true);
if(fg2 == null){
fg2 = new MyFragment("第二個(gè)Fragment");
fTransaction.add(R.id.ly_content,fg2);
}else{
fTransaction.show(fg2);
}
break;
case R.id.txt_better:
setSelected();
txt_better.setSelected(true);
if(fg3 == null){
fg3 = new MyFragment("第三個(gè)Fragment");
fTransaction.add(R.id.ly_content,fg3);
}else{
fTransaction.show(fg3);
}
break;
case R.id.txt_setting:
setSelected();
txt_setting.setSelected(true);
if(fg4 == null){
fg4 = new MyFragment("第四個(gè)Fragment");
fTransaction.add(R.id.ly_content,fg4);
}else{
fTransaction.show(fg4);
}
break;
}
fTransaction.commit();
}
}
FragmentDemo.zip:FragmentDemo.zip 下載 聲明:圖片素材來自App:better,本代碼只做演示,并無用于商業(yè)用途!
本節(jié)給大家講解了如何使用一個(gè)LinarLayout + 四個(gè)TextView 實(shí)現(xiàn)一個(gè)底部導(dǎo)航欄以及 Fragment add,hide,show的邏輯~還是蠻簡(jiǎn)單的,最后要感謝小豬秘密基地的基神,B神, 還有好程序員曹神給我的一些指點(diǎn)!萬分感謝,僅以此篇紀(jì)念小豬重返裝逼界,嗯,重 返應(yīng)用層,嘿嘿,本節(jié)就到這里,謝謝~
更多建議: