扩展第三方DropDownMenu

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

我的简书

原来的效果

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上

时间: 2024-08-28 23:43:55

扩展第三方DropDownMenu的相关文章

YII 1.0 扩展第三方类

扩展缩略图类在extensions 中建立 Image/CThumb.php 1. 自己瞎弄的,一点都不优雅 include_once Yii::app()->BasePath."/extensions/Image/CThumb.php";$aaa = new CThumb(); .... 2. Yii::import("ext.Image.CThumb");$aaa = new CThumb('uploads'); //初始化 3. 在config /mai

JEPLUS快速开发平台怎么支持扩展第三方供应商短信发送

一.效果展示 可以不限制与平台集成的网建提供商,可以自己写发送短信实现,平台会提供一个扩展类的实现. 二.准备工作 JEPLUS平台版本:5.0.0.1 Eclipse版本:4.3以上 Intellij IDEA : 2015以上,推荐使用IDEA2017版本以上(功能更强大,UI更美观,支持各种插件,还在等什么?) Resin : 3.0以上 Tomcat:6.0以上 JDK:1.7以上 ApacheServer:2.0以上 三.技术要求 Java水平:最好具备初级及以上水平 短信接口:了解短

快速开发平台怎么支持扩展第三方供应商短信发送—JEPLUS快速开发平台

一.效果展示 可以不限制与平台集成的网建提供商,可以自己写发送短信实现,平台会提供一个扩展类的实现. 二.准备工作 JEPLUS平台版本:5.0.0.1 Eclipse版本:4.3以上 Intellij IDEA : 2015以上,推荐使用IDEA2017版本以上(功能更强大,UI更美观,支持各种插件,还在等什么?) Resin : 3.0以上 Tomcat:6.0以上 JDK:1.7以上 ApacheServer:2.0以上 三.技术要求 Java水平:最好具备初级及以上水平 短信接口:了解短

[ffmpeg 扩展第三方库编译系列] 关于libvpx mingw32编译问题

在编译libvpx的时候遇到挺多的问题, 1.[STRIP] libvpx.a < libvpx_g.a strip: Bad file number 这个错误也是比较难搞的,一开始以为只是strip没有找到造成的,但是后来尝试修改strip路径也无法解决. 这个错误需要修改Makefile代码, %.a: %_g.a $(if $(quiet),@echo " [STRIP] [email protected] < $<") # $(qexec)$(STRIP) -

[ffmpeg 扩展第三方库编译系列] 关于 mingw32 下编译libcaca

在编译前最好先看一下帮助 ./configure --help 開始编译 ./configure  --disable-shared --disable-cxx \ --disable-csharp --disable-java --disable-python --disable-ruby \ --disable-imlib2 --disable-doc  \ --enable-win32 \ --build=mingw32 联系方式:[email protected] QQ:51454000

[ffmpeg 扩展第三方库编译系列] frei0r mingw32 下编译问题

在编译安装frei0r的时候遇到两个错误地方, 两个都是在install的时候. 一開始编译都非常顺利,输入了 make install之后就走开了,回来一看,报错误. 提示mkdir -p //usr/local/lib/frei0r-1错误,让我百思不得其解,一開始以为我手动创建就能够,于是到相关文件夹下创建了该文件夹. 再次install的时候还是不行. 于是我就想着去找百度,谷歌.最终有解决的方法 是一下src/Makefile下的$(DESTDIR)/$(plugindir)多了一个/

[ffmpeg 扩展第三方库编译系列] 关于libopenjpeg mingw32编译问题

在mingw32假设想编译libopenjpeg 会比較麻烦 会出现undefined reference to `[email protected]' 等错误 因此编译时候须要make CFLAGS="-DWIN32 -DOPJ_STATIC $CFLAGS" 就可以

iOS8中添加的extensions总结(一)——今日扩展

通知栏中的今日扩展 分享扩展 Action扩展 图片编辑扩展 文件管理扩展 第三方键盘扩展 注:此教程来源于http://www.raywenderlich.com的<iOS8 by Tutorials> 关于App extensions 的原理,即How extensions work 首先App扩展是一个App功能性上的扩展,它并不独立与你原来的App,也就是说在给App Store提交的时候是打包到原有App中一起提交,它们并不是独立的App.其次,App的每一种扩展都有自己单独的API

编写高质量代码改善C#程序的157个建议——建议101:使用扩展方法,向现有类型“添加”方法

建议101:使用扩展方法,向现有类型“添加”方法 考虑如何让一个sealed类型具备新的行为.以往我们会创建一个包装器类,然后为其添加方法,而这看上去一点儿也不优雅.我们也许会考虑修改设计,直接修改sealed类型,然后为其发布一个新的版本,但这依赖于你拥有全部的源码.更多的时候,我们会采取针对第三方公司提供的API进行编程的方式.对于我们来说,FCL是一组第三方公司(微软)提供给我们的最好的API. 包装类的编码形式如下: class Program { static void Main(st