Toas
Android中的Toast是一种简易的消息提示框。
基本吐司
基本Toast的使用如下所示:
Toast.makeText(MainActivity.this, "按钮被单击", Toast.LENGTH_SHORT).show();
Toast默认的位置在于屏幕的下方居中的位置,如果想改变Toast的位置则可以设置Gravity:
Toast toast = Toast.makeText(this, "当前已是最新版本", Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
自定义吐司
在Android中还可以自定义吐司,来改变吐司的显示位置和存在的时间等。
private void showMyToast(String address) {
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
View view = View.inflate(this, R.layout.total_address, null);
TextView tv_address = (TextView) view.findViewById(R.id.tv_address);
tv_address.setText(address);
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.format = PixelFormat.TRANSLUCENT;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
wm.addView(view, params);
}
注意:在自定义Tost使用完后必须调用WindowManager的removeView(view)来释放资源。
Toast工具类
Toast一般要求在主线程执行,所以我们可以编写工具类对Toast所在线程进行判断,然后执行相应的操作。
public class ToastUtils {
private static final String TAG = "ToastUtil";
public static void showToast(final Activity context, final String messages) {
if ("main".equals(Thread.currentThread().getName())) {
Toast.makeText(context, messages, Toast.LENGTH_LONG).show();
} else {
context.runOnUiThread(() -> Toast.makeText(context, messages, Toast.LENGTH_LONG).show());
}
}
}
PopupWindow
PopupWindow,顾名思义弹窗。PopupWindow是与AlertDialog在形式上类似的弹窗功能,都是为了在activity最上层显示一个弹窗.但是区别是PopupWindow可以自定义出现的位置,并且可以添加入自己需要的View或者导入自己写好的xml布局。
TextView textView = new TextView(MainActivity.this);
textView.setText("测试文本");
PopupWindow popupWindow = new PopupWindow(textView, 200, 300);//参数为1.View 2.宽度 3.高度
popupWindow.setOutsideTouchable(true); //设置点击外部区域可以取消popupWindow
mTestButton = (Button)findViewById(R.id.test_btn);
mTestButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//设置popupWindow显示,并且告诉它显示在那个View下面
popupWindow.showAsDropDown(mTestButton);
}
});
使用详解
常用函数
PopupWindow常用的构造函数如下所示:
public PopupWindow (Context context)
public PopupWindow(View contentView, int width, int height)
public PopupWindow(View contentView)
public PopupWindow(View contentView, int width, int height, boolean focusable)
PopupWindow常用的方法如下所示:
setContentView(View contentView):设置PopupWindow显示的View
getContentView():获得PopupWindow显示的View
setTouchable(true):设置PopupWindow可触摸
setOutsideTouchable(boolean touchable):设置外部点击退出
showAsDropDown(View anchor):相对某个控件的位置(正左下方),无偏移
showAsDropDown(View anchor, int xoff, int yoff):相对某个控件的位置,有偏移
showAtLocation(View parent, int gravity, int x, int y): 相对于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以设置偏移或无偏移 PS:parent这个参数只要是activity中的view就可以了!
setWidth/setHeight:设置宽高,也可以在构造方法那里指定好宽高, 除了可以写具体的值,还可以用WRAP_CONTENT或MATCH_PARENT, popupWindow的width和height属性直接和第一层View相对应。
setFocusable(true):设置焦点,设置焦点后,如果返回按下返回键,不会直接退出当前activity而是先退出当前的PopupWindow。
setAnimationStyle(int):设置动画效果
其中设置PopupWindow的显示方法有两种方式,分别是:showAsDropDown()和showAtLocation()
位置显示
showAtLocation()显示View的内部在指定位置(),它有两个方法的重载:
public void showAtLocation(View parent, int gravity, int x, int y)
public void showAtLocation(IBinder token, int gravity, int x, int y)
showAsDropDown()显示在一个参照物View的外部周围,有三个方法重载,这里参照物View的周围,使用这个方法是无法在View的内部找到锚点,它的锚点都是围绕者View的外部四周
public void showAsDropDown(View anchor)
public void showAsDropDown(View anchor, int xoff, int yoff)
public void showAsDropDown(View anchor, int xoff, int yoff, int gravity)
带Gravity参数的方法是API 19新引入的。这里的xoff与yoff是对应view的坐标偏移量,对应的初始坐标位置是view的左下角。
适配问题
解决Android7.0调用showAsDropDown方法失效问题:
原理是重写showAsDropDown,将PopupWindow对话框的高度设置成整个屏幕这么大,然后在减去这View指定的底部坐标值。
@Override
public void showAsDropDown(View anchor) {
if(Build.VERSION.SDK_INT >= 24) {
Rect rect = new Rect();
anchor.getGlobalVisibleRect(rect);
DisplayMetrics outMetrics = new DisplayMetrics();
Context context = anchor.getContext();
((Activity) context).getWindowManager().getDefaultDisplay().getRealMetrics(outMetrics);
int h = outMetrics.heightPixels - rect.bottom;
setHeight(h);
}
super.showAsDropDown(anchor);
}
对话框
Android中提供了种类丰富的对话框:
名称 | 描述 |
---|---|
AlertDialog | 功能最丰富、实际使用最广的对话框 |
ProgressDialog | 进度对话框,这个对话框支持简单进度条的封装 |
DatePickDialog | 日期选择对话框,该对话框只是对DatePicker的包装 |
TimePickDialog | 时间选择对话框,该对话框只是对TimePick的包装 |
除上表列出的对话框外,我们还可以进行自定义对话框。
常用对话框
1、确定取消对话框
AlertDialog.Builder builder = new Builder(this);
builder.setTitle("友情提醒");
builder.setMessage("若练此功,必先自宫,是否继续?");
builder.setPositiveButton("好的,想好了", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "啊。。。", 0).show();
Toast.makeText(MainActivity.this, "即使自宫,也不一定成功", 0).show();
}
});
builder.setNegativeButton("想想再说", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "若不自宫,一定不成功", 0).show();
}
});
builder.create().show();
2、单选对话框
AlertDialog.Builder builder = new Builder(this);
builder.setTitle("请选择性别:");
final String[] items = { "男", "女", "未知" };
builder.setSingleChoiceItems(items, 2, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
Toast.makeText(MainActivity.this, "您的性别:" + items[which], 0).show();
}
});
builder.show();
3、多选对话框
AlertDialog.Builder builder = new Builder(this);
builder.setTitle("请选择您喜欢的水果:");
final String[] items = { "苹果", "香蕉", "葡萄", "橘子" };
final boolean[] result = new boolean[] { true, true, false, false };
builder.setMultiChoiceItems(items, result,
new OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
result[which] = isChecked;
Toast.makeText(MainActivity.this,items[which] + isChecked, 0).show();
}
});
builder.setPositiveButton("提交", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < result.length; i++) {
if (result[i])
sb.append(items[i] + ",");
}
Toast.makeText(MainActivity.this, "您喜欢:" + sb.toString(), 0).show();
}
});
builder.show();
4、进度对话框
final ProgressDialog pd = new ProgressDialog(this);
pd.setTitle("提醒");
pd.setMessage("正在处理中。。。请稍后");
pd.show();
new Thread() {
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
pd.dismiss();
};
}.start();
5、进度条对话框
final ProgressDialog pd = new ProgressDialog(this);
// 设置进度的样式
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setTitle("提醒");
pd.setMessage("正在处理中。。。请稍后");
pd.show();
new Thread() {
public void run() {
pd.setMax(100);
try {
for (int i = 0; i <= 100; i++) {
pd.setProgress(i);
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
pd.dismiss();
};
}.start();
样式对话框
基本对话框
在Android中可以对对话框进行简单的定制,代码如下:
Builder builder = new Builder(this);
View view = View.inflate(this, R.layout.item_dialog, null);
final AlertDialog dialog = builder.create();
dialog.setView(view, 0, 0, 0, 0);
dialog.show();
Button btn_ok = (Button) view.findViewById(R.id.btn_item_ok);
Button btn_cancel = (Button) view.findViewById(R.id.btn_item_cancel);
btn_ok.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "确认对话框被按下", 0).show();
dialog.dismiss();
}
});
btn_cancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "取消对话框被按下", 0).show();
dialog.dismiss();
}
});
底部弹出对话框
除了自定义布局文件外,还可以对弹出位置进行修改
View view = getLayoutInflater().inflate(R.layout.photo_choose_dialog, null);
dialog = new Dialog(this, R.style.transparentFrameWindowStyle);
dialog.setContentView(view, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
Window window = dialog.getWindow();
window.setWindowAnimations(R.style.main_menu_animstyle);
WindowManager.LayoutParams wl = window.getAttributes();
wl.x = 0;
wl.y = getWindowManager().getDefaultDisplay().getHeight();
wl.width = ViewGroup.LayoutParams.MATCH_PARENT;
wl.height = ViewGroup.LayoutParams.WRAP_CONTENT;
dialog.onWindowAttributesChanged(wl);
dialog.setCanceledOnTouchOutside(false);
dialog.show();
// 初始化
Button btnCamera = (Button) view.findViewById(R.id.btn_phonedialog_camera);
Button btnPhoto = (Button) view.findViewById(R.id.btn_phonedialog_photo);
Button btnCancel = (Button) view.findViewById(R.id.btn_phonedialog_cancel);
btnCamera.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
btnPhoto.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
btnCancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
其中使用到的样式
<style name="transparentFrameWindowStyle" parent="android:style/Theme.Dialog">
<item name="android:windowBackground">@drawable/photo_choose_bg</item>
</style>
<style name="main_menu_animstyle">
<item name="android:windowEnterAnimation">@anim/photo_dialog_in_anim</item>
<item name="android:windowExitAnimation">@anim/photo_dialog_out_anim</item>
</style>
使用到的布局文件如下:
<?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:background="#00000000"
android:gravity="bottom"
android:orientation="vertical"
android:padding="5dip" >
<Button
android:id="@+id/btn_phonedialog_camera"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/photo_gallery_selector"
android:paddingBottom="10dip"
android:paddingTop="10dip"
android:text="拍照"
android:textSize="16sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="0.5dip"
android:background="#DAD9DB" />
<Button
android:id="@+id/btn_phonedialog_photo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/photo_camera_selector"
android:paddingBottom="10dip"
android:paddingTop="10dip"
android:text="从手机相册选择"
android:textSize="16sp" />
<Button
android:id="@+id/btn_phonedialog_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dip"
android:background="@drawable/photo_cancel_selector"
android:paddingBottom="10dip"
android:paddingTop="10dip"
android:text="取消"
android:textSize="16sp" />
</LinearLayout>
全局对话框
写好Alert功能块后,在altet.show()语句前加入:
alert.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
使用到的权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"></uses-permission>
如果只在Service中写入常在Activity中使用的创建Alert的代码,运行时是会发生错误的,因为Alter的显示需要依附于一个确定的 Activity类。而以上做法就是声明我们要弹出的这个提示框是一个系统的提示框,即全局性质的提示框,所以只要手机处于开机状态,无论它现在处于何种 界面之下,只要调用alter.show(),就会弹出提示框来。
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Are you sure you want to exit?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
MyActivity.this.finish();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
alert.show();
自定义对话框
1、 在theme.xml或style.xml中定义对话框的样式:
<style name="CustomDialog">
<!-- alertDialog窗口背景色 -->
<item name="android:windowBackground">@android:color/transparent</item>
<!--dialog是否有边框-->
<item name="android:windowFrame">@null</item>
<!--dialog是否有标题-->
<item name="android:windowNoTitle">true</item>
<!--是否浮现在activity之上-->
<item name="android:windowIsFloating">true</item>
<!--是否半透明-->
<item name="android:windowIsTranslucent">true</item>
<!--是否有遮盖(eg.Activity的闪屏页)-->
<item name="android:windowContentOverlay">@null</item>
<!--进出动画-->
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
<!--背景是否模糊显示-->
<item name="android:backgroundDimEnabled">true</item>
</style>
2、创建自定义的对话框继承自Dialog,并在构造函数中配置相关参数:
public class GeneralDialog extends Dialog {
private Context mContext;
@BindView(R.id.title)
TextView mTvTitle;
@BindView(R.id.confirm)
Button mBtnConfirm;
@BindView(R.id.cancel)
Button mBtnCancel;
private OnGeneralClickListener mListener;
public GeneralDialog(Context context) {
super(context, R.style.CustomDialog);
this.mContext = context;
View view = View.inflate(mContext, R.layout.dialog_genera_layout, null);
ButterKnife.bind(this, view);
setContentView(view);
// Init Dialog
setCanceledOnTouchOutside(true);
setCancelable(true);
WindowManager.LayoutParams params = this.getWindow().getAttributes();
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.gravity = Gravity.CENTER;
this.getWindow().setAttributes(params);
// Init Event
mBtnConfirm.setOnClickListener(v -> {
if (mListener != null)
mListener.onConfirmClick(v);
});
mBtnCancel.setOnClickListener(v -> {
if (mListener != null)
mListener.onCancelClick(v);
});
}
public void setCustomTitle(int titleStr){
mTvTitle.setText(titleStr);
}
public void setOnGeneralClickListener(OnGeneralClickListener listener){
this.mListener = listener;
}
public interface OnGeneralClickListener{
void onConfirmClick(View view);
void onCancelClick(View view);
}
}
3、如果想让对话框的宽度能铺满全屏,可以做如下设置
setCanceledOnTouchOutside(true);
setCancelable(true);
WindowManager.LayoutParams params = this.getWindow().getAttributes();
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
params.y = DensityUtils.dip2px(context, 145);
this.getWindow().setAttributes(params);
this.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
4、使用自定义对话框代码如下:
GeneralDialog generalDialog = new GeneralDialog(SplashActivity.this);
generalDialog.setCustomTitle(R.string.text_splash_network_desc);
generalDialog.setOnGeneralClickListener(new GeneralDialog.OnGeneralClickListener() {
@Override
public void onConfirmClick(View view) {
startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
generalDialog.dismiss();
}
@Override
public void onCancelClick(View view) {
requestPermission();
generalDialog.dismiss();
}
});
generalDialog.show();