Android電商專案學習筆記(二)--主介面完成
本專案來源於慕課網Android實戰課——Android通用框架設計與完整電商開發
前天跟隨視訊完成了對主介面的封裝及使用,這種模式使用的還不夠熟悉,需加強理解並練習。寫下這篇來加深理解。
先上效果圖:
哈哈,別想多,就是我們平常見的效果。底部一些Tab,上部是與之對應的Fragment。但是與以往不同的是,該介面本身還是一個Fragment,但都是一個原理(底部導航+Fragment)。
在專案中是進行抽取(主介面的基類,詳情頁的基類)。主介面分為兩個部分,上部詳情頁的容器,下部Tab導航欄,同時對Tab導航欄的點選事件進行處理。詳情頁的基類比較簡單,封裝了一些通用的功能:如雙擊返回鍵退出應用等。
首先上詳情頁的程式碼:
public abstract class ButtomItemdelegate extends MinDelegate implements View.OnKeyListener {
private long mExitTime = 0;
private static final int EXIT_TIME = 2000;
@Override
public void onResume() {
super.onResume();
View rootView = getView();
if (rootView != null ) {
rootView.setFocusableInTouchMode(true);
rootView.requestFocus();
rootView.setOnKeyListener(this);
}
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
if (System.currentTimeMillis() - mExitTime > EXIT_TIME) {
Toast.makeText(getContext(), "雙擊退出應用", Toast.LENGTH_SHORT).show();
mExitTime = System.currentTimeMillis();
} else {
_mActivity.finish();
if (mExitTime != 0) {
mExitTime = 0;
}
}
return true;
}
return false;
}
}
這裡程式碼來說相對簡單,就提取了一個功能,就是雙擊返回鍵退出應用。
監聽返回鍵的點選事件,判斷兩次點選的間隔時間,如果大於2s,就提示,小於2s直接退出。值得注意的是,在Fragment中,每次重新進入都要對View的焦點重新獲取,並重新註冊點選事件。程式碼如下:
rootView.setFocusableInTouchMode(true);
rootView.requestFocus();
rootView.setOnKeyListener(this);
接著是每個Tab的資訊,建一個類:
public class ButtomTabBean {
private final CharSequence ICON;
private final CharSequence TITLE;
public ButtomTabBean(CharSequence icon, CharSequence title) {
ICON = icon;
TITLE = title;
}
public CharSequence getIcon() {
return ICON;
}
public CharSequence getTitle() {
return TITLE;
}
}
ICON, TITLE,表示每個Tab有一個圖示,和個描述文字。
public class ItemBuilder {
private final LinkedHashMap<ButtomTabBean, ButtomItemdelegate> ITEMS = new LinkedHashMap<>();
static ItemBuilder builder() {
return new ItemBuilder();
}
public final ItemBuilder addItem(ButtomTabBean bean, ButtomItemdelegate itemdelegate) {
ITEMS.put(bean, itemdelegate);
return this;
}
public final ItemBuilder addItems(LinkedHashMap<ButtomTabBean, ButtomItemdelegate> items) {
ITEMS.putAll(items);
return this;
}
public final LinkedHashMap<ButtomTabBean, ButtomItemdelegate> build() {
return ITEMS;
}
}
ItemBuilder是將Tab與介面關聯起來。
然後就是主介面的基類,程式碼:
public abstract class BaseButtomDelegete extends MinDelegate implements View.OnClickListener {
//儲存Tab的內容
private final ArrayList<ButtomTabBean> TAB_BEANS = new ArrayList<>();
//儲存每個Tab所對應的Fragment
private final ArrayList<ButtomItemdelegate> TAB_DELEGATES = new ArrayList<>();
private final LinkedHashMap<ButtomTabBean, ButtomItemdelegate> ITEMS = new LinkedHashMap<>();
private int mCurrentItem = 0; //當前介面
private int mIndexItem = 0; //進入的第一個介面
private int mTabColor = Color.RED;
@BindView(R2.id.mBottomBar)
LinearLayoutCompat mBottomBar;
public abstract LinkedHashMap<ButtomTabBean, ButtomItemdelegate> setItems(ItemBuilder builder);
/**
* @return 進入應用顯示的介面
*/
public abstract int setIndexItem();
/**
* @return tab點選後的顏色
*/
@ColorInt
public abstract int setColor();
@Override
public Object setLayout() {
return R.layout.buttom_delegate_layout;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mIndexItem = setIndexItem();
if (setColor() != 0) {
mTabColor = setColor();
}
final ItemBuilder builder = new ItemBuilder();
final LinkedHashMap<ButtomTabBean, ButtomItemdelegate> maps = setItems(builder);
ITEMS.putAll(maps);
for (Map.Entry<ButtomTabBean, ButtomItemdelegate> item : ITEMS.entrySet()) {
final ButtomTabBean key = item.getKey();
final ButtomItemdelegate value = item.getValue();
TAB_BEANS.add(key);
TAB_DELEGATES.add(value);
}
}
@Override
public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
final int size = ITEMS.size();
for (int i = 0; i < size; i++) {
LayoutInflater.from(getContext()).inflate(R.layout.buttom_item_icon_title_layout, mBottomBar);
final RelativeLayout item = (RelativeLayout) mBottomBar.getChildAt(i);
//設定每個tab的點選事件
item.setTag(i);
item.setOnClickListener(this);
final IconTextView icon = (IconTextView) item.getChildAt(0);
final IconTextView tv = (IconTextView) item.getChildAt(1);
final ButtomTabBean bean = TAB_BEANS.get(i);
//初始化資料
icon.setText(bean.getIcon());
tv.setText(bean.getTitle());
if (i == mIndexItem) {
icon.setTextColor(mTabColor);
tv.setTextColor(mTabColor);
}
}
//初始化每個TAB對應的介面
final ISupportFragment[] fragments = TAB_DELEGATES.toArray(new ISupportFragment[size]);
getSupportDelegate().loadMultipleRootFragment(R.id.buttom_frame, mIndexItem, fragments);
}
private void resetColor() {
final int count = mBottomBar.getChildCount();
for (int i = 0; i < count; i++) {
final RelativeLayout item = (RelativeLayout) mBottomBar.getChildAt(i);
final IconTextView itemIcon = (IconTextView) item.getChildAt(0);
itemIcon.setTextColor(Color.GRAY);
final IconTextView itemTitle = (IconTextView) item.getChildAt(1);
itemTitle.setTextColor(Color.GRAY);
}
}
@Override
public void onClick(View v) {
final int tag = (int) v.getTag();
resetColor();
final RelativeLayout item = (RelativeLayout) v;
final IconTextView itemIcon = (IconTextView) item.getChildAt(0);
itemIcon.setTextColor(mTabColor);
final IconTextView itemTitle = (IconTextView) item.getChildAt(1);
itemTitle.setTextColor(mTabColor);
//展示和隱藏Fragment 引數一為要展示的 引數二為要隱藏的
getSupportDelegate().showHideFragment(TAB_DELEGATES.get(tag), TAB_DELEGATES.get(mCurrentItem));
//注意先後順序
mCurrentItem = tag;
}
}
首先宣告的幾個引數:
ArrayList<ButtomTabBean> TAB_BEANS
:儲存Tab所對應的內容。
ArrayList<ButtomItemdelegate> TAB_DELEGATES
:儲存Tab所對應的Fragmnet。
private final LinkedHashMap<ButtomTabBean, ButtomItemdelegate> ITEMS
:使每個ButtomTabBean物件與對應的Fragment對應起來。
還有幾個抽象方法:
public abstract LinkedHashMap<ButtomTabBean, ButtomItemdelegate> setItems(ItemBuilder builder); //建立Tab類與Fragment類,並傳入到介面
public abstract int setIndexItem(); //設定第一次進入的要顯示第幾個介面
public abstract int setColor(); //設定Tab點選後的顏色
然後就是主程式碼,在oncreat中將 Tab與繫結的介面獲取出來,儲存到TAB_BEANS,TAB_DELEGATES中,這樣就可以控制。
接著在onBindView中對檢視進行繫結,迴圈依次取出每個TabBean,然後使用LayoutInflater載入每個Tab檢視,並新增到容器中,這個容器就是介面底部的一個LinearLayout,同時從TAB_BEANS中獲取資料,並賦值。這裡記得對每個Tab的點選事件進行註冊。點選事件主要處理的就是Tab顯示及對應介面變化。
//初始化每個TAB對應的介面
final ISupportFragment[] fragments = TAB_DELEGATES.toArray(new ISupportFragment[size]);
getSupportDelegate().loadMultipleRootFragment(R.id.buttom_frame, mIndexItem, fragments);
這兩句程式碼實現的對介面(Fragment)的載入,是框架Fragmentation裡的內容,不太懂,待我研究下。
到這裡,這基類的抽取就算完成了。然後就是使用:
public class Bottomdalegate extends BaseButtomDelegete {
@Override
public LinkedHashMap<ButtomTabBean, ButtomItemdelegate> setItems(ItemBuilder builder) {
final LinkedHashMap<ButtomTabBean, ButtomItemdelegate> ITEMS=new LinkedHashMap<>();
ITEMS.put(new ButtomTabBean("{fa-home}","主頁"),new IndexDelegate());
ITEMS.put(new ButtomTabBean("{fa-sort}","分類"),new SortDelegate());
ITEMS.put(new ButtomTabBean("{fa-compass}","發現"),new CompassDelegate());
ITEMS.put(new ButtomTabBean("{fa-shopping-cart}","購物車"),new ShopCarDelegate());
ITEMS.put(new ButtomTabBean("{fa-user}","我的"),new UserDelegate());
return builder.addItems(ITEMS).build();
}
@Override
public int setIndexItem() {
return 0;
}
@Override
public int setColor() {
return Color.parseColor("#0099cc");
}
}
前面封裝好了,這裡程式碼就比較簡單了,直接實現三個抽象方法。
到這裡,主介面就基本實現了。可以使用這種思想,不用每次對檢視直接建立,而是通過動態繫結的方式傳入資料,這樣就比較靈活。