Android 底部导航菜单栏的两种实现方式(ViewPage、Fragment)(仿微信界面)

一、实现效果

    

二、思路分析 

三、实现方式1(ViewPager方式)

1.代码结构

2.代码文件

2.1 顶部 activity_top.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:background="#ffffff"
    android:paddingTop="10dp"
    android:paddingLeft="10dp"
    android:layout_height="45dp">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="微信"
        android:textColor="#1B940A"
        android:textSize="16dp" />

</RelativeLayout>

2.2 底部 activity_bottom.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ffffff"
    android:padding="5dp"
    >

    <LinearLayout
        android:id="@+id/ll_home"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/img_home"
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:src="@mipmap/home" />

        <TextView
            android:id="@+id/txt_home"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="@string/txt_nav_home"
            android:textSize="12dp"
            android:textColor="#888888"
             />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/ll_news"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/img_news"
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:src="@mipmap/news_index" />

        <TextView
            android:id="@+id/txt_news"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="@string/txt_nav_news"
            android:textSize="12dp"
            android:textColor="#888888"
             />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/ll_friend"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/img_friend"
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:src="@mipmap/news_add" />

        <TextView
            android:id="@+id/txt_friend"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="@string/txt_nav_friend"
            android:textSize="12dp"
            android:textColor="#888888"
             />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/ll_user"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/img_user"
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:src="@mipmap/phone"  />

        <TextView
            android:id="@+id/txt_user"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="@string/txt_nav_user"
            android:textSize="12dp"
            android:textColor="#888888"
             />
    </LinearLayout>

</LinearLayout>

2.3 主视图 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <!--这里有个小技巧,把底部菜单栏的每一个小的LinearLayout的宽度都设置成0dp,然后用weight权重去分配它,中间内容区域也是把高度设置成0dp,然后用weight权重去分配它。(weight默认是把界面里空闲的位置作为划分位置,所以这里的宽度或者高度要注意设置成0dp)-->
    <include layout="@layout/activity_top" />

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/vp_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="#ffffff"
        tools:ignore="MissingConstraints"></androidx.viewpager.widget.ViewPager>

    <include layout="@layout/activity_bottom" />

</LinearLayout>
这里有个小技巧,把底部菜单栏的每一个小的LinearLayout的宽度都设置成0dp,然后用weight权重去分配它,中间内容区域也是把高度设置成0dp,然后用weight权重去分配它。(weight默认是把界面里空闲的位置作为划分位置,所以这里的宽度或者高度要注意设置成0dp)

2.4 分页视图 page_home.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=".ui.HomeActivity">

    <TextView
        android:id="@+id/txt_home_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="我是01"
        android:textColor="#1B940A"
        android:textSize="30dp" />

</RelativeLayout>

2.5 ContentAdapter.java:ViewPager需配合一个Adapter使用,所以需先自定义一个Adapter。

package com.rc.bottombar;

import java.util.List;

import android.view.View;
import android.view.ViewGroup;

import androidx.viewpager.widget.PagerAdapter;

public class ContentAdapter extends PagerAdapter {

    private List<View> views;

    public ContentAdapter(List<View> views) {
        this.views = views;
    }

    @Override
    public int getCount() {
        return views.size();
    }

    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
        return arg0 == arg1;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view = views.get(position);
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView(views.get(position));
    }

}

2.6 MainActivity.java

package com.rc.bottombar;

import androidx.viewpager.widget.ViewPager;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.rc.bottombar.ui.HomeActivity;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends Activity implements View.OnClickListener, ViewPager.OnPageChangeListener {

    private TextView txt_title;

    // 底部菜单4个Linearlayout
    private LinearLayout ll_home;
    private LinearLayout ll_address;
    private LinearLayout ll_friend;
    private LinearLayout ll_setting;

    // 底部菜单4个ImageView
    private ImageView img_home;
    private ImageView img_news;
    private ImageView img_friend;
    private ImageView img_user;

    // 底部菜单4个菜单标题
    private TextView txt_home;
    private TextView txt_news;
    private TextView txt_friend;
    private TextView txt_user;

    // 中间内容区域
    private ViewPager viewPager;

    // ViewPager适配器ContentAdapter
    private ContentAdapter adapter;
    private List<View> views;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();// 初始化控件
        initEvent();// 设置按钮监听

        txt_title.setText(R.string.txt_nav_home);
        txt_home.setTextColor(0xff1B940A);
    }

    private void initEvent() {
        ll_home.setOnClickListener(this);
        ll_address.setOnClickListener(this);
        ll_friend.setOnClickListener(this);
        ll_setting.setOnClickListener(this);
        viewPager.setOnPageChangeListener(this);
    }

    private void initView() {
        txt_title = findViewById(R.id.title);

        // 底部菜单4个Linearlayout
        ll_home = findViewById(R.id.ll_home);
        ll_address = findViewById(R.id.ll_news);
        ll_friend = findViewById(R.id.ll_friend);
        ll_setting = findViewById(R.id.ll_user);

        // 底部菜单4个ImageView
        img_home = findViewById(R.id.img_home);
        img_news = findViewById(R.id.img_news);
        img_friend = findViewById(R.id.img_friend);
        img_user = findViewById(R.id.img_user);

        // 底部菜单4个菜单标题
        txt_home = findViewById(R.id.txt_home);
        txt_news = findViewById(R.id.txt_news);
        txt_friend = findViewById(R.id.txt_friend);
        txt_user = findViewById(R.id.txt_user);

        // 中间内容区域ViewPager
        viewPager = findViewById(R.id.vp_content);

        // 适配器
        View page_home = View.inflate(MainActivity.this, R.layout.page_home, null);
        View page_news = View.inflate(MainActivity.this, R.layout.page_news, null);
        View page_friend = View.inflate(MainActivity.this, R.layout.page_friend, null);
        View page_user = View.inflate(MainActivity.this, R.layout.page_user, null);

        views = new ArrayList<View>();
        views.add(page_home);
        views.add(page_news);
        views.add(page_friend);
        views.add(page_user);
        adapter = new ContentAdapter(views);
        viewPager.setAdapter(adapter);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.ll_home:
                restartBotton();
                txt_title.setText(R.string.txt_nav_home);
                txt_home.setTextColor(0xff1B940A);
                viewPager.setCurrentItem(0);
                break;
            case R.id.ll_news:
                restartBotton();
                txt_title.setText(R.string.txt_nav_news);
                txt_news.setTextColor(0xff1B940A);
                viewPager.setCurrentItem(1);
                break;
            case R.id.ll_friend:
                restartBotton();
                txt_title.setText(R.string.txt_nav_friend);
                txt_friend.setTextColor(0xff1B940A);
                viewPager.setCurrentItem(2);
                break;
            case R.id.ll_user:
                restartBotton();
                txt_title.setText(R.string.txt_nav_user);
                txt_user.setTextColor(0xff1B940A);
                viewPager.setCurrentItem(3);
                break;

            default:
                break;
        }
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        restartBotton();
        switch (position) {
            case 0:
                txt_title.setText(R.string.txt_nav_home);
                txt_home.setTextColor(0xff1B940A);
                break;
            case 1:
                txt_title.setText(R.string.txt_nav_news);
                txt_news.setTextColor(0xff1B940A);
                break;
            case 2:
                txt_title.setText(R.string.txt_nav_friend);
                txt_friend.setTextColor(0xff1B940A);
                break;
            case 3:
                txt_title.setText(R.string.txt_nav_user);
                txt_user.setTextColor(0xff1B940A);
                break;

            default:
                break;
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }

    //重置链接样式
    private void restartBotton() {
        txt_home.setTextColor(Color.parseColor("#888888"));
        txt_news.setTextColor(Color.parseColor("#888888"));
        txt_friend.setTextColor(Color.parseColor("#888888"));
        txt_user.setTextColor(Color.parseColor("#888888"));
    }
}

注意事项:

1.需实现视图点击事件和ViewPager切换事件,implements View.OnClickListener, ViewPager.OnPageChangeListener。

2.initEvent()方法中给控件绑定事件后,下面的Listener才捕捉得到。

3.上面代码只切换选中菜单文字的效果,选中图片也是可以切换的,暂忽略。

四、实现方式2(Fragment方式)

1.布局文件基本没变化,只是把主界面的ViewPager改成了FramLayout,其他文件保持一致,就不贴出来了。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <!--这里有个小技巧,把底部菜单栏的每一个小的LinearLayout的宽度都设置成0dp,然后用weight权重去分配它,
         中间内容区域也是把高度设置成0dp,然后用weight权重去分配它。
         (weight默认是把界面里空闲的位置作为划分位置,所以这里的宽度或者高度要注意设置成0dp)-->
    <include layout="@layout/activity_top" />
    <FrameLayout
        android:id="@+id/fl_content"
        android:layout_width="match_parent"
        android:background="#ffffff"
        android:layout_height="0dp"
        android:layout_weight="1" >
    </FrameLayout>
    <include layout="@layout/activity_bottom" />
</LinearLayout>

2.新增4个Fragment类,结构如下图:

以HomeFragment.java 为例,其他类似。

package com.rc.bottombar.ui;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.Nullable;

import com.rc.bottombar.R;

import java.text.SimpleDateFormat;
import java.util.Date;

public class HomeFragment extends Fragment {
    View view;
    TextView title;

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.page_home, container, false);
        title = view.findViewById(R.id.txt_home_title);
        title.setText("我是" + getResources().getString(R.string.txt_nav_home));
        return view;
    }

    public void Load() {
        //title.setText("当前时间:\n" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

    }

}

 3.MainActivity.java

package com.rc.bottombar;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.rc.bottombar.ui.FriendFragment;
import com.rc.bottombar.ui.HomeFragment;
import com.rc.bottombar.ui.NewsFragment;
import com.rc.bottombar.ui.UserFragment;

public class MainActivity extends Activity implements View.OnClickListener {

    private TextView txt_title;

    // 底部菜单4个Linearlayout
    private LinearLayout ll_home;
    private LinearLayout ll_address;
    private LinearLayout ll_friend;
    private LinearLayout ll_setting;

    // 底部菜单4个ImageView
    private ImageView img_home;
    private ImageView img_news;
    private ImageView img_friend;
    private ImageView img_user;

    // 底部菜单4个菜单标题
    private TextView txt_home;
    private TextView txt_news;
    private TextView txt_friend;
    private TextView txt_user;

    // 4个Fragment
    private HomeFragment homeFragment;
    private Fragment newsFragment;
    private Fragment friendFragment;
    private Fragment userFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();// 初始化控件
        initEvent();// 设置按钮监听

        // 初始化并设置当前Fragment
        initFragment(0);

    }

    private void initEvent() {
        ll_home.setOnClickListener(this);
        ll_address.setOnClickListener(this);
        ll_friend.setOnClickListener(this);
        ll_setting.setOnClickListener(this);
    }

    private void initView() {
        txt_title = findViewById(R.id.title);

        // 底部菜单4个Linearlayout
        ll_home = findViewById(R.id.ll_home);
        ll_address = findViewById(R.id.ll_news);
        ll_friend = findViewById(R.id.ll_friend);
        ll_setting = findViewById(R.id.ll_user);

        // 底部菜单4个ImageView
        img_home = findViewById(R.id.img_home);
        img_news = findViewById(R.id.img_news);
        img_friend = findViewById(R.id.img_friend);
        img_user = findViewById(R.id.img_user);

        // 底部菜单4个菜单标题
        txt_home = findViewById(R.id.txt_home);
        txt_news = findViewById(R.id.txt_news);
        txt_friend = findViewById(R.id.txt_friend);
        txt_user = findViewById(R.id.txt_user);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.ll_home:
                restartBotton();
                txt_title.setText(R.string.txt_nav_home);
                txt_home.setTextColor(0xff1B940A);
                initFragment(0);
                break;
            case R.id.ll_news:
                restartBotton();
                txt_title.setText(R.string.txt_nav_news);
                txt_news.setTextColor(0xff1B940A);
                initFragment(1);
                break;
            case R.id.ll_friend:
                restartBotton();
                txt_title.setText(R.string.txt_nav_friend);
                txt_friend.setTextColor(0xff1B940A);
                initFragment(2);
                break;
            case R.id.ll_user:
                restartBotton();
                txt_title.setText(R.string.txt_nav_user);
                txt_user.setTextColor(0xff1B940A);
                initFragment(3);
                break;

            default:
                break;
        }
    }

    private void initFragment(int index) {
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        hideFragment(transaction);
        switch (index) {
            case 0:
                if (homeFragment == null) {
                    homeFragment = new HomeFragment();
                    transaction.add(R.id.fl_content, homeFragment);
                } else {

                    homeFragment.Load();//加载数据
                    transaction.show(homeFragment);
                }
                break;
            case 1:
                if (newsFragment == null) {
                    newsFragment = new NewsFragment();
                    transaction.add(R.id.fl_content, newsFragment);
                } else {
                    transaction.show(newsFragment);
                }

                break;
            case 2:
                if (friendFragment == null) {
                    friendFragment = new FriendFragment();
                    transaction.add(R.id.fl_content, friendFragment);
                } else {
                    transaction.show(friendFragment);
                }

                break;
            case 3:
                if (userFragment == null) {
                    userFragment = new UserFragment();
                    transaction.add(R.id.fl_content, userFragment);
                } else {
                    transaction.show(userFragment);
                }

                break;
            default:
                break;
        }
        transaction.commit();

    }

    //隐藏Fragment
    private void hideFragment(android.app.FragmentTransaction transaction) {
        if (homeFragment != null) {
            transaction.hide(homeFragment);
        }
        if (newsFragment != null) {
            transaction.hide(newsFragment);
        }
        if (friendFragment != null) {
            transaction.hide(friendFragment);
        }
        if (userFragment != null) {
            transaction.hide(userFragment);
        }
    }

    //重置链接样式
    private void restartBotton() {
        txt_home.setTextColor(Color.parseColor("#888888"));
        txt_news.setTextColor(Color.parseColor("#888888"));
        txt_friend.setTextColor(Color.parseColor("#888888"));
        txt_user.setTextColor(Color.parseColor("#888888"));
    }
}

五、小结

方式1:基于ViewPager实现的内容:
优点:
1、界面可以滑动,美观,流畅。
缺点:
1、当界面里有一些需要用手势来实现的内容会起冲突,比如我们ListView里的侧滑删除。
2、由于采用的是ViewPager,所以页面内容实现代码会严重依赖于MainActivity,代码太过冗余,不便于后期维护。 

方式2:基于Fragment实现的内容:
优点:
1、Fragment文件单独存在,各自页面的内容各自去实现完成,有自己的生命周期,便于后期维护。
2、对于需要手势操作的一些内容不会起冲突。
缺点:
1、界面不可滑动,比较死板。

参考内容:

https://www.cnblogs.com/lichenwei/p/4444750.html

发布了438 篇原创文章 · 获赞 229 · 访问量 304万+

猜你喜欢

转载自blog.csdn.net/a497785609/article/details/103765907
今日推荐