android原生的dialog样式很不美观,大多数情况下,我们需要根据需求自定义弹窗的样式,而dialogfragment是官方推荐的对话框控件。 使用DialogFragment来管理对话框,当旋转屏幕和按下后退键时可以更好的管理其声明周期,它和Fragment有着基本一致的声明周期。屏幕旋转时,传统的dialog会报异常,而通过DialogFragment实现的对话框则可以完全不必考虑旋转的问题。且DialogFragment也允许开发者把Dialog作为内嵌的Fragment进行重用,可以在大屏幕和小屏幕显示出不同的效果。详情可以查看[鸿洋大神的博文][1]。 所以利用dialogfragment来封装常用的弹窗工具类再合适不过了,这里记录一下详细过程:
最终效果gif: 这是封装好的lib库,上图 这里我们封装了常见的提示弹窗,选择列表弹窗(支持垂直列表,水平列表,网格列表,同时支持单选与多选),加载弹窗,三种模式。
封装dialog lib 新建一个项目,具体过程不描述了,新建一个module,选择android libiary,填写好相关信息后finish。
创建一个弹窗基类 继承DialogFragment创建一个弹窗基类BaseDialogFragment,以便做统一管理。 统一默认颜色,背景,以及图标。
1 2 3 4 protected int layout; protected static final int DEFAULT_COLOR = -1 ; protected static final int DEFAULT_BG= -1 ; protected static final int DEFAULT_ICON=-1 ;
统一动画,这里我们默认两种动画
1 2 3 protected int animation = R.style.BottomDialog;public static final int BOTTOM_TO_TOP=0 ;public static final int TOP_TO_BOTTOM=1 ;
由子类传入布局文件,并提供显示弹窗和设置动画的方法,具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 @Override public Dialog onCreateDialog (Bundle savedInstanceState) { if (layout == 0 ) { throw new RuntimeException("no correct layout found." ); } View view = LayoutInflater.from(getActivity()).inflate(layout, null ); Dialog dialog= setDialog(view); return dialog; } protected abstract Dialog setDialog (View view) ; public BaseDialogFragment setDialogAnimation (int animation) { if (animation==TOP_TO_BOTTOM){ this .animation= R.style.TopDialog; }else { this .animation= R.style.BottomDialog; } return this ; } public void showDialog (FragmentManager fragmentManager) { FragmentTransaction ft = fragmentManager.beginTransaction(); Fragment fragment = fragmentManager.findFragmentByTag("dialogFragment" ); if (fragment != null ) { ft.remove(fragment); } show(ft, "dialogFragment" ); fragmentManager.executePendingTransactions(); } @Override public void onDestroyView () { super .onDestroyView(); }
封装提示弹窗 创建BaseNormalDialogFragment类继承BaseDialogFragment,添加icon的图标设置和是否显示的属性,提供按键监听接口。
1 2 3 4 5 6 7 8 9 10 protected static final int DEFAULT_ICON=-1 ;protected static final int HIDE_ICON=-2 ;protected ClickListener clickListener; public interface ClickListener { void clickSure () ; void clickCancel () ; }
外部注册监听:
1 2 3 4 public BaseNormalDialogFragment setOnBtnClickListener (ClickListener clickListener) { this .clickListener = clickListener; return this ; }
抽象自定义ui方法,待子类实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 protected abstract int getSureTextColor () ; protected abstract int getCancelTextColor () ; protected abstract String getSureText () ; protected abstract String getCancelText () ; protected abstract String getContent () ; protected abstract int getSureBg () ; protected abstract int getCancelBg () ; protected abstract int getDialogIcon () ; protected abstract int getDividerVerticalColor () ; protected abstract int getDividerHorizontalColor () ;
初始化弹窗设置ui和监听:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 public Dialog setDialog (View view) { Dialog dlg = new Dialog(getActivity(), R.style.MyDialogBottom); dlg.setCancelable(false ); dlg.setCanceledOnTouchOutside(false ); dlg.setContentView(view); dlg.getWindow().setBackgroundDrawableResource(R.color.transparent); TextView textMsg = (TextView) view.findViewById(R.id.text_msg); Button sureButton = (Button) view.findViewById(R.id.btn_sure); Button cancelButton = (Button) view.findViewById(R.id.btn_cancel); ImageView dialog_icon= (ImageView) view.findViewById(R.id.dialog_icon); ImageView divider_vertical= (ImageView) view.findViewById(R.id.divider_vertical); ImageView divider_horizontal= (ImageView) view.findViewById(R.id.divider_horizontal); if (getSureTextColor() != DEFAULT_COLOR) { sureButton.setTextColor(getResources().getColor(getSureTextColor())); } if (getCancelTextColor() != DEFAULT_COLOR) { cancelButton.setTextColor(getResources().getColor(getCancelTextColor())); } if (getCancelBg() != DEFAULT_BG) { sureButton.setBackgroundResource(getSureBg()); } if (getSureBg() != DEFAULT_BG) { sureButton.setBackgroundResource(getSureBg()); } if (getDividerHorizontalColor() != DEFAULT_COLOR){ divider_horizontal.setBackgroundColor(getResources().getColor(getDividerHorizontalColor())); } if (getDividerVerticalColor() != DEFAULT_COLOR){ divider_vertical.setBackgroundColor(getResources().getColor(getDividerVerticalColor())); } if ( getDialogIcon() != DEFAULT_ICON){ if (getDialogIcon()==HIDE_ICON){ dialog_icon.setVisibility(View.GONE); }else { dialog_icon.setVisibility(View.VISIBLE); dialog_icon.setImageResource(getDialogIcon()); } } textMsg.setText(getContent()); sureButton.setText(getSureText()); cancelButton.setText(getCancelText()); sureButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { if (clickListener != null ) { clickListener.clickSure(); } dismiss(); } }); cancelButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { if (clickListener != null ) { clickListener.clickCancel(); } dismiss(); } }); return dlg; }
最后封装一个提示窗子类,传入布局文件,当然这里也可以根据需求自己做扩展,传入不同的布局文件,但要保证控件id相同。
1 2 3 4 5 6 7 8 9 10 public static ListDialogFragment newInstance (int orientation) { ListDialogFragment fragment = new ListDialogFragment(); fragment.orientation=orientation; Bundle bundle = new Bundle(); bundle.putInt(TAG_ARG, R.layout.dialog_list); fragment.setArguments(bundle); return fragment; }
提示窗效果图: 布局文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:layout_width ="match_parent" android:layout_height ="wrap_content" android:gravity ="center" android:orientation ="vertical" android:padding ="30dp" > <RelativeLayout android:layout_width ="match_parent" android:layout_height ="200dp" android:background ="@drawable/dialog_bg_round" > <LinearLayout android:id ="@+id/dia_ll" android:layout_width ="fill_parent" android:layout_height ="45dp" android:layout_alignParentBottom ="true" android:orientation ="horizontal" > <Button android:id ="@+id/btn_cancel" android:layout_width ="0dp" android:layout_height ="match_parent" android:layout_weight ="1" android:background ="@null" android:text ="取消" android:textColor ="@color/default_blue" /> <ImageView android:id ="@+id/divider_vertical" android:layout_width ="1dp" android:layout_height ="45dp" android:background ="@color/default_blue" /> <Button android:id ="@+id/btn_sure" android:layout_width ="0dp" android:layout_height ="match_parent" android:layout_weight ="1" android:background ="@drawable/dialog_btn_bg_round" android:text ="确定" android:textColor ="@color/white" /> </LinearLayout > <ImageView android:id ="@+id/divider_horizontal" android:layout_width ="match_parent" android:layout_height ="1dp" android:layout_above ="@id/dia_ll" android:background ="@color/default_blue" /> <RelativeLayout android:layout_width ="match_parent" android:layout_height ="match_parent" android:layout_above ="@id/dia_ll" android:gravity ="center" > <ImageView android:id ="@+id/dialog_icon" android:layout_width ="60dp" android:layout_height ="60dp" android:layout_centerInParent ="true" android:src ="@drawable/dialog_icon" /> <TextView android:id ="@+id/text_msg" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_below ="@id/dialog_icon" android:layout_centerInParent ="true" android:layout_marginTop ="15dp" android:text ="发现新版本" android:textColor ="@color/default_blue" /> </RelativeLayout > </RelativeLayout > </LinearLayout >
向外暴露ui设置和接口,具体代码这里就不贴了,后面可查看源码。
提示弹窗的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 NormalDialogFragment.newInstance() .setContent("这只是一个普通的提示弹窗" ) .setSureTextColor(R.color.white) .setCancelTextColor(R.color.default_blue) .setSuretext("确定" ) .setCanceltext("取消" ) .setDividerHorizontalColor(R.color.default_line) .setDividerVerticalColor(R.color.default_line) .hideIcon() .setSureBg(R.drawable.dialog_btn_bg_round) .setOnBtnClickListener(new BaseNormalDialogFragment.ClickListener() { @Override public void clickSure () { Toast.makeText(context, "点击了确定" , Toast.LENGTH_SHORT).show(); } @Override public void clickCancel () { Toast.makeText(context, "点击了取消" , Toast.LENGTH_SHORT).show(); } }) .setDialogAnimation(BaseListDialogFragment.BOTTOM_TO_TOP) .showDialog(getFragmentManager());
封装加载弹窗 创建BaseLoadDialogFragment继承BaseDialogFragment,暴露一些自定义ui的方法,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 protected abstract int getLoadMsgColor () ; protected abstract String getLoadMsgText () ; protected abstract int getLoadImg () ; protected abstract int getLoadShape1 () ; protected abstract int getLoadShape2 () ; protected abstract int getBackgroundShape () ;
根据设置的ui初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 @Override protected Dialog setDialog (View view) { Dialog dlg = new Dialog(getActivity(), R.style.MyDialogBottom); dlg.setCancelable(false ); dlg.setCanceledOnTouchOutside(false ); dlg.setContentView(view); dlg.getWindow().setBackgroundDrawableResource(R.color.transparent); ProgressBar pb_progress = (ProgressBar) view.findViewById(R.id.pb_progress); TextView load_msg = (TextView) view.findViewById(R.id.load_msg); ImageView dot_loading1 = (ImageView) view.findViewById(R.id.dot_loading1); ImageView dot_loading2 = (ImageView) view.findViewById(R.id.dot_loading2); ImageView dot_loading3 = (ImageView) view.findViewById(R.id.dot_loading3); LinearLayout ly_background= (LinearLayout) view.findViewById(R.id.ly_background); ly_background.setBackgroundResource(getBackgroundShape()); load_msg.setText(getLoadMsgText()); if (getLoadMsgColor() != DEFAULT_COLOR) { load_msg.setTextColor(getResources().getColor(getLoadMsgColor())); } if (getLoadImg() != DEFAULT_COLOR) { pb_progress.setIndeterminateDrawable(getResources().getDrawable(getLoadImg())); } Drawable drawableBlue = getResources().getDrawable(getLoadShape1()); Drawable drawableGray = getResources().getDrawable(getLoadShape2()); AnimationDrawable anim1 = new AnimationDrawable(); anim1.addFrame(drawableBlue, 300 ); anim1.addFrame(drawableGray, 300 ); anim1.addFrame(drawableGray, 300 ); anim1.setOneShot(false ); dot_loading1.setBackgroundDrawable(anim1); anim1.start(); AnimationDrawable anim2 = new AnimationDrawable(); anim2.addFrame(drawableGray, 300 ); anim2.addFrame(drawableBlue, 300 ); anim2.addFrame(drawableGray, 300 ); anim2.setOneShot(false ); dot_loading2.setBackgroundDrawable(anim2); anim2.start(); AnimationDrawable anim3 = new AnimationDrawable(); anim3.addFrame(drawableGray, 300 ); anim3.addFrame(drawableGray, 300 ); anim3.addFrame(drawableBlue, 300 ); anim3.setOneShot(false ); dot_loading3.setBackgroundDrawable(anim3); anim3.start(); return dlg; }
封装一个加载窗子类,传入布局文件,这里也可以根据需求自己做扩展,传入不同的布局文件,但要保证控件id相同。
1 2 3 4 5 6 7 8 public static LoadDialogFragment newInstance () { LoadDialogFragment fragment=new LoadDialogFragment(); Bundle bundle = new Bundle(); bundle.putInt(TAG_ARG, R.layout.dialog_load); fragment.setArguments(bundle); return fragment; }
加载窗效果图: 布局文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:id ="@+id/ly_background" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:background ="@drawable/bg_load" android:gravity ="center_horizontal" android:orientation ="vertical" android:paddingBottom ="20dp" android:paddingLeft ="30dp" android:paddingRight ="30dp" android:paddingTop ="20dp" > <ProgressBar android:id ="@+id/pb_progress" style ="@style/CustomProgressStyle" android:layout_width ="48dp" android:layout_height ="48dp" android:indeterminateDrawable ="@drawable/load_progress" /> <LinearLayout android:orientation ="horizontal" android:layout_width ="wrap_content" android:layout_height ="wrap_content" > <TextView android:id ="@+id/load_msg" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_marginTop ="15dp" android:text ="Message" android:textColor ="@color/white" /> <ImageView android:id ="@+id/dot_loading1" android:layout_width ="5dp" android:layout_height ="5dp" android:layout_gravity ="bottom" android:layout_marginBottom ="3dp" android:layout_marginLeft ="5dp" /> <ImageView android:id ="@+id/dot_loading2" android:layout_width ="5dp" android:layout_height ="5dp" android:layout_gravity ="bottom" android:layout_marginBottom ="3dp" android:layout_marginLeft ="5dp" /> <ImageView android:id ="@+id/dot_loading3" android:layout_width ="5dp" android:layout_height ="5dp" android:layout_gravity ="bottom" android:layout_marginBottom ="3dp" android:layout_marginLeft ="3dp" /> </LinearLayout > </LinearLayout >
同样向外暴露ui设置和接口,具体代码这里就不贴了,后面可查看源码。
加载弹窗的使用 1 2 3 4 5 6 7 8 9 10 LoadDialogFragment loadDialogFragment = LoadDialogFragment.newInstance() .setLoadMsgText("正在加载中" ) .setLoadImg(R.drawable.load_progress) .setLoadShape1(R.drawable.load_cicle_blue) .setLoadShape2(R.drawable.load_cicle_gray) .setBackgroundShape(R.drawable.bg_load) .setLoadMsgColor(R.color.white); loadDialogFragment .setDialogAnimation(BaseListDialogFragment.BOTTOM_TO_TOP).showDialog(getFragmentManager());
封装选择列表窗 这里展示样式可以分为三种情况,水平,垂直以及网格列表,展示位置也有三种情况,顶部,中间,底部,选择模式可以分为两种情况,单选和多选。 创建BaseListDialogFragment类继承BaseDialogFragment,创建展示样式,位置,选择模式的属性,列表适配器和按键监听。这里的监听有两个,多选时,除了对item的选择监听外,还需要对顶部的确定和返回监听。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static final int HORIZONTAL = 0 ;public static final int VERTICAL = 1 ;public static final int GRID=2 ;protected int orientation;private DialogListAdapter dialogListAdapter;private DialogListAdapter.OnItemClickListener onItemClickListener;private ClickListener clickListener;public static final int BOTTOM=Gravity.BOTTOM;public static final int CENTER=Gravity.CENTER;public static final int TOP=Gravity.TOP;public interface ClickListener { void clickSure (List<Item> selectItems) ; void clickBack () ; }
外部注册监听:
1 2 3 4 5 6 7 8 9 10 public BaseListDialogFragment setOnItemClickListener (DialogListAdapter.OnItemClickListener onItemClickListener) { this .onItemClickListener = onItemClickListener; return this ; } public BaseListDialogFragment setClickListener (ClickListener clickListener) { this .clickListener = clickListener; return this ; }
对于列表项,需要添加数据源和适配器,数据源我们需要封装一个Item类,通过传入这个List- 进行设置。
封装item类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public class Item { private int id; private String title; private Drawable icon; private boolean check; public Item () { } public Item (int id, String title, Drawable icon) { this .id = id; this .title = title; this .icon = icon; } public int getId () { return id; } public void setId (int id) { this .id = id; } public String getTitle () { return title; } public void setTitle (String title) { this .title = title; } public Drawable getIcon () { return icon; } public void setIcon (Drawable icon) { this .icon = icon; } public boolean isCheck () { return check; } public void setCheck (boolean check) { this .check = check; } }
定义适配器 列表采用RecyclerView,适配器与RecyclerView的一致,由于展示样式不同,定义两种holder,对应不同的item布局。 图标文字上下排列的holder,水平列表根据数据个数设置item的宽度,网格列表则根据设置的每排显示个数来设置,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class TopHolder extends RecyclerView .ViewHolder { private TextView item; public TopHolder (View view) { super (view); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); if (orientation == HORIZONTAL){ params.width = getScreenWidth(context) / mItems.size(); }else { params.width = getScreenWidth(context) / rowNum; } params.setMargins(0 , padding, 0 , padding); item = new TextView(view.getContext()); item.setLayoutParams(params); item.setMaxLines(1 ); item.setEllipsize(TextUtils.TruncateAt.END); item.setGravity(Gravity.CENTER); item.setTextColor(ContextCompat.getColor(view.getContext(), R.color.black)); item.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.font_14)); item.setCompoundDrawablePadding(topPadding); TypedValue typedValue = new TypedValue(); view.getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, typedValue, true ); item.setBackgroundResource(typedValue.resourceId); ((LinearLayout) view).addView(item); } private Drawable icon (Drawable drawable) { if (drawable != null ) { Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); Drawable resizeIcon = new BitmapDrawable(context.getResources(), Bitmap.createScaledBitmap(bitmap, topIcon, topIcon, true )); Drawable.ConstantState state = resizeIcon.getConstantState(); resizeIcon = DrawableCompat.wrap(state == null ? resizeIcon : state.newDrawable().mutate()); return resizeIcon; } return null ; } }
图标文字左右排列的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class LeftHolder extends RecyclerView .ViewHolder { private TextView item; public LeftHolder (View view) { super (view); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); view.setLayoutParams(params); params.setMargins(padding, padding, padding, padding); item = new TextView(view.getContext()); item.setLayoutParams(params); item.setMaxLines(1 ); item.setEllipsize(TextUtils.TruncateAt.END); item.setGravity(Gravity.CENTER_VERTICAL); item.setTextColor(ContextCompat.getColor(view.getContext(), R.color.black)); item.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.font_14)); item.setCompoundDrawablePadding(leftPadding); TypedValue typedValue = new TypedValue(); view.getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, typedValue, true ); item.setBackgroundResource(typedValue.resourceId); ((LinearLayout) view).addView(item); } private Drawable icon (Drawable drawable) { if (drawable != null ) { Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); Drawable resizeIcon = new BitmapDrawable(context.getResources(), Bitmap.createScaledBitmap(bitmap, leftIcon, leftIcon, true )); Drawable.ConstantState state = resizeIcon.getConstantState(); resizeIcon = DrawableCompat.wrap(state == null ? resizeIcon : state.newDrawable().mutate()); return resizeIcon; } return null ; } }
根据展示样式,创建不同的holder,网格和水平列表采用图标文字上下排列的方式,垂直列表采用图标文字左右排列的方式:
1 2 3 4 5 6 7 8 @Override public RecyclerView.ViewHolder onCreateViewHolder (ViewGroup parent, int viewType) { if (orientation == GRID) return new TopHolder(new LinearLayout(parent.getContext())); else if (orientation == HORIZONTAL) return new TopHolder(new LinearLayout(parent.getContext())); else return new LeftHolder(new LinearLayout(parent.getContext())); }
同样,根据展示样式,进行不同的数据捆绑和按键监听,需要根据选择模式,进行颜色变化的处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 @Override public void onBindViewHolder (RecyclerView.ViewHolder holder, int position) { final Item item = mItems.get(position); final TopHolder topHolder; final LeftHolder leftHolder; if (orientation == GRID) { topHolder = (TopHolder) holder; topHolder.item.setText(item.getTitle()); topHolder.item.setCompoundDrawablesWithIntrinsicBounds(null , topHolder.icon(item.getIcon()), null , null ); topHolder.item.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { if (itemClickListener != null ) { if (multipleChoice){ if (item.isCheck()){ item.setCheck(false ); topHolder.item.setTextColor(context.getResources().getColor(baseListDialogFragment.getItemTextColor())); topHolder.item.setBackgroundColor(context.getResources().getColor(R.color.transparent)); selectItems.remove(item); }else { item.setCheck(true ); topHolder.item.setTextColor(context.getResources().getColor(baseListDialogFragment.getSelectItemTextColor())); topHolder.item.setBackgroundColor(context.getResources().getColor(baseListDialogFragment.getSelectItemBackgoundColor())); selectItems.add(item); } } itemClickListener.click(item,baseListDialogFragment); } } }); } else if (orientation == HORIZONTAL) { topHolder = (TopHolder) holder; topHolder.item.setText(item.getTitle()); topHolder.item.setCompoundDrawablesWithIntrinsicBounds(null , topHolder.icon(item.getIcon()), null , null ); topHolder.item.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { if (itemClickListener != null ) { if (multipleChoice){ if (item.isCheck()){ item.setCheck(false ); topHolder.item.setTextColor(context.getResources().getColor(baseListDialogFragment.getItemTextColor())); topHolder.item.setBackgroundColor(context.getResources().getColor(R.color.transparent)); selectItems.remove(item); }else { item.setCheck(true ); topHolder.item.setTextColor(context.getResources().getColor(baseListDialogFragment.getSelectItemTextColor())); topHolder.item.setBackgroundColor(context.getResources().getColor(baseListDialogFragment.getSelectItemBackgoundColor())); selectItems.add(item); } } itemClickListener.click(item,baseListDialogFragment); } } }); } else { leftHolder = (LeftHolder) holder; leftHolder.item.setText(item.getTitle()); leftHolder.item.setCompoundDrawablesWithIntrinsicBounds(leftHolder.icon(item.getIcon()), null , null , null ); leftHolder.item.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { if (itemClickListener != null ) { if (multipleChoice){ if (item.isCheck()){ item.setCheck(false ); leftHolder.item.setTextColor(context.getResources().getColor(baseListDialogFragment.getItemTextColor())); leftHolder.item.setBackgroundColor(context.getResources().getColor(R.color.transparent)); selectItems.remove(item); }else { item.setCheck(true ); leftHolder.item.setTextColor(context.getResources().getColor(baseListDialogFragment.getSelectItemTextColor())); leftHolder.item.setBackgroundColor(context.getResources().getColor(baseListDialogFragment.getSelectItemBackgoundColor())); selectItems.add(item); } } itemClickListener.click(item,baseListDialogFragment); } } }); } }
添加数据源和适配器,设置recyclerview的layoutmanager,水平和垂直列表使用LinearLayoutManager,网格列表使用GridLayoutManager。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public void addItems (List<Item> items, RecyclerView dialog_list) { LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); RecyclerView.LayoutManager manager; dialogListAdapter = new DialogListAdapter(getActivity().getApplicationContext(), items, orientation,getMultipleChoice(),this ); dialogListAdapter.setOrientation(orientation); dialogListAdapter.setItemClick(onItemClickListener); dialogListAdapter.setRowNum(getRowNum()); if (orientation == HORIZONTAL) manager = new LinearLayoutManager(getActivity().getApplicationContext(), LinearLayoutManager.HORIZONTAL, false ); else if (orientation == GRID) manager = new GridLayoutManager(getActivity().getApplicationContext(), getRowNum()); else manager = new LinearLayoutManager(getActivity().getApplicationContext(), LinearLayoutManager.VERTICAL, false ); dialog_list.setLayoutParams(params); dialog_list.setLayoutManager(manager); dialog_list.setAdapter(dialogListAdapter); }
初始化弹窗设置ui和监听:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 @Override protected Dialog setDialog (View view) { Dialog dlg; dlg= new Dialog(getActivity(), animation); dlg.setContentView(view); setCancelable(true ); dlg.setCanceledOnTouchOutside(true ); dlg.getWindow().setGravity(getGravity()); dlg.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT); RelativeLayout rl_title= (RelativeLayout) view.findViewById(R.id.rl_title); if (getTitleBarColor()!= DEFAULT_COLOR){ rl_title.setBackgroundColor(getResources().getColor(getTitleBarColor())); } TextView text_list_title = (TextView) view.findViewById(R.id.text_list_title); text_list_title.setText(getListTitleText()); if (getListTitleColor() != DEFAULT_COLOR) { text_list_title.setTextColor(getResources().getColor(getListTitleColor())); } if (getMultipleChoice()){ TextView text_list_sure = (TextView) view.findViewById(R.id.text_list_sure); TextView text_list_back = (TextView) view.findViewById(R.id.text_list_back); text_list_sure.setText(getSureText()); text_list_back.setText(getBackText()); text_list_back.setVisibility(View.VISIBLE); text_list_sure.setVisibility(View.VISIBLE); if (getBackTextTitleColor() != DEFAULT_COLOR) { text_list_sure.setTextColor(getResources().getColor(getSureTextTitleColor())); } if (getSureTextTitleColor() != DEFAULT_COLOR) { text_list_back.setTextColor(getResources().getColor(getBackTextTitleColor())); } text_list_sure.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { clickListener.clickSure(dialogListAdapter.getSelectItems()); dismiss(); } }); text_list_back.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { clickListener.clickBack(); dismiss(); } }); } RecyclerView dialog_list = (RecyclerView) view.findViewById(R.id.dialog_list); if (getListColor()!=DEFAULT_COLOR){ dialog_list.setBackgroundColor(getResources().getColor(getListColor())); } addItems(getDataList(), dialog_list); return dlg; }
抽象自定义ui方法,待子类实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public abstract String getListTitleText () ; public abstract String getBackText () ; public abstract String getSureText () ; public abstract int getListTitleColor () ; public abstract int getBackTextTitleColor () ; public abstract int getSureTextTitleColor () ; public abstract boolean getMultipleChoice () ; public abstract int getGravity () ; public abstract int getTitleBarColor () ; public abstract List<Item> getDataList () ; public abstract int getListColor () ; public abstract int getRowNum () ; public abstract int getItemTextColor () ; public abstract int getSelectItemTextColor () ; public abstract int getSelectItemBackgoundColor () ;
同样,封装一个列表窗子类,传入布局文件,这里也可以根据需求自己做扩展,传入不同的布局文件,但要保证控件id相同。
1 2 3 4 5 6 7 8 public static LoadDialogFragment newInstance () { LoadDialogFragment fragment=new LoadDialogFragment(); Bundle bundle = new Bundle(); bundle.putInt(TAG_ARG, R.layout.dialog_load); fragment.setArguments(bundle); return fragment; }
列表窗效果图: 垂直列表 网格列表 水平列表 布局文件是同一个,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:layout_width ="match_parent" android:layout_height ="wrap_content" android:orientation ="vertical" > <RelativeLayout android:id ="@+id/rl_title" android:layout_width ="match_parent" android:layout_height ="45dp" > <TextView android:id ="@+id/text_list_back" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:text ="取消" android:layout_marginLeft ="12dp" android:layout_centerVertical ="true" android:layout_alignParentLeft ="true" android:visibility ="gone" android:textColor ="@color/colorAccent" android:textSize ="14sp" /> <TextView android:id ="@+id/text_list_title" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_centerHorizontal ="true" android:text ="分享到" android:layout_centerInParent ="true" android:textColor ="@color/black" android:textSize ="16sp" /> <TextView android:id ="@+id/text_list_sure" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:text ="确认" android:layout_marginRight ="12dp" android:layout_centerVertical ="true" android:layout_alignParentRight ="true" android:textColor ="@color/colorAccent" android:visibility ="gone" android:textSize ="14sp" /> <ImageView android:layout_alignParentBottom ="true" android:layout_width ="match_parent" android:src ="@color/default_line" android:layout_height ="1px" /> </RelativeLayout > <android.support.v7.widget.RecyclerView android:id ="@+id/dialog_list" android:background ="@color/white" android:layout_width ="match_parent" android:layout_height ="wrap_content" > </android.support.v7.widget.RecyclerView > </LinearLayout >
也是向外暴露ui设置和接口,具体代码这里就不贴了。
列表弹窗的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 List<Item> items = new ArrayList<>(); items.add(new Item(1 , "通讯录" , getResources().getDrawable(R.mipmap.icon_content_phone))); items.add(new Item(2 , "好友" , getResources().getDrawable(R.mipmap.icon_friend))); items.add(new Item(3 , "朋友圈" , getResources().getDrawable(R.mipmap.icon_moments))); items.add(new Item(4 , "微信" , getResources().getDrawable(R.mipmap.icon_wechat))); items.add(new Item(5 , "微博" , getResources().getDrawable(R.mipmap.icon_weibo))); ListDialogFragment.newInstance(orientation) .setListTitleText("分享到" ) .setListTitleColor(R.color.black) .setBackText("返回" ) .setSureText("确定" ) .setRowNum(3 ) .setBackTextTitleColor(R.color.colorAccent) .setSureTextTitleColor(R.color.colorAccent) .setItems(items) .setTitleBarColor(R.color.white) .setListColor(R.color.white) .setItemTextColor(R.color.black) .setMultipleChoice(multipleChoice) .setSelectBackgroundColor(R.color.white) .setSelectItemTextColor(R.color.colorAccent) .setGravity(gravity) .setClickListener(new BaseListDialogFragment.ClickListener() { @Override public void clickSure (List<Item> selectItems) { if (selectItems.size()>0 ){ String selectStr="" ; Iterator<Item> it=selectItems.iterator(); while (it.hasNext()){ selectStr+=" " +it.next().getTitle(); } Toast.makeText(context, "选择了" +selectStr, Toast.LENGTH_SHORT).show(); }else { Toast.makeText(context, "点击了确定" , Toast.LENGTH_SHORT).show(); } } @Override public void clickBack () { Toast.makeText(context, "点击了取消" , Toast.LENGTH_SHORT).show(); } }) .setOnItemClickListener(new DialogListAdapter.OnItemClickListener() { @Override public void click (Item item, BaseListDialogFragment baseListDialogFragment) { Toast.makeText(context, item.getTitle(), Toast.LENGTH_SHORT).show(); if (!multipleChoice){ baseListDialogFragment.dismiss(); } } }) .setDialogAnimation(animation) .showDialog(getFragmentManager());
到此,弹窗工具类就封装完成了~源码传送门 。