写点什么

Fragment——底部导航栏的实现

作者:向阳逐梦
  • 2023-04-16
    四川
  • 本文字数:6267 字

    阅读完需:约 21 分钟

Fragment——底部导航栏的实现

本节开始我们会讲解一些 Fragment 在实际开发中的一些实例!而本节给大家讲解的是底部导航栏的实现!而基本的底部导航栏方法有很多种,比如全用 TextView 做,或者用 RadioButton,又或者使用 TabLayout + RadioButton,当然复杂的情况还是得走外层套布局的方法!本节我们用 TextView 来做一个底部导航栏的效果,也熟悉下 Fragment 的使用!

1.要实现的效果图以及工程目录结构

先看看效果图:

接着看看我们的工程的目录结构:

2.实现流程

Step 1:写下底部选项的一些资源文件

我们从图上可以看到,我们底部的每一项点击的时候都有不同的效果是吧!我们是通过是否 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>
复制代码

文字资源: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>
复制代码

Step 2:编写我们的 Activity 布局

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>
复制代码

代码解析:

首先定义顶部标题栏的样式,48dp的LinearLayout中间加上一个TextView作为标题!接着定义一个大小为56dp的LinerLayout对其底部,在这个里面加入四个TextView,比例1:1:1:1, 并且设置相关属性,接着在这个LinearLayout上加一条线段!最后以标题栏和底部导航栏为边界,写一个FrameLayout,宽高match_parent,用做Fragment的容器!
复制代码

PS:这里四个 TextView 属性是重复的,你也可以自行抽取出来,编写一个 style,设置下

Step 3:隐藏顶部导航栏

意外发现以前的在 Activity 中调用 requestWindowFeature(Window.FEATURE_NO_TITLE);可以隐藏手机自带顶部导航栏,但是写 demo 时候发现会报错,即使这句话写在了 setContentView()之前!可能是因为继承的是 AppCompatActivity 而非 Activity 类!当然以前的 getSupportActionbar().hide()隐藏掉 Actionbar,但是他还是会在界面上!最后还有一种方法就是自己编写一个 style,然后在 AndroidManifest.xml 中为 Application 设置这个 Theme。

注:把 requestWindowFeature(Window.FEATURE_NO_TITLE);放在 super.onCreate(savedInstanceState);前面就可以隐藏 ActionBar 而不报错。

接着 AndroidManifest.xml 设置下 theme 属性:

android:theme="@style/Theme.AppCompat.NoActionBar"
复制代码

Step 4:创建一个 Fragment 的简单布局与类:

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; }}
复制代码

代码解析:

就是简单的重写了一个 onCreateView()方法,其他方法可以按需重写!

Step 5:编写 MainActivity.java

先说说我们要考虑的一些关键问题:


  • Fragment 什么时候初始化和 add 到容器中?什么时候 hide 和 show?

  • 如何让 TextView 被选中?选中一个 TextView 后,要做一些什么操作?

  • 刚进入 MainActivity 怎么样让一个 TextView 处于 Selected 的状态?

嗯,接下来一一解答上面这些问题:


  • 我们选中 TextView 后对对应的 Fragment 进行判空,如果为空,初始化,并添加到容器中;而 hide 的话,我们定义一个方法 hide 所有的 Fragment,每次触发点击事件就先调用这个 hideAll 方法,讲所有 Fragment 隐藏起来,然后如果 TextView 对应的 Fragment 不为空,我们就将这个 Fragment 显示出来;

  • 这个我们通过点击事件来实现,点击 TextView 后先重置所有 TextView 的选中状态为 false,然后设置点击的 TextView 的选中状态为 true;

  • 这个更简单,我们是通过点击事件来设置选中的,那么在 onCreate()方法里加个触发点击事件的方法不就可以了嘛~ 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(); //模拟一次点击,既进去后选择第一项 }
//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); }
//重置所有文本的选中状态 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("第一个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("第二个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("第三个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("第四个Fragment"); fTransaction.add(R.id.ly_content,fg4); }else{ fTransaction.show(fg4); } break; } fTransaction.commit(); }}
复制代码

3.代码下载:

FragmentDemo.zipFragmentDemo.zip

发布于: 2023-04-16阅读数: 27
用户头像

向阳逐梦

关注

人生享受编程,编程造就人生! 2022-06-01 加入

某公司芯片测试工程师,嵌入式开发工程师,InfoQ签约作者,阿里云星级博主,华为云·云享专家。座右铭:向着太阳,追逐梦想!

评论 (1 条评论)

发布
用户头像
推荐了
2023-04-16 22:40 · 上海
回复
没有更多了
Fragment——底部导航栏的实现_Fragment_向阳逐梦_InfoQ写作社区