需求:
管理后臺可以自由設(shè)置圖片,通過服務(wù)器返回給客戶端,客戶端根據(jù)管理后臺設(shè)置的內(nèi)容,去展示各個位置的圖或圖標(例如很多常用的app,有沒有觀察到有時候底部圖標會不一樣啊,不知道別人怎么實現(xiàn)的,但是我們的客戶要求就是需要可以動態(tài)設(shè)置這樣會比較靈活不用每次都找技術(shù)去換)
要達到的效果

美團app的bottomBar.png
上圖是我截圖美團的bottomBar,要達到的效果就是這些圖標他們自己可以換,我們只需要加載圖標url就可以了
碎碎念:其實這種需求就自己寫就可以了,干嘛還要用第三方的依賴,還要拿別人源碼然后再改多麻煩?因為當初項目開始的時候沒有這個需求啊,用本地資源的話這個FlycoTabLayout蜜汁方便??蛻簦阂銈冏屇銈儗懯娣?,就算我輸
相關(guān)代碼:
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;
//直接用本地資源時候用的構(gòu)造方法
public ImageTabEntity(String title, int selectedIcon, int unSelectedIcon) {
this.title = title;
this.selectedIcon = selectedIcon;
this.unSelectedIcon = unSelectedIcon;
}
//用url時的構(gòu)造方法,這兩個構(gòu)造方法里的第一個參數(shù)就是選項的字,第二個參數(shù)是選項被選中時的圖,第三個參數(shù)是選項未被選中時的圖
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中的使用(只記錄一下關(guān)鍵代碼):
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<>();
//登錄獲取服務(wù)器返回的服務(wù)器圖標url數(shù)組如果不為空就加載圖標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);
}
//將數(shù)據(jù)設(shè)置到這個bottomBar中
bottomBar.setTabData(tabs);
bottomBar.setOnTabSelectListener(new OnTabSelectListener() {
@Override
public void onTabSelect(int position) {
//這個方法是選中了哪個圖標的監(jiān)聽,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方法 設(shè)置數(shù)據(jù),在這個方法里就要用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加載的緩存數(shù)組有沒有
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();
}
//更新數(shù)據(jù)的方法
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{
//如果執(zhí)行到這一步的時候圖片還未加載完成,就先設(shè)置未加載本地資源的圖標
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的布局參數(shù) */
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風(fēng)格
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);
}
}
}
實現(xiàn)思路:
- 本身項目都是需要加載url展示圖片的,鬼知道客戶會不會要加載gif圖什么的,所以用了glide,那么剛好用glide加載圖標吧(glide看這里)
- FlycoTabLayout:因為要用glide所以要把庫下下來引入,在庫的build文件里引入glide
- 在自定義圖標對象繼承 CustomEntity時候,加自定義的參數(shù),是自己需要的url,String類型就行了
- 然后第一次將數(shù)據(jù)設(shè)置到tabLayout的時候,在setData的方法里就要判斷是否需要加載url,如果是的話,就用glide在這個方法里加載,循環(huán)加載,每循環(huán)一次將緩存下來的bitmap存入list中(總共bottom中也用不了幾個圖標,所以循環(huán)也不會耗時,并且glide load的時候應(yīng)該也是異步的)
- 每次不管點擊也好,還是別的操作觸發(fā)tabLayout的更新方法,在這個更新方法里設(shè)置setImageBitmap即可
以上是關(guān)于這個需求的筆記,最重要的是項目開始時候一定要做好未來擴展的準備,不要像這次突然提一個需求,只能現(xiàn)想辦法改!