Android弹窗二则: PopupWindow和AlertDialog

前言

弹窗是图形界面必备的一个模块, 回忆一下windows那些恶心爆了的错误弹窗吧, 把弹窗制作的更高效友好一点是非常必要的. 这里说两个常用的弹窗类, PopupWindow和AlertDialog. 我的理解就是, PopupWindow较为随性, 可以在任意位置弹窗, 比如你经常看到的朋友圈点赞的那个小的弹窗. 那AlertDialog就很正经了, 位置固定在中央, 比如无比烦人的更新提示就是用的它, 大多数都是消息标题+内容+确定按钮+取消按钮. 好, 不多废话了.

为了保护你的眼睛, 图片已处理


PopupWindow

官方文档传送门

实例解析

先来看一段常规的PopupWindow的使用, 然后逐行分析下.

PopupWindow popupWindow = new PopupWindow();

popupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setContentView(View.inflate(this, R.layout.layout_popup, null));

popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));
popupWindow.setFocusable(true);
popupWindow.setOutsideTouchable(false);

popupWindow.setAnimationStyle(R.style.anim_menu_bottombar);

popupWindow.showAsDropDown(bt_popup, 0, 0);

解析:

  • 首先肯定是创建一个PopupWindow对象了, 当然, 它肯定还有许多带参数的构造方法, 而无参肯定是最好理解的那种.
  • 然后就是设置三连, 设置宽高, 设置布局View. 如果想要显示一个弹窗, 这三句话是必须的.
  • 然后popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));这个很有意思. 在高版本的android中(比如8.0), 实测可以不写, 但是低版本就不行了(比如4.1), 低版本不写的话, 会导致点击返回或者是屏幕其它地方无法取消弹窗, 所以稳妥起见还是加上, 并设置一个透明色.
  • popupWindow.setFocusable(true);是比较重要的, 一般都为true, 也就是弹窗之后, 焦点就到了弹窗, 你再点击其它地方, 弹窗失去焦点就会消失. popupWindow.setOutsideTouchable(false);这句在之前那句为true的前提下, true和false效果几乎一样.
  • 再往下是添加一个动画效果, 你可以用默认的, 或者自定义.
  • 最后一句显示弹窗, 默认对齐左下, 后面两个参数是偏移值, 应该很好理解啦. 然后我们来看一张效果图.

效果图


内容补充

RelativeLayout rl_content = (RelativeLayout) findViewById(R.id.rl_content);
popupWindow.showAtLocation(rl_content, Gravity.CENTER, 0, 0);

补充:

  • 显示还有一种方法, showAtLocation(). 举个栗子, 就是如上代码, 先获取一个布局, 然后设置Gravity.CENTER, 以及偏移量, 这样就会把弹窗设置到布局中心加上偏移量的一个位置.

AlertDialog

官方文档传送门

实例解析

解析:

  • 先来看一下Module中的build.gradle, 关键是compile 'com.android.support:appcompat-v7:25.3.1', 版本要确保大于22, 因为22中引入了Material Design风格的Dialog(5.0引入的Material Design), 当然, 如果你用Android Studio, 这点基本无需担心.
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
}

  • 再者下面两句是不同的, 第二种实例化方法会导致5.0前和5.0后风格不统一, 这里来两张效果图. 用API16的虚拟机.

android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app.AlertDialog.Builder(this);

AlertDialog.Builder builder = new AlertDialog.Builder(this);

右侧是Material Design风格

  • 好, 接下来进入正文. 我们构建一个最简单的弹窗. 当然, 以下代码可以浓缩成一行代码, 但是不够直观, 我更喜欢清晰一点的代码.
android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app.AlertDialog.Builder(this);

builder.setIcon(R.mipmap.ic_launcher);
builder.setTitle("title");
builder.setMessage("message");

builder.setPositiveButton("positive", null);
builder.setNegativeButton("negative", null);
builder.setNeutralButton("neutral", null);

builder.setCancelable(true);
android.support.v7.app.AlertDialog dialog = builder.create();
dialog.show();

举个栗子

  • 注意一点就是, setPositiveButton等函数第二个参数其实是监听器, 你可以如下操作.
builder.setPositiveButton("positive", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
        Toast.makeText(getApplicationContext(), "positive", Toast.LENGTH_SHORT).show();
    }
});

  • 这行builder.setCancelable(true);就是意思点击弹窗以外的部分可以取消弹窗, 设置false则不取消弹窗, 按需设置啦.

  • 然后就是AlertDialog是非常便于放入各种条目的, 比如单选和多选. 但是注意, 这之间会起冲突, 比如之前的builder.setMessage("message");和设置单选多选条目不能同时存在. 下方展示代码和效果图. 当然了, 监听我都没写, 按需求自己完成啦.
builder.setItems(new String[]{"1", "2", "3"}, null);
builder.setSingleChoiceItems(new String[]{"1", "2", "3"}, 2, null); //数字对应默认选中, 从0开始
builder.setMultiChoiceItems(new String[]{"1", "2", "3"}, new boolean[]{true, true, false}, null); //boolean数组对应勾选

普通条目展示

单选多选条目展示


内容补充

补充:

  • 我们现在来说一个比较复杂的, 也比较有意思的. 就是在弹窗中填充自定义view. 当然啦, 还有adapter的方法, 但是我暂时不打算在这次的文章中写, 因为用adapter的时候太多了, 可能要下次弄个单独的部分.

举个栗子

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <EditText
        android:id="@+id/et_account"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:ignore="TextFields" />

    <EditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/et_account"
        tools:ignore="TextFields" />

    <Button
        android:id="@+id/bt_cancel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_below="@id/et_password"
        android:text="@string/bt_cancel"
        tools:ignore="RtlHardcoded" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/et_password"
        android:layout_toLeftOf="@id/bt_cancel"
        android:text="@string/bt_login"
        tools:ignore="RtlHardcoded" />
</RelativeLayout>

  • 随便写个布局文件, 然后我们在java中加入如下一行. 要说的是, 大家仔细看效果图, 会发现自定义View可以和builder.setMessage("message");共存, 但事实上, 好像没有这个必要, 我故意把一些非自定义的也展示出来, 其实自定义View完全可以全部自己写.
builder.setView(View.inflate(this, R.layout.layout_login, null));

最后

喜欢记得点个赞了, 有意见或者建议可以评论区见哦, 当然啦, 暗中关注我也是可以的.


本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏积累沉淀

Java SWT事件

什么是事件?点击鼠标是一个事件,按下一个按钮也一个事件,关闭一个窗口也是一个事件。 什么是监听器?监听器就是监听事件什么时候发生的,用来控制事件发生的具体动...

2645
来自专栏郭霖

Android自定义View的实现方法,带你一步步深入了解View(四)

不知不觉中,带你一步步深入了解View系列的文章已经写到第四篇了,回顾一下,我们一共学习了LayoutInflater的原理分析、视图的绘制流程、视图的状态及重...

3019
来自专栏非著名程序员

教你步步为营掌握自定义ViewGroup

本篇是《教你步步为营掌握自定义View》一文的姊妹篇。自定义ViewGroup的文章很多,但都有一个缺点,没有回应用户关切,比如我在读那些文章时,就很想知道,自...

2196
来自专栏三好码农的三亩自留地

Android-教你写小米系统应用--"我的小米"

前面的文章中,我们已经了解了如何去自定义一个ViewGroup,可以在onLayout中自由的对子View进行位置设定,我们今天这里刚好需要对上面需求提到的三部...

1682
来自专栏开发之途

Android Drawable图解

1434
来自专栏Jack的Android之旅

NestedScrolling机制之CoordinatorLayout.Behavior实战

在上一讲中我们讲了NestedScrolling机制,其实android很多有些常用的控件都是支持NestedScrolling机制的,如RecyclerVie...

1101
来自专栏何俊林

两步集成TV移动框架,从未如此简单

导读:TV相关的资料网上相对来说少点,我早期写了七篇TV相关的开发总结,有开源了一些Demo,在我的github上,今天是单灿灿同学独家在本公众平台发布他最新开...

4875
来自专栏技术小黑屋

仿腾讯新闻样式的Toast

厌倦了网易新闻无处不在的喷子,尝试了一下腾讯新闻,果然顿时清净了很多,当然这不是重点。个人感觉腾讯新闻客户端的Toast比较不错,相对于系统默认的Toast,更...

973
来自专栏Android干货

Android项目实战(十):自定义倒计时的TextView

3286
来自专栏何俊林

如何优化你的布局层级结构之RelativeLayout和LinearLayout及FrameLayout性能分析(一)

工作一段时间后,经常会被领导说,你这个进入速度太慢了,竞品的进入速度很快,你搞下优化吧?每当这时,你会怎么办?功能实现都有啊,进入时要加载那么多view,这也没...

3919

扫码关注云+社区

领取腾讯云代金券