笔记20170429--用FlycoTabLayout+Glide实现动态加载底部TAB图标(Android)

需求:

管理后台可以自由设置图片,通过服务器返回给客户端,客户端根据管理后台设置的内容,去展示各个位置的图或图标(例如很多常用的app,有没有观察到有时候底部图标会不一样啊,不知道别人怎么实现的,但是我们的客户要求就是需要可以动态设置这样会比较灵活不用每次都找技术去换)

要达到的效果

美团app的bottomBar.png

上图是我截图美团的bottomBar,要达到的效果就是这些图标他们自己可以换,我们只需要加载图标url就可以了
碎碎念:其实这种需求就自己写就可以了,干嘛还要用第三方的依赖,还要拿别人源码然后再改多麻烦?因为当初项目开始的时候没有这个需求啊,用本地资源的话这个FlycoTabLayout蜜汁方便。客户:要你们让你们写舒服,就算我输

相关代码:

xml--用到FlycoTabLayout的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clickable="true">

    <FrameLayout
        android:id="@+id/fragmentContent"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/bottomLayout" />


    <LinearLayout
        android:id="@+id/bottomLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@android:color/white"
        android:orientation="vertical">

        <View
            android:layout_width="match_parent"
            android:layout_height="1px"
            android:background="?android:listDivider" />

        <com.flyco.tablayout.CommonTabLayout
            android:id="@+id/bottomBar"
            android:layout_width="match_parent"
            android:layout_height="49dp"
            android:layout_marginTop="2dp"
            android:background="#ffffff"
            app:tl_iconHeight="23dp"
            app:tl_iconWidth="25dp"
            app:tl_indicator_color="#ffcc02"
            app:tl_indicator_height="0dp"
            app:tl_textSelectColor="#ffcc02"
            app:tl_textUnselectColor="#666666"
            app:tl_textsize="10sp"
            app:tl_underline_color="#DDDDDD"
            app:tl_underline_height="1dp" />


    </LinearLayout>
</RelativeLayout>

代码:存每个图标和文字的对象
package com.xxx.xxx.xxx.bean;

import com.flyco.tablayout.listener.CustomTabEntity;

/**
 * Created by Hello我的World on 2017/3/12.
 */

public class ImageTabEntity implements CustomTabEntity {
    public String title;
    public int selectedIcon;
    public int unSelectedIcon;
    public String selectedIconStr;
    public String unSelectedIconStr;
    //直接用本地资源时候用的构造方法
    public ImageTabEntity(String title, int selectedIcon, int unSelectedIcon) {
        this.title = title;
        this.selectedIcon = selectedIcon;
        this.unSelectedIcon = unSelectedIcon;
    }
    //用url时的构造方法,这两个构造方法里的第一个参数就是选项的字,第二个参数是选项被选中时的图,第三个参数是选项未被选中时的图
    public ImageTabEntity(String title,String selectedIconStr,String unSelectedIconStr){
        this.title = title;
        this.selectedIconStr = selectedIconStr;
        this.unSelectedIconStr = unSelectedIconStr;
    }

    @Override
    public String getTabTitle() {
        return title;
    }

    @Override
    public int getTabSelectedIcon() {
        return selectedIcon;
    }

    @Override
    public int getTabUnselectedIcon() {
        return unSelectedIcon;
    }

    @Override
    public String getTabSelectedIconByString() {
        return selectedIconStr;
    }

    @Override
    public String getTabUnSelectedIconByString() {
        return unSelectedIconStr;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setSelectedIcon(int selectedIcon) {
        this.selectedIcon = selectedIcon;
    }

    public void setUnSelectedIcon(int unSelectedIcon) {
        this.unSelectedIcon = unSelectedIcon;
    }

    public void setSelectedIconStr(String selectedIconStr) {
        this.selectedIconStr = selectedIconStr;
    }

    public void setUnSelectedIconStr(String unSelectedIconStr) {
        this.unSelectedIconStr = unSelectedIconStr;
    }
}

Activity中的使用(只记录一下关键代码):
public class MainActivity extends BaseActivity {
    @BindView(R.id.fragmentContent)
    FrameLayout fragmentContent;
    @BindView(R.id.bottomBar)
    CommonTabLayout bottomBar;

 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        manager = getSupportFragmentManager();
        currentTabIndex = 0;
        if (savedInstanceState != null) {
            currentTabIndex = savedInstanceState.getInt("CurrentIndex", 0);
        }
        setCurrentTab(currentTabIndex, manager);
        ImageTabEntity imageTabEntity1;
        ImageTabEntity imageTabEntity2;
        ImageTabEntity imageTabEntity3;
        ArrayList<CustomTabEntity> tabs = new ArrayList<>();
        //登录获取服务器返回的服务器图标url数组如果不为空就加载图标url和本地资源,如果为空就只加载本地资源
                if (pref.getBottomIcons() != null) {
                    imageTabEntity1 = new ImageTabEntity(getString(R.string.work),pref.getBottomIcons().getIcons().get(1).getUrl(),pref.getBottomIcons().getIcons().get(0).getUrl());
                    imageTabEntity1.setSelectedIcon( R.drawable.bottom_lh_hover_icon);
                    imageTabEntity1.setUnSelectedIcon(R.drawable.bottom_lh_icon);
                    imageTabEntity2 = new ImageTabEntity(getString(R.string.order),pref.getBottomIcons().getIcons().get(3).getUrl(),pref.getBottomIcons().getIcons().get(2).getUrl());
                    imageTabEntity2.setSelectedIcon(R.drawable.bottom_order_hover_icon);
                    imageTabEntity2.setUnSelectedIcon(R.drawable.bottom_order_icon);
                    imageTabEntity3 = new ImageTabEntity(getString(R.string.mine),pref.getBottomIcons().getIcons().get(5).getUrl(),pref.getBottomIcons().getIcons().get(4).getUrl());
                    imageTabEntity3.setSelectedIcon(R.drawable.bottom_my_hover_icon);
                    imageTabEntity3.setUnSelectedIcon(R.drawable.bottom_icon);
                    tabs.add(imageTabEntity1);
                    tabs.add(imageTabEntity2);
                    tabs.add(imageTabEntity3);
                } else {
                    imageTabEntity1 = new ImageTabEntity(getString(R.string.work), R.drawable.bottom_lh_hover_icon, R.drawable.bottom_lh_icon);
                    imageTabEntity2 = new ImageTabEntity(getString(R.string.order), R.drawable.bottom_order_hover_icon, R.drawable.bottom_order_icon);
                    imageTabEntity3 = new ImageTabEntity(getString(R.string.mine), R.drawable.bottom_my_hover_icon, R.drawable.bottom_icon);
                    tabs.add(imageTabEntity1);
                    tabs.add(imageTabEntity2);
                    tabs.add(imageTabEntity3);
                }
        //将数据设置到这个bottomBar中
        bottomBar.setTabData(tabs);
        bottomBar.setOnTabSelectListener(new OnTabSelectListener() {
            @Override
            public void onTabSelect(int position) {
                //这个方法是选中了哪个图标的监听,position是选中的位置
                setCurrentTab(position, manager);
            }

            @Override
            public void onTabReselect(int position) {

            }
        });
}
CommonTabLayout源码中要改的方法(代码片段):
//首先要在FlycoTabLayout库的build文件中,添加最新的glide依赖
//我当时加的时候还是最新的  compile 'com.github.bumptech.glide:glide:3.7.0'
//在这个控件的类中声明两个变量两个常量
private RequestManager glide;//glide
private List<HashMap> bitmapResource ;//glide加载了图片后的缓存bitmap集合,选中和非选中的两个图为1个map
private final String TAB_SELECTED="tabSelected";//和下边这个变量是用到的hashmap的key
private final String TAB_UNSELECTED="tabUnselected";

//setDate方法 设置数据,在这个方法里就要用glide把图片都加载一边并存好缓存的bitmap
public void setTabData(ArrayList<CustomTabEntity> tabEntities) {
        if (tabEntities == null || tabEntities.size() == 0) {
            throw new IllegalStateException("TabEntitys can not be NULL or EMPTY !");
        }
        this.mTabEntitys.clear();
        this.mTabEntitys.addAll(tabEntities);
        //先判断glide加载的缓存数组有没有
        if(bitmapResource==null||bitmapResource.size()==0){
            bitmapResource = new ArrayList<>();
        }else{
            bitmapResource.clear();
        }
        //遍历传来的tab对象
        for(final CustomTabEntity tabEntity:tabEntities){
            //如果图标url不是空的,就用glide加载选中的和未选中的图片,缓存下来的bitmap存进map中,然后将map放入list里
            if(!TextUtils.isEmpty(tabEntity.getTabSelectedIconByString())||!TextUtils.isEmpty(tabEntity.getTabUnSelectedIconByString())){
                final HashMap<String,Bitmap> hashMap = new HashMap<>();
                glide.load(tabEntity.getTabUnSelectedIconByString()).asBitmap().into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
                        hashMap.put(TAB_UNSELECTED,resource);
                    }
                });
                glide.load(tabEntity.getTabSelectedIconByString()).asBitmap().into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
                        hashMap.put(TAB_SELECTED,resource);
                    }
                });
                bitmapResource.add(hashMap);
            }
        }
        notifyDataSetChanged();
    }

//更新数据的方法
public void notifyDataSetChanged() {
        mTabsContainer.removeAllViews();
        this.mTabCount = mTabEntitys.size();
        View tabView;
        for (int i = 0; i < mTabCount; i++) {
            if (mIconGravity == Gravity.LEFT) {
                tabView = View.inflate(mContext, R.layout.layout_tab_left, null);
            } else if (mIconGravity == Gravity.RIGHT) {
                tabView = View.inflate(mContext, R.layout.layout_tab_right, null);
            } else if (mIconGravity == Gravity.BOTTOM) {
                tabView = View.inflate(mContext, R.layout.layout_tab_bottom, null);
            } else {
                tabView = View.inflate(mContext, R.layout.layout_tab_top, null);
            }
            tabView.setTag(i);
            addTab(i, tabView);
        }
        updateTabStyles();
    }

//添加tab
private void addTab(final int position, View tabView) {
        TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
        tv_tab_title.setText(mTabEntitys.get(position).getTabTitle());
        final ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon);
        int resourceImg = mTabEntitys.get(position).getTabUnselectedIcon();
      //还是先判断是加载本地资源还是加载url 
      if(TextUtils.isEmpty(mTabEntitys.get(position).getTabSelectedIconByString())||TextUtils.isEmpty(mTabEntitys.get(position).getTabUnSelectedIconByString())){
            iv_tab_icon.setImageResource(resourceImg);
        }else{
            //如果执行到这一步的时候图片还未加载完成,就先设置未加载本地资源的图标
            Bitmap bitmap = (Bitmap) bitmapResource.get(position).get(TAB_UNSELECTED);
            if(bitmap!=null){
                iv_tab_icon.setImageBitmap(bitmap);
            }else{
                iv_tab_icon.setImageResource(resourceImg);
            }
        }
        tabView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = (Integer) v.getTag();
                if (mCurrentTab != position) {
                    setCurrentTab(position);
                    if (mListener != null) {
                        mListener.onTabSelect(position);
                    }
                } else {
                    if (mListener != null) {
                        mListener.onTabReselect(position);
                    }
                }
            }
        });

        /** 每一个Tab的布局参数 */
        LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ?
                new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) :
                new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
        if (mTabWidth > 0) {
            lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT);
        }
        mTabsContainer.addView(tabView, position, lp_tab);
    }
//更新tab风格
 private void updateTabStyles() {
        for (int i = 0; i < mTabCount; i++) {
            View tabView = mTabsContainer.getChildAt(i);
            tabView.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0);
            TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
            tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor);
            tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize);
//            tv_tab_title.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0);
            if (mTextAllCaps) {
                tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase());
            }

            if (mTextBold == TEXT_BOLD_BOTH) {
                tv_tab_title.getPaint().setFakeBoldText(true);
            } else if (mTextBold == TEXT_BOLD_NONE) {
                tv_tab_title.getPaint().setFakeBoldText(false);
            }

            final ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon);
            if (mIconVisible) {
                iv_tab_icon.setVisibility(View.VISIBLE);
                CustomTabEntity tabEntity = mTabEntitys.get(i);
            //跟上边的方法一样都是如果不是bitmap不为空就加载bitmap如果为空就加载本地资源    
            if(TextUtils.isEmpty(tabEntity.getTabSelectedIconByString())||TextUtils.isEmpty(tabEntity.getTabUnSelectedIconByString())){
                    iv_tab_icon.setImageResource(i == mCurrentTab ? tabEntity.getTabSelectedIcon() : tabEntity.getTabUnselectedIcon());
                }else{
                    Bitmap sBitmap,uBitmap;
                    sBitmap = (Bitmap) bitmapResource.get(i).get(TAB_SELECTED);
                    uBitmap = (Bitmap) bitmapResource.get(i).get(TAB_UNSELECTED);
                    if(sBitmap!=null&&uBitmap!=null){
                        iv_tab_icon.setImageBitmap(i==mCurrentTab?sBitmap:uBitmap);
                    }else{
                        iv_tab_icon.setImageResource(i==mCurrentTab?tabEntity.getTabSelectedIcon():tabEntity.getTabUnselectedIcon());
                    }

                }
                LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                        mIconWidth <= 0 ? LinearLayout.LayoutParams.WRAP_CONTENT : (int) mIconWidth,
                        mIconHeight <= 0 ? LinearLayout.LayoutParams.WRAP_CONTENT : (int) mIconHeight);
                if (mIconGravity == Gravity.LEFT) {
                    lp.rightMargin = (int) mIconMargin;
                } else if (mIconGravity == Gravity.RIGHT) {
                    lp.leftMargin = (int) mIconMargin;
                } else if (mIconGravity == Gravity.BOTTOM) {
                    lp.topMargin = (int) mIconMargin;
                } else {
                    lp.bottomMargin = (int) mIconMargin;
                }

                iv_tab_icon.setLayoutParams(lp);
            } else {
                iv_tab_icon.setVisibility(View.GONE);
            }
        }
    }

实现思路:

  • 本身项目都是需要加载url展示图片的,鬼知道客户会不会要加载gif图什么的,所以用了glide,那么刚好用glide加载图标吧(glide看这里
  • FlycoTabLayout:因为要用glide所以要把库下下来引入,在库的build文件里引入glide
  • 在自定义图标对象继承 CustomEntity时候,加自定义的参数,是自己需要的url,String类型就行了
  • 然后第一次将数据设置到tabLayout的时候,在setData的方法里就要判断是否需要加载url,如果是的话,就用glide在这个方法里加载,循环加载,每循环一次将缓存下来的bitmap存入list中(总共bottom中也用不了几个图标,所以循环也不会耗时,并且glide load的时候应该也是异步的)
  • 每次不管点击也好,还是别的操作触发tabLayout的更新方法,在这个更新方法里设置setImageBitmap即可

以上是关于这个需求的笔记,最重要的是项目开始时候一定要做好未来扩展的准备,不要像这次突然提一个需求,只能现想办法改!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,870评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,638评论 18 139
  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 46,739评论 22 665
  • 一、简介 在泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫Glide的图片加载库,作者是bumptech。这...
    天天大保建阅读 7,461评论 2 28
  • 老子云:祸莫大于不知足,咎莫大于欲得,故知足之足长足矣。控制住自己的欲望,坚定自己的信心,不断完善自己,终会获得内...
    翠翠美阅读 249评论 0 1