需求:
管理后台可以自由设置图片,通过服务器返回给客户端,客户端根据管理后台设置的内容,去展示各个位置的图或图标(例如很多常用的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即可
以上是关于这个需求的笔记,最重要的是项目开始时候一定要做好未来扩展的准备,不要像这次突然提一个需求,只能现想办法改!
网友评论