Android自定義控件:下拉菜單的實現與優化

jopen 10年前發布 | 23K 次閱讀 安卓開發 Android開發 移動開發

下拉菜單

美團首頁類似的下拉彈出菜單工程中經常遇到的控件,不同工程中菜單條目的類型與數量也不一樣
所以需要根據實際需要填充不同內容。先寫個demo,一倍不時之需吧。

既然每個項目用到的菜單樣式不同,此時我們必須根據實際情況填充,這樣就需要將容器和內容分開。</pre>

容器

容器的畫當然就使用popWindow了,我們需要在點擊指定控件后彈出window,需要

1.指定當前window的位置及大小

2.指定window出方式

3.如果要求其他部分變暗,我們必須指定變暗部分的高度

</div>

</div>

內容

內容需要被填充到容器中,根據不同的數據類型及需求,設置不同的頁面填充。可以將其定義為**組合控件**或者一個**Holder**。
需要提供控件填充方法和數據刷新兩個基本方法,同時還需要一個方法暴露一個View的引用,這樣就可以將這個View填充到我們想添加的任何位置。

BaseHolder

/**

  • Created by Administrator on 2015/10/30 0030. */ public abstract class BaseHolder<T> {

    private View mView;

    public abstract View initView(); public abstract void refreshView(T info);

    public BaseHolder(){

     mView = initView();
     mView.setTag(this);
    

    }

    public View getView(){

     return mView;
    

    } }</pre>

    彈窗代碼

    假定我們現在按下一個按鍵,然后彈出popwindow,此時我們需要繼承一個Button,復寫Button的OnClick方法,從而實現點擊按鍵在按鍵正下方彈出popwindow的效果。

    public class PopMenuButton extends Button  implements View.OnClickListener {

    private Context mCtx; private PopupWindow mPopupWindow; private LinearLayout mPopupWindowView; //根布局設置為Button 彈出popwindow的位置可以以根布局為參照 private View mRootView; private View mShodowView; private LinearLayout mContentView;

    private int[] mLocation = new int[2]; private int mStartY; private int mScreenHeight;

    public PopMenuButton(Context context, AttributeSet attrs) {

     super(context, attrs);
     mCtx = context;
     mRootView = this;
    

    }

    public PopMenuButton(Context context) {

     super(context);
     mCtx = context;
     mRootView = this;
    

    }

    @Override protected void onFinishInflate() {

     super.onFinishInflate();
     initPopWindow();
    

    }

    public void setContentView(View view){

     LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
     mContentView.addView(view, params);
    

    }

    private void initView(){

     mPopupWindowView = (LinearLayout) View.inflate(mCtx, R.layout.popmenu_layout, null);
     mContentView = (LinearLayout) mPopupWindowView.findViewById(R.id.rl_content);
     mShodowView = mPopupWindowView.findViewById(R.id.rl_shodow);
    
     mShodowView.setOnClickListener(new OnClickListener() {
         @Override
         public void onClick(View v) {
             mPopupWindow.dismiss();
         }
     });
    
     setOnClickListener(this);
    

    }

    private void initPopWindow(){

     initView();
     //獲取按鍵的位置
     mRootView.getLocationOnScreen(mLocation);
     mStartY = mLocation[1] + mRootView.getHeight();
    

    }

    @Override public void onClick(View v) {

     if(mPopupWindow == null) {
         //initPopWindow();
    
         int[] location = new int[2];
         this.getLocationOnScreen(location);
         //y軸起始位置
         int start = location[1] + this.getHeight() + 1;
         //測量屏幕的高度
         int screenHeight = ((Activity) mCtx).getWindowManager().getDefaultDisplay().getHeight();
    
         //設置彈框的大小  彈框位置在按鈕以下,占據所有屏幕
         mPopupWindow = new PopupWindow(mPopupWindowView, ViewGroup.LayoutParams.MATCH_PARENT, screenHeight - start, false);
         // mPopupWindow = new PopupWindow(mPopupWindowView,  ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,false);
         mPopupWindow.setBackgroundDrawable(new ColorDrawable(0xb0000000));
         //mPopupWindow.setAnimationStyle(R.style.AnimationFade);
         mPopupWindow.setAnimationStyle(R.style.popupAnimation);
         mPopupWindow.setFocusable(true);
         mPopupWindow.setOutsideTouchable(true);
     }
    
     if (mPopupWindow.isShowing()) {
         mPopupWindow.dismiss();
     } else {
    
         int[] location1 = new int[2];
         this.getLocationOnScreen(location1);
         //設置彈框的位置
         mPopupWindow.showAtLocation(mRootView, Gravity.NO_GRAVITY, 0,  location1[1]+this.getHeight()+1);
     }
    

    }

    private int dip2px(Context context, float dpValue) {

     final float scale = context.getResources().getDisplayMetrics().density;
     return (int) (dpValue * scale);
    

    } }</pre>

    二級菜單Holder

    假設我們當前要彈出一個二級菜單,我們可以將邏輯封裝到一個Holder中,最終讓holder為我們提供頁面,直接將頁面貼到容器中。

    /**

  • Created by vonchenchen on 2015/10/30 0030. */ public class DoubleListViewHolder extends BaseHolder<List<List<String>>> {

    private List<List<String>> mData;

    private ListView mLeftListView; private ListView mRightListView;

    private List<String> mLeftList; private List<String> mRightList; private TextListAdapter mLeftAdapter; private TextRightListAdapter mRightAdapter;

    private View mViewClickRecorder = null; private boolean mFirstMesure = true;

    @Override public View initView() {

     View view = View.inflate(MyApplication.getContext(), R.layout.doublelistview_layout, null);
    
     mLeftListView = (ListView) view.findViewById(R.id.ll_left);
     mRightListView = (ListView) view.findViewById(R.id.ll_right);
    
     mLeftListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
         @Override
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    
             //如果點擊條目,更換被點擊條目的顏色
             if(mViewClickRecorder != view){
                 view.setBackgroundColor(MyApplication.getContext().getResources().getColor(R.color.normal_selected_color));
                 if(mViewClickRecorder != null) {
                     mViewClickRecorder.setBackgroundColor(MyApplication.getContext().getResources().getColor(R.color.normal_unselected_color));
                 }
                mViewClickRecorder = view;
             }
    
             mRightList = mData.get(position+1);
    
             mRightAdapter = new TextRightListAdapter(mRightList);
             mRightListView.setAdapter(mRightAdapter);
         }
     });
    
     return view;
    

    }

    @Override public void refreshView(List<List<String>> info) {

     this.mData = info;
    
     mLeftList = info.get(0);
     mLeftAdapter = new TextListAdapter(mLeftList);
    
     mRightList = info.get(1);
     mRightAdapter = new TextRightListAdapter(mRightList);
    
     mLeftListView.setAdapter(mLeftAdapter);
     mRightListView.setAdapter(mRightAdapter);
    

    }

    class TextListAdapter extends MyAdapter{

     public TextListAdapter(List list) {
         super(list);
     }
    
     @Override
     public View getView(final int position, View convertView, ViewGroup parent) {
    
         TextViewHolder holder = null;
         if(convertView == null){
             holder = new TextViewHolder();
         }else{
             holder = (TextViewHolder) convertView.getTag();
         }
    
         convertView = holder.getView();
         holder.refreshView((String) getItem(position));
    
         //防止多次測量
         if(position == 0 && mFirstMesure){
             mFirstMesure = false;
             convertView.setBackgroundColor(MyApplication.getContext().getResources().getColor(R.color.normal_selected_color));
             mViewClickRecorder = convertView;
         }
    
         return convertView;
     }
    

    }

    class TextRightListAdapter extends MyAdapter{

     public TextRightListAdapter(List list) {
         super(list);
     }
    
     @Override
     public View getView(final int position, View convertView, ViewGroup parent) {
    
         TextViewHolder holder = null;
         if(convertView == null){
             holder = new TextViewHolder();
         }else{
             holder = (TextViewHolder) convertView.getTag();
         }
    
         convertView = holder.getView();
         holder.refreshView((String) getItem(position));
         return convertView;
     }
    

    }

    /**

    • ListView 中的 Holder */ private class TextViewHolder extends BaseHolder<String>{

      private TextView mTextView;

      @Override public View initView() {

       View view = View.inflate(MyApplication.getContext(), R.layout.simpletext_item, null);
       mTextView = (TextView) view.findViewById(R.id.tv_text);
       return view;
      

      }

      @Override public void refreshView(String info) {

       mTextView.setText(info);
      

      } } }</pre>

      將內容添加到容器中

    調用的時候分為以下四步。這樣,顯示,邏輯和數據就自然分離開來了。

    //創建容器

     PopMenuButton mPopMenuButton = (PopMenuButton) findViewById(R.id.btn_pop);
     //創建Holder,提供內容
     DoubleListViewHolder holder = new DoubleListViewHolder();
    
     //將 內容 貼到 容器 中
     mPopMenuButton.setContentView(holder.getView());
     //用數據刷新容器的顯示內容
     holder.refreshView(mLists);</pre> 
    

    git: https://git.oschina.net/vonchenchen/pulldownmenu.git

來自: http://www.androidchina.net/3928.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!