两种常用的带有底部导航的AndroidUI实现

最近决定,从头整理Android基础知识,和常用基本架构 和框架 ,方便以后使用,更主要是知道自己到底会些什么,突破技术瓶颈!!!

这一篇先从基本上每个应用都会搭建的软件UI 总结做起,这里的软件架构是指对现在流行软件中都会搭建的UI界面底部导航,并切换不同的片段或者跳转页面,如下图:

《两种常用的带有底部导航的AndroidUI实现》 底部均带有导航栏

主要实现一共是以下两种选择:

1、RadioButton 加帧布局并替换帧布局中的片段 实现点击按钮可切换片段的效果(这里面采用尚硅谷杨老师的封装方法)

2、结合RadioButton 加ViewPager 填充片段实现可点击并支持滑动切换片段的底部导航

一、RadioButton 加帧布局并替换帧布局中的片段

相信这种实现方式,很多人都会,这里面涉及到的主要是片段的生命周期,片段事务的使用,替换,添加,覆盖,还有就是Radiobutton的使用已经很普遍了,写在这里就算是总结,之后如果需要直接过来粘贴了。
效果图如下,很简单的效果,但是这里面加入了一下代码结构设计的思想,方便提升,还有就是防止片段重复,反复的初始化:

《两种常用的带有底部导航的AndroidUI实现》 片段效果图

1、首先我们需要一个主Activity,然后就是四个片段

片段的生命周期这里就不做赘述了,直接来看这几个片段的创建过程,我是很喜欢这种方式,也为之后写代码提供了一种思路:

首先一个BaseFragment作为基类:这样就定义了一个规范,有时感觉定义接口并没有这样优雅。

package com.wgd.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by wangg on 2018/7/26.
 * * 作用:基类,公共类
 * CommonFragment,ThirdPartyFragment,CustomFragment,OtherFragment等都要继承该类
 */
public abstract class BaseFragment extends Fragment {
    //上下文
    protected Context context;

    protected String TAG="FragmentTAG";
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context=getActivity();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return initView();
    }
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        initData();
    }
    protected abstract View initView();
    /**
     * 当孩子需要初始化数据,或者联网请求绑定数据,展示数据的 等等可以重写该方法
     */
    protected void initData(){}
}

然后四个片段主要是依照这个抽象类的标准去完成:
举例:

package com.wgd.fragment;

import android.graphics.Color;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.TextView;

/**
 * Created by 王国栋 on 2018/7/26.
 * qq 1350802989
 * 微信 WGDLOVELC
 * 你的煎熬,都是因为你的上进心和你的能力不成正比
 */
public class CommonFragment extends BaseFragment{
    TextView textView;
    @Override
    protected View initView() {
        Log.i(TAG, "initView: CommonFragment初始化了");
        textView=new TextView(context);
        textView.setTextSize(20);
        textView.setTextColor(Color.RED);
        textView.setGravity(Gravity.CENTER);
        return textView;
    }
    @Override
    protected void initData() {
        super.initData();
        textView.setText("common");
    }
}

以此类推创建另外三个,最后添加到主Activity中,在Activity中完成片段的添加替换和覆盖操作,什么是覆盖?就是为了防止片段反复初始化!
主Activity代码:

package com.wgd.example1;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RadioGroup;

import com.wgd.fragment.BaseFragment;
import com.wgd.fragment.CommonFragment;
import com.wgd.fragment.CustomFragment;
import com.wgd.fragment.OtherFragment;
import com.wgd.fragment.ThirdPartyFragment;

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

public class MainActivity extends AppCompatActivity {
    private RadioGroup mRg_main;
    private List<BaseFragment> mBaseFragment;
    /**
     * 选中的Fragment的对应的位置
     */
    private int position;
    /**
     * 上次切换的Fragment
     */
    private Fragment mContent;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化View
        initView();
        //初始化Fragment
        initFragment();
        //设置RadioGroup的监听
        setListener();
    }
    private void setListener() {
        mRg_main.setOnCheckedChangeListener(new MyOnCheckedChangeListener());
        //设置默认选中常用框架
        mRg_main.check(R.id.rb_common_frame);
    }

    class MyOnCheckedChangeListener implements RadioGroup.OnCheckedChangeListener {
        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            switch (checkedId){
                case R.id.rb_common_frame://常用框架
                    position = 0;
                    break;
                case R.id.rb_thirdparty://第三方
                    position = 1;
                    break;
                case R.id.rb_custom://自定义
                    position = 2;
                    break;
                case R.id.rb_other://其他
                    position = 3;
                    break;
                default:
                    position = 0;
                    break;
            }
            //根据位置得到对应的Fragment
            BaseFragment to = getFragment();
            //替换
            switchFrament(mContent,to);
        }
    }
    /**
     *
     * @param from 刚显示的Fragment,马上就要被隐藏了
     * @param to 马上要切换到的Fragment,一会要显示
     */
    private void switchFrament(Fragment from,Fragment to) {
        if(from != to){
            mContent = to;
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            //才切换
            //判断有没有被添加
            if(!to.isAdded()){
                //to没有被添加
                //from隐藏
                if(from != null){
                    ft.hide(from);
                }
                //添加to
                if(to != null){
                    ft.add(R.id.fl_content,to).commit();
                }
            }else{
                //to已经被添加
                // from隐藏
                if(from != null){
                    ft.hide(from);
                }
                //显示to
                if(to != null){
                    ft.show(to).commit();
                }
            }
        }

    }
//    private void switchFrament(BaseFragment fragment) {
//        //1.得到FragmentManger
//        FragmentManager fm = getSupportFragmentManager();
//        //2.开启事务
//        FragmentTransaction transaction = fm.beginTransaction();
//        //3.替换
//        transaction.replace(R.id.fl_content, fragment);
//        //4.提交事务
//        transaction.commit();
//    }

    /**
     * 根据位置得到对应的Fragment
     * @return
     */
    private BaseFragment getFragment() {
        BaseFragment fragment = mBaseFragment.get(position);
        return fragment;
    }

    private void initFragment() {
        mBaseFragment = new ArrayList<>();
        mBaseFragment.add(new CommonFragment());//常用框架Fragment
        mBaseFragment.add(new ThirdPartyFragment());//第三方Fragment
        mBaseFragment.add(new CustomFragment());//自定义控件Fragment
        mBaseFragment.add(new OtherFragment());//其他Fragment
    }

    private void initView() {
        setContentView(R.layout.activity_main);
        mRg_main = (RadioGroup) findViewById(R.id.rg_main);
    }
}

activty_main.xml文件

<?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="com.wgd.example1.MainActivity">
    <!--标题栏-->
    <include layout="@layout/layout_title" />
    <!--FrameLayout-->
    <FrameLayout
        android:id="@+id/fl_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <!--底部的RadioGroup-->
    <RadioGroup
        android:id="@+id/rg_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#11000000"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:padding="5dp">


        <RadioButton
            android:id="@+id/rb_common_frame"
            style="@style/bottom_tag_style"
            android:drawableTop="@drawable/rb_common_frame_drawable_selector"
            android:text="常用框架"
            />

        <RadioButton
            android:id="@+id/rb_thirdparty"
            style="@style/bottom_tag_style"
            android:drawableTop="@drawable/rb_thirdparty_drawable_selector"
            android:text="第三方"

            />
        <RadioButton
            android:id="@+id/rb_custom"
            style="@style/bottom_tag_style"
            android:drawableTop="@drawable/rb_custom_drawable_selector"
            android:text="自定义控件" />
        <RadioButton
            android:id="@+id/rb_other"
            style="@style/bottom_tag_style"
            android:drawableTop="@drawable/rb_other_drawable_selector"
            android:text="其他" />

    </RadioGroup>
</LinearLayout>

bottom_tag_style文件

   <style name="bottom_tag_style" >
        <!-- Customize your theme here. -->
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_weight">1</item>
        <item name="android:button">@android:color/transparent</item>
        <item name="android:drawablePadding">3dp</item>
        <item name="android:gravity">center</item>
        <item name="android:textColor">@drawable/bottom_textcolor_drawable_selector</item>
        <item name="android:textSize">10sp</item>
    </style>

bottom_textcolor_drawable_selector

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="false" android:color="#363636"/>
    <item android:state_checked="true" android:color="#3097FD"/>
</selector>

rb_common_frame_drawable_selector文件,另外三个片段一样

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false" android:drawable="@drawable/ic_tab_video"/>
<item android:state_checked="true" android:drawable="@drawable/ic_tab_video_press"/>
</selector>

这个例子RadioButton的字体的颜色是通过Selector变化的,也可以像下面一样,第二种方式实现。

二、RadioButton 加ViewPager 填充片段实现(可点击可滑动)

1、首先同样需要一个主Activity,四个片段(一般应用底部都会分为四个部分,可根据实际需求添加)

底部导航栏的图片,每个主题对应深色和浅色两张图片,分别用来给RedioButton填充背景,作为待选择和被选择的效果。

主Activity布局文件

<?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=".activity.MainActivity">
    <!-- 这里可根据需求添加顶部title布局这个例子就省略了 -->

    <android.support.v4.view.ViewPager
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:id="@+id/viewpager"
        android:background="@color/background"
        >
    </android.support.v4.view.ViewPager>

    <RadioGroup
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_weight="0"
        android:orientation="horizontal"
        android:gravity="center"
        android:background="#E3E2E1"
        android:id="@+id/radiogroup"
        >
        <RadioButton
            style="@style/MyRadioButtonStyle"
            android:id="@+id/r1"
            android:drawableTop="@drawable/radiobtn_selector1"
            android:text="@string/workbank"
            android:checked="true"
            android:textColor="@color/blue"
            />
        <RadioButton
            style="@style/MyRadioButtonStyle"
            android:id="@+id/r2"
            android:drawableTop="@drawable/radiobtn_selector2"
            android:text="@string/jobfair"
            android:textColor="@color/gray"
            />
        <RadioButton
            style="@style/MyRadioButtonStyle"
            android:id="@+id/r3"
            android:drawableTop="@drawable/radiobtn_selector3"
            android:text="@string/news"
            android:textColor="@color/gray"
            />
        <RadioButton
            style="@style/MyRadioButtonStyle"
            android:id="@+id/r4"
            android:drawableTop="@drawable/radiobtn_selector4"
            android:text="@string/mine"
            android:textColor="@color/gray"
            />
    </RadioGroup>
</LinearLayout>

style如下:

 <style name="MyRadioButtonStyle">
        <item name="android:button">@null</item>
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_weight">1</item>
        <item name="android:gravity">center</item>
    </style>

Selecter文件如下(需要几个导航栏就创建几个)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true" android:drawable="@drawable/nav1_01"></item>
    <item android:state_checked="false" android:drawable="@drawable/nav1_02"></item>
</selector>

RedioButton 和 Selecter的用法应该不用多说了,主要是再Style样式里面的配置。
RedioButton 图片下发的字体颜色还可以用这种方式实现,就是先再在xml中设置一个默认颜色,然后在Activty中根据选中状态,修改字体颜色。
Selecter 给选中和未被选中时两个不同颜色的图片即可,注意是state_checked

主Activity中的代码

/**
 * author wanggd
 *
 * 主入口Activity
 */
public class MainActivity extends FragmentActivity
        implements RadioGroup.OnCheckedChangeListener,ViewPager.OnPageChangeListener{
    private RadioButton r1, r2, r3, r4;
    private RadioGroup radioGroup;
    private ViewPager pager;
    private List<Fragment> fraglist;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }
    private void initView() {
        fraglist = new ArrayList<>();
        fraglist.add(new WorkBankFragment());
        fraglist.add(new JobFairFragment());
        fraglist.add(new NewsFragment());
        fraglist.add(new MineFragment());
        r1 = (RadioButton) findViewById(R.id.r1);
        r2 = (RadioButton) findViewById(R.id.r2);
        r3 = (RadioButton) findViewById(R.id.r3);
        r4 = (RadioButton) findViewById(R.id.r4);
        radioGroup = (RadioGroup) findViewById(R.id.radiogroup);
        radioGroup.setOnCheckedChangeListener(this);
        pager = (ViewPager) findViewById(R.id.viewpager);
        pager.setPageTransformer(true, new DepthPageTransformer());
        pager.addOnPageChangeListener(this);
        pager.setAdapter(new MyAdapter(getSupportFragmentManager()));
    }
    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        if (checkedId == R.id.r1) {
            checkLogin();
            r1.setTextColor(ContextCompat.getColor(this, R.color.blue));
            r2.setTextColor(ContextCompat.getColor(this, R.color.gray));
            r3.setTextColor(ContextCompat.getColor(this, R.color.gray));
            r4.setTextColor(ContextCompat.getColor(this, R.color.gray));
            pager.setCurrentItem(0);
        } else if (checkedId == R.id.r2) {
            checkLogin();
            r2.setTextColor(ContextCompat.getColor(this, R.color.blue));
            r1.setTextColor(ContextCompat.getColor(this, R.color.gray));
            r3.setTextColor(ContextCompat.getColor(this, R.color.gray));
            r4.setTextColor(ContextCompat.getColor(this, R.color.gray));
            pager.setCurrentItem(1);
        } else if (checkedId == R.id.r3) {
            checkLogin();
            r3.setTextColor(ContextCompat.getColor(this, R.color.blue));
            r1.setTextColor(ContextCompat.getColor(this, R.color.gray));
            r2.setTextColor(ContextCompat.getColor(this, R.color.gray));
            r4.setTextColor(ContextCompat.getColor(this, R.color.gray));
            pager.setCurrentItem(2);
        } else if (checkedId == R.id.r4) {
            checkLogin();
            r4.setTextColor(ContextCompat.getColor(this, R.color.blue));
            r1.setTextColor(ContextCompat.getColor(this, R.color.gray));
            r3.setTextColor(ContextCompat.getColor(this, R.color.gray));
            r2.setTextColor(ContextCompat.getColor(this, R.color.gray));
            pager.setCurrentItem(3);
        }
    }
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    }
    @Override
    public void onPageSelected(int position) {
        switch (position) {
            case 0:
                r1.setChecked(true);
                break;
            case 1:
                r2.setChecked(true);
                break;
            case 2:
                r3.setChecked(true);
                break;
            case 3:
                r4.setChecked(true);
                break;
            default:
                break;
        }
    }
    @Override
    public void onPageScrollStateChanged(int state) {
    }
    private class MyAdapter extends FragmentStatePagerAdapter {

        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return fraglist.get(position);
        }

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

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            //这个地方注释掉可以防止ViewPager加载卡顿的问题
            //super.destroyItem(container, position, object);
        }
    }
}

Fragment 的实现 可以结合第一种方式实现。或者如果java基础薄弱根据实际需要直接创建不同的Fragment,然后每个Fragment一个布局文件也可以,只是会显得杂乱而已
到此,就可以实现结合viewpager的滑动导航,其实也可以结合上面的例子,将代码精简很多,这是很久之前写的代码了,作为例子放到这。

    原文作者:从新开始学android
    原文地址: https://www.jianshu.com/p/471014419140
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞