下拉菜单
美团首页类似的下拉弹出菜单工程中经常遇到的控件,不同工程中菜单条目的类型与数量也不一样 所以需要根据实际需要填充不同内容。先写个demo,一倍不时之需吧。 既然每个项目用到的菜单样式不同,此时我们必须根据实际情况填充,这样就需要将容器和内容分开。
容器
容器的画当然就使用popWindow了,我们需要在点击指定控件后弹出window,需要
1.指定当前window的位置及大小
2.指定window出方式
3.如果要求其他部分变暗,我们必须指定变暗部分的高度
内容
内容需要被填充到容器中,根据不同的数据类型及需求,设置不同的页面填充。可以将其定义为**组合控件**或者一个**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; } }
弹窗代码
假定我们现在按下一个按键,然后弹出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); } }
二级菜单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); } } }
将内容添加到容器中
调用的时候分为以下四步。这样,显示,逻辑和数据就自然分离开来了。
//创建容器 PopMenuButton mPopMenuButton = (PopMenuButton) findViewById(R.id.btn_pop); //创建Holder,提供内容 DoubleListViewHolder holder = new DoubleListViewHolder(); //将 内容 贴到 容器 中 mPopMenuButton.setContentView(holder.getView()); //用数据刷新容器的显示内容 holder.refreshView(mLists);
git: https://git.oschina.net/vonchenchen/pulldownmenu.git