这次还是带来一个Android仿Ios风格的控件。Ios里有个控件叫ActionSheet,就是那种从下往上弹出的选项卡,比如下面这个效果:
UI在设计效果图的时候,添加图片、选择性别之类的功能经常会这么设计,ios那边有个ActionSheet可以用,android这边就比较麻烦了(有时候会感叹ios的一些控件确实要比android封装得更彻底)于是就自己封装了一个,名字也叫ActionSheet。控件其实是很久以前写的,现在拿出来跟大家分享一下。话不多说,正片开始。
首先这个控件继承自Dialog,需要先定义一个style和弹入弹出的动画。首先在res目录下新建一个anim文件夹,并在这个文件夹下新建两个动画文件
actionsheet_in.xml和 actionsheet_out,xml,如下:
actionsheet_in.xml文件:
actionsheet_out.xml文件:
然后就定义一个style并绑定这两个动画。在styles文件先添加以下内容:
然后是最麻烦的地方,定义背景资源文件,一共12个(没办法,好看是有代价的 >_<)。在drawable目录下创建以下12个资源文件:
dialog_bottom_up.xml:
dialog_bottom_down.xml:
dialog_bottom_selector.xml:
dialog_top_up.xml:
dialog_top_down.xml:
dialog_top_selector.xml:
dialog_white_up.xml:
dialog_white_down.xml:
dialog_white_selector.xml:
layout_white_up.xml:
layout_white_down.xml:
layout_white_selector.xml:
终于搞好了,好麻烦的说。接下来就可以上ActionDialog的本体了,如下:
ActionDialog.java:
public class ActionSheet extends Dialog {
private Context context;
private LinearLayout parentLayout;
private TextView titleTextView;
private ArrayList sheetList;
private Button cancelButton;
// 标题
private String title;
//就取消按钮文字
private String cancel;
// 选择项文字列表
private ArrayList sheetTextList;
// 标题颜色
private int titleTextColor;
// 取消按钮文字颜色
private int cancelTextColor;
// 选择项文字颜色
private int sheetTextColor;
// 标题大小
private int titleTextSize;
// 取消按钮文字大小
private int cancelTextSize;
// 选择项文字大小
private int sheetTextSize;
// 标题栏高度
private int titleHeight;
// 取消按钮高度
private int cancelHeight;
// 选择项高度
private int sheetHeight;
// 弹出框距离底部的高度
private int marginBottom;
// 取消按钮点击回调
private View.OnClickListener cancelListener;
// 选择项点击回调列表
private ArrayList sheetListenerList;
public ActionSheet(Context context) {
super(context, R.style.ActionSheetStyle);
init(context);
}
public ActionSheet(Context context, int theme) {
super(context, theme);
init(context);
}
private void init(Context context) {
this.context = context;
cancel = "取消";
titleTextColor = Color.parseColor("#aaaaaa");
cancelTextColor = Color.parseColor("#666666");
sheetTextColor = Color.parseColor("#666666");
titleTextSize = 14;
cancelTextSize = 16;
sheetTextSize = 16;
titleHeight = dp2px(40);
cancelHeight = dp2px(40);
sheetHeight = dp2px(40);
marginBottom = dp2px(10);
sheetList = new ArrayList<>();
sheetTextList = new ArrayList<>();
sheetListenerList = new ArrayList<>();
}
private ActionSheet createDialog() {
parentLayout = new LinearLayout(context);
parentLayout.setBackgroundColor(Color.parseColor("#00000000"));
parentLayout.setOrientation(LinearLayout.VERTICAL);
if (title != null) {
titleTextView = new TextView(context);
titleTextView.setGravity(Gravity.CENTER);
titleTextView.setText(title);
titleTextView.setTextColor(titleTextColor);
titleTextView.setTextSize(titleTextSize);
titleTextView.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.dialog_top_up));
LinearLayout.LayoutParams titleLayoutParams = new LinearLayout.LayoutParams
(ViewGroup.LayoutParams.MATCH_PARENT, titleHeight);
parentLayout.addView(titleTextView, titleLayoutParams);
}
for (int i = 0; i < sheetTextList.size(); i++) {
if (i == 0 && title != null) {
View topDividerLine = new View(context);
topDividerLine.setBackgroundColor(Color.parseColor("#eeeeee"));
parentLayout.addView(topDividerLine, new LinearLayout
.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(1)));
}
Button button = new Button(context);
button.setGravity(Gravity.CENTER);
button.setText(sheetTextList.get(i));
button.setTextColor(sheetTextColor);
button.setTextSize(sheetTextSize);
if (title != null) {
if (i == sheetTextList.size() - 1) {
button.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.dialog_bottom_selector));
} else {
button.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.layout_white_selector));
}
} else {
if (sheetTextList.size() == 1) {
button.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.dialog_white_selector));
} else {
if (i == 0) {
button.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.dialog_top_selector));
} else if (i == sheetTextList.size() - 1) {
button.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.dialog_bottom_selector));
} else {
button.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.layout_white_selector));
}
}
}
button.setOnClickListener(sheetListenerList.get(i));
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams
(ViewGroup.LayoutParams.MATCH_PARENT, sheetHeight);
parentLayout.addView(button, layoutParams);
sheetList.add(button);
if (i != sheetTextList.size() - 1) {
View bottomDividerLine = new View(context);
bottomDividerLine.setBackgroundColor(Color.parseColor("#eeeeee"));
parentLayout.addView(bottomDividerLine, new LinearLayout
.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(1)));
}
}
cancelButton = new Button(context);
cancelButton.setGravity(Gravity.CENTER);
cancelButton.setText(cancel);
cancelButton.setTextColor(cancelTextColor);
cancelButton.setTextSize(cancelTextSize);
cancelButton.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.dialog_white_selector));
cancelButton.setOnClickListener(cancelListener);
LinearLayout.LayoutParams cancelParams = new LinearLayout.LayoutParams
(ViewGroup.LayoutParams.MATCH_PARENT, cancelHeight);
cancelParams.setMargins(0, dp2px(10), 0, 0);
parentLayout.addView(cancelButton, cancelParams);
getWindow().setGravity(Gravity.BOTTOM);
getWindow().getAttributes().y = marginBottom;
show();
setContentView(parentLayout);
setCancelable(true);
setCanceledOnTouchOutside(true);
return this;
}
private void addSheet(String text, View.OnClickListener listener) {
sheetTextList.add(text);
sheetListenerList.add(listener);
}
public void setCancel(String text) {
this.cancel = text;
}
public void setCancelHeight(int height) {
this.cancelHeight = dp2px(height);
}
public void setCancelTextColor(int color) {
this.cancelTextColor = color;
}
public void setCancelTextSize(int textSize) {
this.cancelTextSize = textSize;
}
public void setSheetHeight(int height) {
this.sheetHeight = dp2px(height);
}
public void setSheetTextColor(int color) {
this.sheetTextColor = color;
}
public void setSheetTextSize(int textSize) {
this.sheetTextSize = textSize;
}
public void setTitle(String text) {
this.title = text;
}
public void setTitleHeight(int height) {
this.titleHeight = height;
}
public void setTitleTextColor(int color) {
this.titleTextColor = color;
}
public void setTitleTextSize(int textSize) {
this.titleTextSize = textSize;
}
public void setMargin(int bottom) {
this.marginBottom = dp2px(bottom);
}
public void addCancelListener(View.OnClickListener listener) {
this.cancelListener = listener;
}
private int dp2px(float dipValue) {
float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
public static class DialogBuilder {
ActionSheet dialog;
public DialogBuilder(Context context) {
dialog = new ActionSheet(context);
}
/**
* 添加一个选择项
* @param text 选择项文字
* @param listener 选择项点击回调监听
* @return 当前DialogBuilder
*/
public DialogBuilder addSheet(String text, View.OnClickListener listener) {
dialog.addSheet(text, listener);
return this;
}
/**
* 设置取消按钮文字
* @param text 文字内容
* @return 当前DialogBuilder
*/
public DialogBuilder setCancel(String text) {
dialog.setCancel(text);
return this;
}
/**
* 设置取消按钮高度
* @param height 高度值,单位dp
* @return 当前DialogBuilder
*/
public DialogBuilder setCancelHeight(int height) {
dialog.setCancelHeight(height);
return this;
}
/**
* 设置取消按钮文字颜色
* @param color 颜色值
* @return 当前DialogBuilder
*/
public DialogBuilder setCancelTextColor(int color) {
dialog.setCancelTextColor(color);
return this;
}
/**
* 设置取消按钮文字大小
* @param textSize 大小值,单位sp
* @return 当前DialogBuilder
*/
public DialogBuilder setCancelTextSize(int textSize) {
dialog.setCancelTextSize(textSize);
return this;
}
/**
* 设置选择项高度
* @param height 高度值,单位dp
* @return 当前DialogBuilder
*/
public DialogBuilder setSheetHeight(int height) {
dialog.setSheetHeight(height);
return this;
}
/**
* 设置选择项文字颜色
* @param color 颜色值
* @return 当前DialogBuilder
*/
public DialogBuilder setSheetTextColor(int color) {
dialog.setSheetTextColor(color);
return this;
}
/**
* 设置选择项文字大小
* @param textSize 大小值,单位sp
* @return 当前DialogBuilder
*/
public DialogBuilder setSheetTextSize(int textSize) {
dialog.setSheetTextSize(textSize);
return this;
}
/**
* 设置标题
* @param text 文字内容
* @return 当前DialogBuilder
*/
public DialogBuilder setTitle(String text) {
dialog.setTitle(text);
return this;
}
/**
* 设置标题栏高度
* @param height 高度值,单位dp
* @return 当前DialogBuilder
*/
public DialogBuilder setTitleHeight(int height) {
dialog.setTitleHeight(height);
return this;
}
/**
* 设置标题颜色
* @param color 颜色值
* @return 当前DialogBuilder
*/
public DialogBuilder setTitleTextColor(int color) {
dialog.setTitleTextColor(color);
return this;
}
/**
* 设置标题大小
* @param textSize 大小值,单位sp
* @return 当前DialogBuilder
*/
public DialogBuilder setTitleTextSize(int textSize) {
dialog.setTitleTextSize(textSize);
return this;
}
/**
* 设置弹出框距离底部的高度
* @param bottom 距离值,单位dp
* @return 当前DialogBuilder
*/
public DialogBuilder setMargin(int bottom) {
dialog.setMargin(bottom);
return this;
}
/**
* 设置取消按钮的点击回调
* @param listener 回调监听
* @return
*/
public DialogBuilder addCancelListener(View.OnClickListener listener) {
dialog.addCancelListener(listener);
return this;
}
/**
* 创建弹出框,放在最后执行
* @return 创建的 ActionSheet 实体
*/
public ActionSheet create() {
return dialog.createDialog();
}
}
}
稍微说一下,依然是建造者模式的写法,内部类DialogBuilder是一个建造器,调用的时候通过新建一个DialogBuilder实体,设置好想要的参数,最后调用其create方法就建造完成了。
最后的最后,终于可以用了!MainActivity.class和activity_main.xml贴上:
MainActivity.class:
public class MainActivity extends Activity {
private Button button;
private ActionSheet actionSheet;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
}
private void initData() {
}
private void initView() {
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showSheet();
}
});
}
private void showSheet() {
actionSheet=new ActionSheet.DialogBuilder(this)
.addSheet("雷军", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "当然是雷布斯!", Toast.LENGTH_SHORT).show();
actionSheet.dismiss();
}
})
.addSheet("马化腾", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "当然是小马哥!", Toast.LENGTH_SHORT).show();
actionSheet.dismiss();
}
})
.addSheet("马云", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "当然是马爸爸!", Toast.LENGTH_SHORT).show();
actionSheet.dismiss();
}
})
.addCancelListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "容我三思", Toast.LENGTH_SHORT).show();
actionSheet.dismiss();
}
})
.create();
}
}
activity_main.xml:
简单的说一下,调用方法之前已经说了,其中addSheet方法每调用一次就会添加一条选线栏,需要输入选项栏文字,和点击的回调监听,这里监听直接用的是View下的OnClickListener,是不是很亲切?顺带一提,取消按钮是默认存在的,所以务必设置一下addCancelListener,不然点击取消会没反应。
来看一下效果,运行走起!
控件支持添加标题栏,改变文字大小、颜色什么的,几行代码搞定,如下:
actionSheet=new ActionSheet.DialogBuilder(this)
...
.setTitle("你觉得以下谁最帅?")
.setCancel("容我三思")
.setTitleTextColor(Color.parseColor("#ff69b4"))
.setCancelTextColor(Color.parseColor("#aaaaaa"))
.setSheetTextColor(Color.parseColor("#1e90ff"))
...
.create();
再次运行,看一下效果:
是不是很简单?更多设置选项在控件源码里都已经注释清楚了,大家可以自己试一试。
总结一下控件的用法就是:new一个DialogBulder,根据需要set一堆东西有几个选项卡就调用几次addSheet ,最后create一下,搞定。
最后附上源码地址:点击打开链接
这次的内容就到这里,我们下次再见。