这是我在CSDN上第一篇原创文章,趁着从上家公司离职去考驾照的这段日子,想通过写技术博客的方式,锻炼一下自己的语言表达能力,以及对之前工作的总结。废话不多说了,直接进入正题
先给客官来张效果图:
一、思路
下拉菜单首先让我想到了PopupWindow,PopupWindow上的contentView是一个半透明的LineaLayout,再上面是一个ListView。popupWindow的showAsDropDown方法可以让popupWindow显示到某个控件的下方,出现和隐藏的时候加个动画就行了。那么下拉菜单已经有了,接下来上部的菜单按钮要怎么实现呢,无非就是LinearLayout上有个TextView和View,文字右边的箭头可以调用TextView的方法画到右边,无非多加一个状态参数来判定到底是画哪个。好了,思路有了,接下来我们看是怎么实现的。
二、实现
首先我封装了一个PopupUtil类:
public class PopWinDownUtil {
private Context context;
private View contentView;
private View relayView;
private PopupWindow popupWindow;
public PopWinDownUtil(Context context, View contentView, View relayView){
this.context = context;
this.contentView = contentView;
this.relayView = relayView;
init();
}
public void init(){
//内容,高度,宽度
popupWindow = new PopupWindow(contentView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, true);
//动画效果
popupWindow.setAnimationStyle(R.style.AnimationTopFade);
//菜单背景色
ColorDrawable dw = new ColorDrawable(Color.TRANSPARENT);
popupWindow.setBackgroundDrawable(dw);
popupWindow.setOutsideTouchable(true);
//关闭事件
popupWindow.setSoftInputMode(PopupWindow.INPUT_METHOD_NEEDED);
popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
if(onDismissLisener != null){
onDismissLisener.onDismiss();
}
}
});
}
public void show(){
//显示位置
popupWindow.showAsDropDown(relayView);
}
public void hide(){
if(popupWindow != null && popupWindow.isShowing()){
popupWindow.dismiss();
}
}
private OnDismissLisener onDismissLisener;
public void setOnDismissListener(OnDismissLisener onDismissLisener){
this.onDismissLisener = onDismissLisener;
}
public interface OnDismissLisener{
void onDismiss();
}
public boolean isShowing(){
return popupWindow.isShowing();
}
}
可以直接把contenView和显示到哪个控件下面的View传进来,添加了一个监听popupWindow窗口消失的回调接口,代码很简单就不多说了。
之后就该菜单按钮了,代码如下:
public class DropdownButton extends RelativeLayout implements Checkable, View.OnClickListener, PopWinDownUtil.OnDismissLisener, AdapterView.OnItemClickListener {
/**
* 菜单按钮文字内容
*/
private TextView text;
/**
* 菜单按钮底部的提示条
*/
private View bLine;
private boolean isCheced;
private PopWinDownUtil popWinDownUtil;
private Context mContext;
private DropDownAdapter adapter;
/**
* 传入的数据
*/
private List drops;
/**
* 当前被选择的item位置
*/
private int selectPosition;
public DropdownButton(Context context) {
this(context, null);
}
public DropdownButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DropdownButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mContext = context;
//菜单按钮的布局
View view = LayoutInflater.from(getContext()).inflate(R.layout.dropdown_tab_button,this, true);
text = (TextView) view.findViewById(R.id.textView);
bLine = view.findViewById(R.id.bottomLine);
//点击事件,点击外部区域隐藏popupWindow
setOnClickListener(this);
}
/**
* 添加数据,默认选择第一项
* @param dropBeans
*/
public void setData(List dropBeans){
if(dropBeans == null || dropBeans.isEmpty()){
return;
}
drops = dropBeans;
drops.get(0).setChoiced(true);
text.setText(drops.get(0).getName());
selectPosition = 0;
View view = LayoutInflater.from(mContext).inflate(R.layout.dropdown_content, null);
view.findViewById(R.id.content).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
popWinDownUtil.hide();
}
});
ListView listView = (ListView) view.findViewById(R.id.list);
listView.setOnItemClickListener(this);
adapter = new DropDownAdapter(drops,mContext);
listView.setAdapter(adapter);
popWinDownUtil = new PopWinDownUtil(mContext,view,this);
popWinDownUtil.setOnDismissListener(this);
}
public void setText(CharSequence content) {
text.setText(content);
}
/**
* 根据传过来的参数改变状态
* @param checked
*/
@Override
public void setChecked(boolean checked) {
isCheced = checked;
Drawable icon;
if (checked) {
icon = getResources().getDrawable(R.mipmap.ic_dropdown_actived);
text.setTextColor(getResources().getColor(R.color.green));
bLine.setVisibility(VISIBLE);
popWinDownUtil.show();
} else {
icon = getResources().getDrawable(R.mipmap.ic_dropdown_normal);
text.setTextColor(getResources().getColor(R.color.black));
bLine.setVisibility(GONE);
popWinDownUtil.hide();
}
//把箭头画到textView右边
text.setCompoundDrawablesWithIntrinsicBounds(null, null, icon, null);
}
@Override
public boolean isChecked() {
return isCheced;
}
@Override
public void toggle() {
setChecked(!isCheced);
}
@Override
public void onClick(View v) {
setChecked(!isCheced);
}
@Override
public void onDismiss() {
setChecked(false);
}
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
if(selectPosition == position){
return;
}
drops.get(selectPosition).setChoiced(false);
drops.get(position).setChoiced(true);
text.setText(drops.get(position).getName());
adapter.notifyDataSetChanged();
selectPosition = position;
popWinDownUtil.hide();
if(onDropItemSelectListener != null){
onDropItemSelectListener.onDropItemSelect(position);
}
}
private OnDropItemSelectListener onDropItemSelectListener;
public void setOnDropItemSelectListener(OnDropItemSelectListener onDropItemSelectListener){
this.onDropItemSelectListener = onDropItemSelectListener;
}
public interface OnDropItemSelectListener{
void onDropItemSelect(int Postion);
}
class DropDownAdapter extends BaseAdapter {
private List drops;
private Context context;
public DropDownAdapter(List drops, Context context){
this.drops = drops;
this.context = context;
}
@Override
public int getCount() {
return drops.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null){
holder = new ViewHolder();
convertView = LayoutInflater.from(context).inflate(R.layout.dropdown_item,parent,false);
holder.tv = (TextView) convertView.findViewById(R.id.name);
holder.tig = (ImageView) convertView.findViewById(R.id.check);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.tv.setText(drops.get(position).getName());
if(drops.get(position).isChoiced()){
holder.tig.setVisibility(VISIBLE);
}else{
holder.tig.setVisibility(GONE);
}
return convertView;
}
private class ViewHolder{
TextView tv;
ImageView tig;
}
}
}
逻辑并不难,重要的部分都有提示,还是要讲一下,控件用到的数据是我定义的一个DropBean集合,里边有要展示的文字内容和一个isChecked状态,用来决定该item是否已被选中。如果我们的列表数据是从服务端获取的,那么我们只要用个for循环赋值成DropBean集合就行了。然后直接调用菜单控件的setData就不用管了。
接下来是我的调用示例:
public class MainActivity extends AppCompatActivity {
private DropdownButton dropdownButton1;
private DropdownButton dropdownButton2;
private DropdownButton dropdownButton3;
private List times;
private List types;
private List names;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dropdownButton1 = (DropdownButton) findViewById(R.id.time1);
dropdownButton2 = (DropdownButton) findViewById(R.id.time2);
dropdownButton3 = (DropdownButton) findViewById(R.id.time3);
initSomeData();
dropdownButton1.setData(times);
dropdownButton2.setData(types);
dropdownButton3.setData(names);
}
private void initSomeData() {
times = new ArrayList<>();
types = new ArrayList<>();
names = new ArrayList<>();
int mouth = 5;
int year = 2016;
times.add(new DropBean("全部时间"));
times.add(new DropBean(year + "年 全年"));
for (int i = 0; i < mouth; i++) {
times.add(new DropBean(year + "年 " + (i + 1) + "月"));
}
types.add(new DropBean("交通"));
types.add(new DropBean("饮食"));
names.add(new DropBean("小张"));
names.add(new DropBean("小王"));
names.add(new DropBean("小c"));
names.add(new DropBean("小刘"));
}
}
代码很少,逻辑也很明确,这里就不多说了。对了我们的布局文件是这样的:
是不是很简单,需要几个就写几个。
dropdown_in.xml的代码:
dropdown_out.xml的代码:
到此史上最简单的下拉菜单就打造完了!
点击下载源码