這次還是帶來一個Android仿Ios風格的控件。Ios裏有個控件叫ActionSheet,就是那種從下往上彈出的選項卡,比如下面這個效果:
UI在設計效果圖的時候,添加圖片、選擇性別之類的功能經常會這麼設計,ios那邊有個ActionSheet可以用,android這邊就比較麻煩了(有時候會感嘆ios的一些控件確實要比android封裝得更徹底)於是就自己封裝了一個,名字也叫ActionSheet。控件其實是很久以前寫的,現在拿出來跟大家分享一下。話不多說,正片開始。
首先這個控件繼承自Dialog,需要先定義一個style和彈入彈出的動畫。首先在res目錄下新建一個anim文件夾,並在這個文件夾下新建兩個動畫文件
actionsheet_in.xml和 actionsheet_out,xml,如下:
actionsheet_in.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:fromYDelta="100%"
android:toYDelta="0" />
actionsheet_out.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:fromYDelta="0"
android:toYDelta="100%" />
然後就定義一個style並綁定這兩個動畫。在styles文件先添加以下內容:
<style name="ActionSheetStyle" parent="@android:style/Theme.Dialog">
<!-- 背景透明 -->
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<!-- 浮於Activity之上 -->
<item name="android:windowIsFloating">true</item>
<!-- 邊框 -->
<item name="android:windowFrame">@null</item>
<!-- Dialog以外的區域模糊效果 -->
<item name="android:backgroundDimEnabled">true</item>
<!-- 無標題 -->
<item name="android:windowNoTitle">true</item>
<!-- 半透明 -->
<item name="android:windowIsTranslucent">true</item>
<!-- Dialog進入及退出動畫 -->
<item name="android:windowAnimationStyle">@style/ActionSheetAnimation</item>
</style>
<!-- ActionSheet進出動畫 -->
<style name="ActionSheetAnimation" parent="@android:style/Animation.Dialog">
<item name="android:windowEnterAnimation">@anim/actionsheet_in</item>
<item name="android:windowExitAnimation">@anim/actionsheet_out</item>
</style>
然後是最麻煩的地方,定義背景資源文件,一共12個(沒辦法,好看是有代價的 >_<)。在drawable目錄下創建以下12個資源文件:
dialog_bottom_up.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#e3ffffff" />
<corners
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp" />
</shape>
dialog_bottom_down.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#e3eeeeee" />
<corners
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp" />
</shape>
dialog_bottom_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/dialog_bottom_up" android:state_pressed="false"></item>
<item android:drawable="@drawable/dialog_bottom_down" android:state_pressed="true"></item>
</selector>
dialog_top_up.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#e3ffffff" />
<corners
android:topLeftRadius="10dp"
android:topRightRadius="10dp" />
</shape>
dialog_top_down.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#e3eeeeee" />
<corners
android:topLeftRadius="10dp"
android:topRightRadius="10dp" />
</shape>
dialog_top_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/dialog_top_up" android:state_pressed="false"></item>
<item android:drawable="@drawable/dialog_top_down" android:state_pressed="true"></item>
</selector>
dialog_white_up.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#e3ffffff" />
<corners android:radius="10dp" />
</shape>
dialog_white_down.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#e3eeeeee" />
</shape>
dialog_white_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/dialog_white_up" android:state_pressed="false"></item>
<item android:drawable="@drawable/dialog_white_down" android:state_pressed="true"></item>
</selector>
layout_white_up.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#e3ffffff" />
</shape>
layout_white_down.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#e3eeeeee" />
</shape>
layout_white_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/layout_white_up" android:state_pressed="false"></item>
<item android:drawable="@drawable/layout_white_down" android:state_pressed="true"></item>
</selector>
終於搞好了,好麻煩的說。接下來就可以上ActionDialog的本體了,如下:
ActionDialog.java:
public class ActionSheet extends Dialog {
private Context context;
private LinearLayout parentLayout;
private TextView titleTextView;
private ArrayList<Button> sheetList;
private Button cancelButton;
// 標題
private String title;
//就取消按鈕文字
private String cancel;
// 選擇項文字列表
private ArrayList<String> 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<View.OnClickListener> 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:
<?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="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="10dp"
android:text="SHOW SHEET" />
</LinearLayout>
簡單的說一下,調用方法之前已經說了,其中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一下,搞定。
最後附上源碼地址:點擊打開鏈接
這次的內容就到這裏,我們下次再見。