美文网首页Android收藏集需要使用Android开发
两种常用的带有底部导航的AndroidUI实现

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

作者: 从新开始学android | 来源:发表于2018-07-26 21:16 被阅读273次

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

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

    底部均带有导航栏

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

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

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

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

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


    片段效果图

    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的滑动导航,其实也可以结合上面的例子,将代码精简很多,这是很久之前写的代码了,作为例子放到这。

    相关文章

      网友评论

      本文标题:两种常用的带有底部导航的AndroidUI实现

      本文链接:https://www.haomeiwen.com/subject/rrpvmftx.html