android 通用是框架,对导航栏和fragment的封装

简介: android 通用是框架,对导航栏和fragment的封装

这是fragmentation 和 底部的导航栏 进行一些封装,效果就像是微信的页面,上面是碎片,下面是tab。使用了映射的关系,也就是键值对的意思,键对应tab ,键对应的fragmentation非常好看,使用起来非常方便,逻辑清楚,层次分明。效果如图



0a2653c851af460fa595bd959398a8f1.png


这个框架使用的fragment 不是原生的 fragment ,而是 fragmentation。不会的也可以去查一下。其实这里使用fragment也是可以的。只需要改一下继承的类就好了。


还有ButterKnife ,使用注解生成 R文件,不需要findViewById。不会使用也没关系,直接按原来的来就好,会的话就更好了。


下面看一下实现:


1,抽象的基类,实际上就是fragment的基类


public abstract class BaseDelegate extends SwipeBackFragment {
    @SuppressWarnings("SpellCheckingInspection")
    private Unbinder mUnbinder = null;
    /**
     * @return 可以是一个View ,也可以是一个Layout的Id,代表一个视图
     */
    public abstract Object setLayout();
    public abstract void onBindView(@Nullable Bundle savedInstanceState, View rootView);
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        final View rootView;
        //返回的是 Layout的 id
        if (setLayout() instanceof Integer) {
            rootView = inflater.inflate((Integer) setLayout(), container, false);
        } else if (setLayout() instanceof View) {
            rootView = (View) setLayout();
        } else {
            throw new ClassCastException("setLayout() type must be int or view");
        }
        //绑定 资源(ButterKnife)
        mUnbinder = ButterKnife.bind(this, rootView);
        //子类 实现,传入 Bundle 和 碎片视图
        onBindView(savedInstanceState, rootView);
        return rootView;
    }
    /**
     * @return 返回一个 Activity
     */
    public final ProxyActivity getProxyActivity(){
        return (ProxyActivity) _mActivity;
    }
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (mUnbinder != null) {
            mUnbinder.unbind();
        }
    }
}


public abstract class LatteDelegate extends PermissionCheckerDelegate{
  //这里没用,但是可以在这里进行一些权限的操作
}


上面进行了一些简单的封装。


2,fragment 界面的基类,如果要显示某个页面,就需要继承自这个类


/**
 * Copyright (C)
 *
 * @file: BottomItemDelegate
 * @author: 345
 * @Time: 2019/4/25 19:26
 * @description: 导航栏对应的 页面
 */
public abstract class BottomItemDelegate extends LatteDelegate implements View.OnKeyListener {
    private long mExitTime = 0;
    private static final int EXIT_TIME = 2000;
    @Override
    public void onResume() {
        super.onResume();
        final View rootView = getView();
        if (rootView != null) {
            rootView.setFocusableInTouchMode(true);
            rootView.requestFocus();
            rootView.setOnKeyListener(this);
        }
    }
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
            if ((System.currentTimeMillis() - mExitTime) > EXIT_TIME) {
                Toast.makeText(_mActivity, "双击退出" + getString(com.wang.avi.R.string.app_name), Toast.LENGTH_SHORT).show();
                mExitTime = System.currentTimeMillis();
            } else {
                _mActivity.finish();
                if (mExitTime != 0) {
                    mExitTime = 0;
                }
            }
            return true;
        }
        return false;
    }
}


3,tab 的封装,也就是导航栏,其实就是一个bean类,导航栏有几个tab,就new几个对象。(注意这个的导航栏使用了矢量图 第三方库ionicons),不了解的可以先看一下这篇文章


**
 * Copyright (C)
 *
 * @file: BottomTabBean
 * @author: 345
 * @Time: 2019/4/25 19:40
 * @description: 导航栏 的Tab
 */
public final class BottomTabBean {
    /**
     * 图标
     */
    private final CharSequence ICON;
    /**
     * 文字
     */
    private final CharSequence TITLE;
    public BottomTabBean(CharSequence ICON, CharSequence TITLE) {
        this.ICON = ICON;
        this.TITLE = TITLE;
    }
    public CharSequence getIcon() {
        return ICON;
    }
    public CharSequence getTitle() {
        return TITLE;
    }
}


4,创建一个 ItemBuilder 类,用来创造键值对,相当于一个工厂类。用来让tab 和 fragment 产生 映射关系。


/**
 * Copyright (C)
 *
 * @file: ItemBuilder
 * @author: 345
 * @Time: 2019/4/25 19:42
 * @description: 工厂类,用来构建 导航栏 和 碎片
 */
public final class ItemBuilder {
    private final LinkedHashMap<BottomTabBean,BottomItemDelegate> ITEMS = new LinkedHashMap<>();
    static ItemBuilder builder(){
        return new ItemBuilder();
    }
    public final ItemBuilder addItem(BottomTabBean bean,BottomItemDelegate delegate){
        ITEMS.put(bean,delegate);
        return this;
    }
    public final ItemBuilder addItem(LinkedHashMap<BottomTabBean,BottomItemDelegate> items){
        ITEMS.putAll(items);
        return this;
    }
    public final LinkedHashMap<BottomTabBean,BottomItemDelegate> build(){
        return ITEMS;
    }
}


5,对键值对 进行一些封装和使用。通果上面的ItemBuilder 类拿到要显示的所有 fragment和 tab 的类。然后进行一些逻辑的处理。这是一个抽象类。还需要一个子类来实现一些方法。比如setItems()方法 添加需要的 map 。对tab进行监听。对fragment进行处理。他的子类就是用来创建 所有的键值对的。


/**
 * Copyright (C)
 *
 * @file: BaseBottomDelegate
 * @author: 345
 * @Time: 2019/4/25 19:24
 * @description: 对所有的键值对进行管理,也就是 碎片和tab,这是一个抽象类。
 */
public abstract class BaseBottomDelegate extends LatteDelegate implements View.OnClickListener {
    /**
     * 存储所有的子 Fragment
     */
    private final ArrayList<BottomItemDelegate> ITEM_DELEGATES = new ArrayList<>();
    /**
     * 存储所有的子 TabBean
     */
    private final ArrayList<BottomTabBean> TAB_BEANS = new ArrayList<>();
    /**
     * 存储 Fragment和TabBean 的映射
     */
    private final LinkedHashMap<BottomTabBean, BottomItemDelegate> ITEMS = new LinkedHashMap<>();
    /**
     * 当前Fragment 的位置
     */
    private int mCurrentDelegate = 0;
    /**
     * 进入程序展示 的Fragment
     */
    private int mIndexDelegate = 0;
    /**
     * Tab 的颜色
     */
    private int mClickedColor = Color.RED;
    /**
     * 底部 tab
     */
    @BindView(R2.id.bottom_bar)
    LinearLayoutCompat mBottomBar = null;
    /**
     * @param builder 要添加的 映射
     * @return  返回值为 LinkedHashMap
     */
    public abstract LinkedHashMap<BottomTabBean, BottomItemDelegate> setItems(ItemBuilder builder);
    @Override
    public Object setLayout() {
        return R.layout.delegate_bottom;
    }
    public abstract int setIndexDelegate();
    /**
     * 该注解表示 这必须是一个颜色
     */
    @ColorInt
    public abstract int setClickedColor();
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mIndexDelegate = setIndexDelegate();
        if (setClickedColor() != 0){
            mClickedColor = setClickedColor();
        }
        //拿到工厂类的实例
        final ItemBuilder builder = ItemBuilder.builder();
        //获取 添加完成的键值对
        final LinkedHashMap<BottomTabBean,BottomItemDelegate> items = setItems(builder);
        //将 键值对 保存在ITEMS 中
        ITEMS.putAll(items);
        //拿到键和值
        for (Map.Entry<BottomTabBean,BottomItemDelegate> item  :ITEMS.entrySet()){
            final BottomTabBean key = item.getKey();
            final BottomItemDelegate value = item.getValue();
            TAB_BEANS.add(key);
            ITEM_DELEGATES.add(value);
        }
    }
    @Override
    public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
        final int size = ITEMS.size();
        for (int i = 0; i < size; i++) {
            //第一个参数 布局,第二个参数 为给第一个参数加载的布局 设置一个父布局
            LayoutInflater.from(getContext()).inflate(R.layout.bottom_item_icon_text_layout,mBottomBar);
            //返回指定的视图
            final RelativeLayout item = (RelativeLayout) mBottomBar.getChildAt(i);
            //设置每个 item的点击事件 和标记
            item.setTag(i);
            item.setOnClickListener(this);
            //拿到 item 的第一个和 第二个子布局
            final IconTextView itemIcon = (IconTextView) item.getChildAt(0);
            final AppCompatTextView itemTitle  = (AppCompatTextView) item.getChildAt(1);
            //获取 集合中对应的 Tab
            final BottomTabBean bean = TAB_BEANS.get(i);
            //初始化 tab 数据
            itemIcon.setText(bean.getIcon());
            itemTitle.setText(bean.getTitle());
            //判断是否是 当前显示
            if (i == mIndexDelegate){
                itemIcon.setTextColor(mClickedColor);
                itemTitle.setTextColor(mClickedColor);
            }
        }
        //返回一个数组,里边是fragment的。注意fragment 是继承 supportFragment 的,所以这里的集合是这个类型
        //fragmentation 需要我们这样做
        final SupportFragment[] delegateArry = ITEM_DELEGATES.toArray(new SupportFragment[size]);
        //加载多个根fragment ,并显示其中一个,第二个参数为要显示的fragment
        loadMultipleRootFragment(R.id.bottom_bar_delegate_container,mIndexDelegate,delegateArry);
    }
    /**
     * 重置所有颜色
     */
    private void resetColor(){
        //拿到 底部tab的子布局的size
        final int count = mBottomBar.getChildCount();
        for (int i = 0; i < count; i++) {
            final RelativeLayout item = (RelativeLayout) mBottomBar.getChildAt(i);
            final IconTextView itemIcon = (IconTextView) item.getChildAt(0);
            itemIcon.setTextColor(Color.GRAY);
            final AppCompatTextView itemTitle = (AppCompatTextView) item.getChildAt(1);
            itemTitle.setTextColor(Color.GRAY);
        }
    }
    @Override
    public void onClick(View v) {
        final int tag = (int) v.getTag();
        resetColor();
        final RelativeLayout item = (RelativeLayout) v;
        final IconTextView itemIcon = (IconTextView) item.getChildAt(0);
        itemIcon.setTextColor(mClickedColor);
        final AppCompatTextView itemTitle = (AppCompatTextView) item.getChildAt(1);
        itemTitle.setTextColor(mClickedColor);
        //第一次参数 为要显示的,第二个则是要隐藏的
        showHideFragment(ITEM_DELEGATES.get(tag),ITEM_DELEGATES.get(mCurrentDelegate));
        // 记住当前显示 的下标,注意顺序
        mCurrentDelegate = tag;
    }
}


这里有两个布局,一个是整个界面的布局,还有一个是 tab的子布局


delegate_bottom.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v7.widget.ContentFrameLayout
        android:id="@+id/bottom_bar_delegate_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/bottom_bar"/>
    <android.support.v7.widget.LinearLayoutCompat
        android:id="@+id/bottom_bar"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"/>
</RelativeLayout>


bottom_item_icon_text_layout.xml


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_weight="1"
    android:paddingBottom="6dp"
    android:paddingTop="6dp"
    android:layout_height="match_parent">
    <com.joanzapata.iconify.widget.IconTextView
        android:id="@+id/item_bottom_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignParentTop="true"
        android:textSize="25sp"
        android:gravity="center"/>
    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/tv_bottom_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"/>
</RelativeLayout>


6,要显示的 fragment,这里就是用户可以看见的界面了,这些会和对应的tab 一起存进map中,然后被 上面的类进行管理


public class IndexDelegate extends BottomItemDelegate {
    @Override
    public Object setLayout() {
        return R.layout.delegate_index;
    }
    @Override
    public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
    }
}


public class SortDelegate extends BottomItemDelegate {
    @Override
    public Object setLayout() {
        return R.layout.delegate_sort;
    }
    @Override
    public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
    }


这里只加了 两个碎片,有需要的可以多加。


对应布局如下


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <android.support.v7.widget.AppCompatTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="首页"/>
</LinearLayout>


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <android.support.v7.widget.AppCompatTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="分类" />
</LinearLayout>


7,继承自抽象BaseBottomDelegate ,在这个类中 我们可以创建多个 键值对,这些会返回到 上面的第5点的那个类中,进行处理并进行显示。


/**
 * Copyright (C)
 *
 * @file: EcBottomDelegate
 * @author: 345
 * @Time: 2019/4/26 14:26
 * @description: ${DESCRIPTION}
 */
public class EcBottomDelegate extends BaseBottomDelegate {
    @Override
    public LinkedHashMap<BottomTabBean, BottomItemDelegate> setItems(ItemBuilder builder) {
        final LinkedHashMap<BottomTabBean, BottomItemDelegate> items = new LinkedHashMap<>();
        items.put(new BottomTabBean("{fa-home}","主页"),new IndexDelegate());
        items.put(new BottomTabBean("{fa-sort}","分类"),new SortDelegate());
        items.put(new BottomTabBean("{fa-compass}","发现"),new IndexDelegate());
        items.put(new BottomTabBean("{fa-shopping-cart}","购物车"),new IndexDelegate());
        items.put(new BottomTabBean("{fa-user}","我的"),new IndexDelegate());
        return builder.addItem(items).build();
    }
    @Override
    public int setIndexDelegate() {
        return 0;
    }
    @Override
    public int setClickedColor() {
        return Color.parseColor("#ffff8800");
    }
}


在这个类里面可以对全局的 碎片进行管理。如果导航栏要增加一个 tab ,只需要创建一个字体的bean类,和一个碎片类存入map里面可以显示了。


经过上面的这几个步骤,这个通用的 导航栏+fragment 就弄好了。如果以后我们有任何更改的话,就可以在 BaseBottomDelegate类里面进行更改。如果要添加tab 直接new 字体的bean 在创建一个 fragment就好。如果每个每个碎片中有相同的功能,还可以在页面的基类BottomItemDelegate 中进行更改。目前这个类中只加了 双击退出的功能


效果如下所示


2d65d23f6d4748949b924e4057485923.png

4cebaac233b3433da32a72337a77fc60.png

6de278e6d6694ce5bb08e7e842b7e74b.png

相关文章
|
3月前
|
Android开发 Python
Python封装ADB获取Android设备wifi地址的方法
Python封装ADB获取Android设备wifi地址的方法
59 0
|
6月前
|
XML Android开发 数据格式
Android -- Fragment动态注册
Android -- Fragment动态注册
31 0
|
6月前
|
Android开发
Android Http 请求封装及使用
Android Http 请求封装及使用
123 0
|
6月前
|
Java Android开发 开发者
1024程序节|Android框架之一 BRVAH【BaseRecyclerViewAdapterHelper】使用demo
BRVAH是一个强大的RecyclerAdapter框架(什么是RecyclerView?),它能节约开发者大量的开发时间,集成了大部分列表常用需求解决方案。为什么会有它?请查看「Android开源框架BRVAH由来篇」该框架于2016年4月10号发布的第1个版本到现在已经一年多了,经历了800多次代码提交,140多次版本打包,修复了1000多个问题,获得了9000多star,非常感谢大家的使用以及反馈。
136 0
|
3月前
|
Android开发
Android基础知识:什么是Fragment?与Activity的区别是什么?
Android基础知识:什么是Fragment?与Activity的区别是什么?
265 54
|
4月前
|
缓存 JSON Android开发
[Android]网络框架之OkHttp(详细)(kotlin)
[Android]网络框架之OkHttp(详细)(kotlin)
128 0
|
4月前
|
Android开发 Kotlin
android开发,使用kotlin学习Fragment
android开发,使用kotlin学习Fragment
46 0
|
4月前
|
XML Java Android开发
Android Studio App开发之利用图片加载框架Glide实现刷新验证码功能(附源码 简单易懂)
Android Studio App开发之利用图片加载框架Glide实现刷新验证码功能(附源码 简单易懂)
33 0
|
4月前
|
XML Java Android开发
Android Studio App开发中工具栏Toolbar、溢出菜单OverflowMenu、标签布局TabLayout的讲解及实战(实现京东App的标签导航栏,附源码)
Android Studio App开发中工具栏Toolbar、溢出菜单OverflowMenu、标签布局TabLayout的讲解及实战(实现京东App的标签导航栏,附源码)
55 0
|
4月前
|
XML Java Android开发
Android Studio App开发之碎片Fragment的讲解及实战(附源码 包括静态和动态注册)
Android Studio App开发之碎片Fragment的讲解及实战(附源码 包括静态和动态注册)
36 1