Android仿大眾點評多條目下拉菜單篩選
首先來看看我們要實現(xiàn)的效果,下面這張圖是大眾點評APP里面的一個多條目下拉菜單篩選的一個效果,這是很多App里面都比較常見的一種多條目篩選菜單。

結(jié)構(gòu)分析:

整個控件我么用一個LinearLayout 實現(xiàn),所以我們要繼承LinearLayout .然后是上面紅色長方形部分的Tab欄,下面最外層黑色框框是一個FrameLayout用來存放陰影(綠色框框部分)和菜單布局(最里面紅色框框部分)
實現(xiàn)
分析完了,我們就可以用代碼來實現(xiàn)了,代碼如下:
1、基本布局:
public class ListDataScreenView extends LinearLayout {private Context mContext;// 1.1 創(chuàng)建頭部用來存放 Tabprivate LinearLayout mMenuTabView;// 1.2 創(chuàng)建 FrameLayout 用來存放 = 陰影(View) + 菜單內(nèi)容布局(FrameLayout)private FrameLayout mMenuMiddleView;// 陰影private View mShadowView;// 創(chuàng)建菜單用來存放菜單內(nèi)容private FrameLayout mMenuContainerView;// 陰影的顏色private int mShadowColor = 0x88888888;// 篩選菜單的 Adapterprivate BaseMenuAdapter mAdapter;// 內(nèi)容菜單的高度private int mMenuContainerHeight;// 當(dāng)前打開的位置private int mCurrentPosition = -1;private long DURATION_TIME = 350;// 動畫是否在執(zhí)行private boolean mAnimatorExecute;public ListDataScreenView(Context context) {this(context, null);}public ListDataScreenView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public ListDataScreenView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mContext = context;initLayout();}/*** 1.布局實例化好 (組合控件)*/private void initLayout() {// 1. 先創(chuàng)建一個 xml 布局 ,再加載,findViewById// 2. 簡單的效果用代碼去創(chuàng)建 早期IOS 用代碼創(chuàng)建布局setOrientation(VERTICAL);// 1.1 創(chuàng)建頭部用來存放 TabmMenuTabView = new LinearLayout(mContext);mMenuTabView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));addView(mMenuTabView);// 1.2 創(chuàng)建 FrameLayout 用來存放 = 陰影(View) + 菜單內(nèi)容布局(FrameLayout)mMenuMiddleView = new FrameLayout(mContext);LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);params.weight = 1;mMenuMiddleView.setLayoutParams(params);addView(mMenuMiddleView);// 創(chuàng)建陰影 可以不用設(shè)置 LayoutParams 默認(rèn)就是 MATCH_PARENT ,MATCH_PARENTmShadowView = new View(mContext);mShadowView.setBackgroundColor(mShadowColor);mShadowView.setAlpha(0f);mShadowView.setOnClickListener(this);mShadowView.setVisibility(GONE);mMenuMiddleView.addView(mShadowView);//陰影View在下面// 創(chuàng)建菜單用來存放菜單內(nèi)容mMenuContainerView = new FrameLayout(mContext);mMenuContainerView.setBackgroundColor(Color.WHITE);mMenuMiddleView.addView(mMenuContainerView);//菜單內(nèi)容在上面}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);Log.e("TAG", "onMeasure");int height = MeasureSpec.getSize(heightMeasureSpec);if (mMenuContainerHeight == 0 && height > 0) {// 內(nèi)容的高度應(yīng)該不是全部 應(yīng)該是整個 View的 75%mMenuContainerHeight = (int) (height * 75f / 100);//獲取菜單內(nèi)容View的LayoutParamsViewGroup.LayoutParams params = mMenuContainerView.getLayoutParams();//設(shè)置菜單內(nèi)容的高度params.height = mMenuContainerHeight;mMenuContainerView.setLayoutParams(params);// 進(jìn)來的時候陰影不顯示 ,內(nèi)容也是不顯示的(把它移上去)//放菜單內(nèi)容mMenuContainerView.setTranslationY(-mMenuContainerHeight);}}}
2、設(shè)置點擊事件,以及過程中的動畫
/*** 設(shè)置tab的點擊** @param tabView* @param position*/private void setTabClick(final View tabView, final int position) {tabView.setOnClickListener(new OnClickListener() {public void onClick(View v) {if (mCurrentPosition == -1) {// 沒打開openMenu(position, tabView);} else {if (mCurrentPosition == position) {// 打開了,關(guān)閉closeMenu();} else {// 切換一下顯示//拿到菜單容器里的子view(TextView)View currentMenu = mMenuContainerView.getChildAt(mCurrentPosition);currentMenu.setVisibility(View.GONE);//將子view(TextView)設(shè)置無不可見mAdapter.menuClose(mMenuTabView.getChildAt(mCurrentPosition));//拿到當(dāng)前點擊的位置mCurrentPosition = position;currentMenu = mMenuContainerView.getChildAt(mCurrentPosition);currentMenu.setVisibility(View.VISIBLE);mAdapter.menuOpen(mMenuTabView.getChildAt(mCurrentPosition));}}}});}/*** 關(guān)閉菜單*/private void closeMenu() {//動畫正在執(zhí)行,點擊無效if (mAnimatorExecute) {return;}// 關(guān)閉動畫 位移動畫 透明度動畫ObjectAnimator translationAnimator = ObjectAnimator.ofFloat(mMenuContainerView, "translationY", 0, -mMenuContainerHeight);translationAnimator.setDuration(DURATION_TIME);translationAnimator.start();mShadowView.setVisibility(View.VISIBLE);ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(mShadowView, "alpha", 1f, 0f);alphaAnimator.setDuration(DURATION_TIME);// 要等關(guān)閉動畫執(zhí)行完才能去隱藏當(dāng)前菜單alphaAnimator.addListener(new AnimatorListenerAdapter() {//動畫執(zhí)行完畢public void onAnimationEnd(Animator animation) {View menuView = mMenuContainerView.getChildAt(mCurrentPosition);menuView.setVisibility(View.GONE);mCurrentPosition = -1;mShadowView.setVisibility(GONE);mAnimatorExecute = false;}//關(guān)閉菜單動畫開始public void onAnimationStart(Animator animation) {mAnimatorExecute = true;mAdapter.menuClose(mMenuTabView.getChildAt(mCurrentPosition));}});alphaAnimator.start();}/*** 打開菜單** @param position* @param tabView*/private void openMenu(final int position, final View tabView) {//動畫正在執(zhí)行,點擊無效if (mAnimatorExecute) {return;}//設(shè)置陰影可見mShadowView.setVisibility(View.VISIBLE);// 獲取當(dāng)前位置顯示當(dāng)前菜單,菜單是加到了菜單容器View menuView = mMenuContainerView.getChildAt(position);menuView.setVisibility(View.VISIBLE);// 打開開啟動畫 位移動畫 透明度動畫//位移動畫ObjectAnimator translationAnimator = ObjectAnimator.ofFloat(mMenuContainerView, "translationY", -mMenuContainerHeight, 0);translationAnimator.setDuration(DURATION_TIME);translationAnimator.start();//透明度動畫ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(mShadowView, "alpha", 0f, 1f);alphaAnimator.setDuration(DURATION_TIME);alphaAnimator.addListener(new AnimatorListenerAdapter() {public void onAnimationEnd(Animator animation) {mAnimatorExecute = false;mCurrentPosition = position;}public void onAnimationStart(Animator animation) {mAnimatorExecute = true;// 把當(dāng)前的 tab 傳到外面mAdapter.menuOpen(tabView);}});alphaAnimator.start();}
3、寫Adapter提供數(shù)據(jù)源
這個時候我們的效果還是死的,我么得給他設(shè)置寫一個Adapter,現(xiàn)實情況下,我們的數(shù)據(jù)也是通常要去網(wǎng)絡(luò)獲取,所以不能寫死。
>BaseMenuAdapter/*** 篩選菜單的 Adapter*/public abstract class BaseMenuAdapter {// 獲取總共有多少條public abstract int getCount();// 獲取當(dāng)前的TabViewpublic abstract View getTabView(int position, ViewGroup parent);// 獲取當(dāng)前的菜單內(nèi)容public abstract View getMenuView(int position, ViewGroup parent);/*** 菜單打開* @param tabView*/public void menuOpen(View tabView) {}/*** 菜單關(guān)閉* @param tabView*/public void menuClose(View tabView) {}}
具體的Adapter:
public class ListScreenMenuAdapter extends BaseMenuAdapter{private Context mContext;public ListScreenMenuAdapter(Context context){this.mContext = context;}private String[] mItems ={"附近","美食","智能排序","篩選"};public int getCount() {return mItems.length;}public View getTabView(int position, ViewGroup parent) {TextView tabView = (TextView) LayoutInflater.from(mContext).inflate(R.layout.ui_list_data_screen_tab,parent,false);tabView.setText(mItems[position]);tabView.setTextColor(Color.BLACK);return tabView;}public View getMenuView(int position, ViewGroup parent) {// 真正開發(fā)過程中,不同的位置顯示的布局不一樣TextView menuView = (TextView) LayoutInflater.from(mContext).inflate(R.layout.ui_list_data_screen_menu,parent,false);menuView.setText(mItems[position]);return menuView;}public void menuClose(View tabView) {TextView tabTv = (TextView) tabView;tabTv.setTextColor(Color.BLACK);}public void menuOpen(View tabView) {TextView tabTv = (TextView) tabView;tabTv.setTextColor(Color.RED);}}
有了Adapter之后,我們就可以給ListDataScreenView 以下方法,是不是感覺跟ListView很像。
/*** 設(shè)置 Adapter** @param adapter*/public void setAdapter(BaseMenuAdapter adapter) {this.mAdapter = adapter;// 獲取有多少條int count = mAdapter.getCount();for (int i = 0; i < count; i++) {// 獲取菜單的TabView tabView = mAdapter.getTabView(i, mMenuTabView);mMenuTabView.addView(tabView);//加一個TextViewLinearLayout.LayoutParams params = (LayoutParams) tabView.getLayoutParams();params.weight = 1;tabView.setLayoutParams(params);// 設(shè)置tab點擊事件setTabClick(tabView, i);// 獲取菜單的內(nèi)容(一個TextView)View menuView = mAdapter.getMenuView(i, mMenuContainerView);menuView.setVisibility(GONE);mMenuContainerView.addView(menuView);}// 內(nèi)容還沒有顯示出來,打開的時候顯示當(dāng)前位置的菜單,關(guān)閉的時候隱藏,陰影點擊應(yīng)該要關(guān)閉菜單// 動畫在執(zhí)行的情況下就不要在響應(yīng)動畫事件// 打開和關(guān)閉 變化tab的顯示 , 肯定不能把代碼寫到 ListDataScreen 里面來// 當(dāng)菜單是打開的狀態(tài) 不要執(zhí)行動畫只要切換}
最后看下我們實現(xiàn)的效果:

到這里就結(jié)束啦。
評論
圖片
表情
