• 扩展第三方DropDownMenu


    找工作之际,静下心总结工作中的想法。

    我的简书

    原来的效果

    Paste_Image.png

    Paste_Image.png

    #解析结构

    • 导读
      想要扩展首先我需要执行下面几个步骤

    1.fork DropDownMenu到自己的github账号
    2.使用as的vcs checkout出来
    3.提交到github
    4.发起pull request(还没发)

    • 源码实现原理
      作者对该控件的分析 导读

    1240 0.00KB

    这是我对该DropDownMenu的组成结构进行的图解

    DropDownMenu:下拉菜单控件 继承自LinearLayout
    tabMenuView:顶部菜单布局 继承自LinearLayout
    containerView:底部容器,包含popupMenuViews,maskView 继承自FrameLayout
    popupMenuViews:弹出菜单父布局 继承自FrameLayout
    maskView:遮罩半透明View,点击可关闭DropDownMenu 继承自View
    contentView:一个页面除了顶部菜单栏以外的所有内容
    tabView : ListView → 1 : 1

    调用方法基本解析

    DropDownMenu:对tabMenuView、containerView进行初始化
    setDropDownMenu:传参为tabTexts(字符串数组),popupViews(ListView数组),contentView(内容View)。调用addtab方法向tabMenuView添加tabView并设置对应tabView点击切换显示ListView
    addTab:循环tabTexts文本,TextView赋值添加到tabMenuView
    switchMenu:切换tab调用对应的popupMenuViews里面的ListView显示,其他的ListView隐藏

    一般情况下在我们的UI图不是对tab特别要求的话,那么这种已经符合要求了。但是奈不住它就是不长这样啊。

    • tabView样式扩展
      有时候UI图就是这么可恶,^这个箭头不是靠右,空的那么开。当然我这里只是举一个例子。

    1240 0.00KB

    • tabView功能扩展
      这个需求更加丧心病狂了,tab不都是下拉框。实现扩展之后可以在tabMenu中任意顺序插入自定义的tabView,且不影响下拉功能。

    1240 0.00KB

    #代码实现细则

    tabView样式扩展源码实现

    这里我们说这个dropDownMenu的tab为TextView肯定无法达到我们想要的效果了。
    那么最差将tab换成LinearLayout,那么自定义效果就随你自己了。但是我们就这样实现的话肯定性能跟原来有些差距。那么这个库tab都默认是viewGroup多渲染了一层,我们能不能在用的时候,自己定义的tab_item.xml。xml中我们想要viewGroup就写ViewGroup包裹,想只要TextView就只有TextView。
    其实我们只需要定义id约束,xml中TextView必须指定为(例如)R.id.tv_tab。DropDownMenu底层在设置tab的内容的时候多一步操作,加载指定的tab_laytou.xml,然后如果是ViewGroup就findViewById找到TextView,否则就直接转成TextView。
    

    1.addTab()方法从代码中直接new TextView改成从layout中加载
    2.将原来tabView(textView)相关的设置代码全部先用获取textView的过滤方法筛选一下textView

    这里只截取关键代码
    原addTab()

        private void addTab(@NonNull List<String> tabTexts, int i) {
            final TextView tab = new TextView(getContext());
            ...//tab的样式设置
            tab.setText(tabTexts.get(i));
            tab.setPadding(dpTpPx(5), dpTpPx(12), dpTpPx(5), dpTpPx(12));
            //添加点击事件
            ...
            tabMenuView.addView(tab);
            //添加分割线
            ...
        }
    

    改addTab()

        private void addTab(@NonNull List<String> tabTexts, int i) {
            View tab = inflate(getContext(), R.layout.tab_item, null);
            tab.setLayoutParams(new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));
            ...//样式设置
            tabMenuView.addView(tab);
            //添加分割线
            ...
        }
    

    增加tab_item.xml(viewGroup包含textView / 只是textView) ,样式的可扩展性大大增强

    <!-----------ViewGroup------------------>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center">
    
        <TextView
            android:id="@+id/tv_tab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:drawablePadding="7dp"
            android:gravity="center"
            android:paddingBottom="12dp"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            android:paddingTop="12dp"
            android:text="adfad"
            android:textColor="#26a8e0" />
    </LinearLayout>
    <!-------或者只有TextView,也没有问题---------------------->
    <?xml version="1.0" encoding="utf-8"?>
    <TextView android:id="@+id/tv_tab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:drawablePadding="7dp"
        android:gravity="center"
        android:paddingBottom="12dp"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:paddingTop="12dp"
        android:textColor="#26a8e0"
        xmlns:android="http://schemas.android.com/apk/res/android" />
    

    过滤获取TextView方法

        /**
         * 获取tabView中id为tv_tab的textView
         *
         * @param tabView
         * @return
         */
        private TextView getTabTextView(View tabView) {
            TextView tabtext = (TextView) tabView.findViewById(R.id.tv_tab);
            return tabtext;
        }
    

    hint: 然后代码中凡是涉及到设置tab textView相关设置的地方都需要先用我这个方法过滤,替换一下。主要有这么几个地方,初始化设置tab,选中List单项确定设置tab,打开和关闭菜单对tab的文本颜色的设置。
    效果:就是最上面扩展的效果图

    tabView功能扩展源码实现

    从上面可以知道,现在tabMenuView的tab和popupMenuViews的ListView的数量是相同的。而现在我们要实现的是 tabMenuView中tab的数量>popupMenuViews的ListView的数量。多的那部分tabView就只是展示的功能,不会触发点击下拉展示。
    另外因为tabtexts文本是作为数组顺序添加的。所以我们需要用dropTabViews类记录tabtexts添加的顺序。当点击了一个tabView看是否存在于dropTabViews数组中,不存在就不处理,存在就indexOf获取当前tabView在dropTabViews中的顺序然后去对应找ListView。这样处理之后,tabMenuView设置tabtexts之后就可以随便在哪个位置上插入需要的tabView样式了,且不影响功能。
    

    1.创建记录tabtexts顺序的而创建的tabView数组
    2.在switchMenu切换popupMenuViews的ListView的获取方式要过滤一下

    旧switchMenu方法

       private void switchMenu(View target) {
            System.out.println(current_tab_position);
            for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {
                if (target == tabMenuView.getChildAt(i)) {//找到点击到的tabView
                    if (current_tab_position == i) {//点击的view是原来显示的tabView则关闭菜单
                        closeMenu();
                    } else {//不是,就显示菜单
                        if (current_tab_position == -1) {
                            ...
                            popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);
                        } else {
                            popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);
                        }
                        ...
                    }
                } else {//没找到就颜色等属性设置成普通
                    TextView textView = getTabTextView(tabMenuView.getChildAt(i));
                    textView.setTextColor(textUnselectedColor);
                    textView.setCompoundDrawablesWithIntrinsicBounds(null, null,
                            getResources().getDrawable(menuUnselectedIcon), null);
                    popupMenuViews.getChildAt(i / 2).setVisibility(View.GONE);
                }
            }
        }
    

    修改的switchMenu方法

     private void switchMenu(View target) {
            for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {
                if (target == tabMenuView.getChildAt(i)) {//找到点击到的tabView
                    if (current_tab_position == i) {//点击的view是原来显示的tabView则关闭菜单
                        closeMenu();
                    } else {//不是,就显示菜单
                        ...
                        View listView = getListView(tabMenuView.getChildAt(i));
                        if (listView != null) {
                            listView.setVisibility(View.VISIBLE);
                        }
                        ...
                    }
                } else {//没找到就颜色等属性设置成普通
                    TextView textView = getTabTextView(tabMenuView.getChildAt(i));
                    View listView = getListView(tabMenuView.getChildAt(i));
                    if (listView != null) {
                        if(textView!=null){
                            textView.setCompoundDrawablesWithIntrinsicBounds(null, null,
                                    getResources().getDrawable(menuUnselectedIcon), null);
                        }
                        listView.setVisibility(View.GONE);
                    }
                }
            }
        }
    

    addTab进一步修改

        private void addTab(@NonNull List<String> tabTexts, int i) {
           ...
            dropTabViews.add(tab);//记录创建的添加顺序
        }
    

    新增getListView方法

        /**
         * 获取dropTabViews中对应popupMenuViews数组中的ListView
         *
         * @param view
         * @return
         */
        private View getListView(View view) {
            if (dropTabViews.contains(view)) {
                int index = dropTabViews.indexOf(view);
                return popupMenuViews.getChildAt(index);
            } else {
                return null;
            }
        }
    

    调用演示MainActivity.java

          mDropDownMenu.setDropDownMenu(Arrays.asList(headers), popupViews, contentView);
            //测试tabView扩展功能
            TextView textView= (TextView) getLayoutInflater().inflate(R.layout.tab_text,null);
            textView.setLayoutParams(new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));
            textView.setText("2位置");
            mDropDownMenu.addTab(textView,2);
    

    1240 0.00KB

    总结

    样式性扩展:我们尽量从xml中加载view,根据指定id获取控件,到达最大程度的样式解耦
    功能性扩展:将tabViews数组顺序的位置不依赖于父View的child,而是依赖于一个动态的数组。我们对父View的child的添加并不会影响到原来的功能。这样可以做到tabView的功能性扩展

    该篇文章代码在 Github上

  • 相关阅读:
    如何理解cat的输入输出重定向
    Vagrant网络设置
    Vagrant入门
    设计模式的原则
    单例模式
    LRU 实现缓存
    java注解
    java8---lambda表达式
    JUC--Callable 以及Lock同步锁
    JUC--闭锁 CountDownLatch
  • 原文地址:https://www.cnblogs.com/woshijishu3/p/5964634.html
Copyright © 2020-2023  润新知