0%

利用dialogfragment封装弹窗工具类


android原生的dialog样式很不美观,大多数情况下,我们需要根据需求自定义弹窗的样式,而dialogfragment是官方推荐的对话框控件。
使用DialogFragment来管理对话框,当旋转屏幕和按下后退键时可以更好的管理其声明周期,它和Fragment有着基本一致的声明周期。屏幕旋转时,传统的dialog会报异常,而通过DialogFragment实现的对话框则可以完全不必考虑旋转的问题。且DialogFragment也允许开发者把Dialog作为内嵌的Fragment进行重用,可以在大屏幕和小屏幕显示出不同的效果。详情可以查看[鸿洋大神的博文][1]。
所以利用dialogfragment来封装常用的弹窗工具类再合适不过了,这里记录一下详细过程:


最终效果gif:
效果gif
这是封装好的lib库,上图
封装好的lib库截图
这里我们封装了常见的提示弹窗,选择列表弹窗(支持垂直列表,水平列表,网格列表,同时支持单选与多选),加载弹窗,三种模式。

封装dialog lib

新建一个项目,具体过程不描述了,新建一个module,选择android libiary,填写好相关信息后finish。

创建一个弹窗基类

继承DialogFragment创建一个弹窗基类BaseDialogFragment,以便做统一管理。
统一默认颜色,背景,以及图标。

1
2
3
4
protected int layout;//布局文件id
protected static final int DEFAULT_COLOR = -1; //default
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) {
//Step1 build Dialog
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");//显示一个Fragment并且给该Fragment添加一个Tag,可通过findFragme ntByTag找到该Fragment
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) {
//创建一个带有参数的Fragment实例
ListDialogFragment fragment = new ListDialogFragment();
fragment.orientation=orientation;
Bundle bundle = new Bundle();
bundle.putInt(TAG_ARG, R.layout.dialog_list);
fragment.setArguments(bundle);//把参数传递给该DialogFragment

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();


//设置加载进度图1
protected abstract int getLoadShape1();

//设置加载进度图2
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);//把参数传递给该DialogFragment

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());
// loadDialogFragment.dismiss();

封装选择列表窗

这里展示样式可以分为三种情况,水平,垂直以及网格列表,展示位置也有三种情况,顶部,中间,底部,选择模式可以分为两种情况,单选和多选。
创建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);//把参数传递给该DialogFragment

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());

到此,弹窗工具类就封装完成了~源码传送门