最全AltertDialog 你只需要这一篇就够了

简单介绍一下自己,大三学生党一枚!主攻Android开发,对于Web和后端均有了解。
个人语录取乎其上,得乎其中,取乎其中,得乎其下,以顶级态度写好一篇的博客。


AlertDialog在实际开发过程中经常用到,并且根据场景不同,设计的提示也大相径庭,前几天我遇到一个需求:弹出提示的同时播放铃声,本来以为很简单,过程跌宕起伏让人抓狂! 在这本该陪女盆友的一天,我却在写博客(说的我好像有女盆友一样!)

在这里插入图片描述

一.AlertDialog的基础知识

1.1 AlertDialog的构造函数

AlertDialog大体上来说有两个重载构造函数

//只需要传入上下文context即可,最后会调用具有默认布局的第二个构造函数。
 AlertDialog.Builder alertDialog1 = new AlertDialog.Builder(Context context);
//传入上下文,同时传入自定义的布局
 AlertDialog.Builder alertDialog2 = new AlertDialog.Builder(context, R.layout.xxx);

1.2 辅助类函数介绍

  builder.setMessage(CharSequence char);
  //设置提示信息,传入字符串即可
  builder.setIcon(Drawable drawable|int id);
  //设置提示的图标,可以传入资源id,也可以传入Drawable对象
  builder.setTitle(CharSequence char|int id);
  //设置提示的标题,传入字符串或者id
  builder.setView();
  //设置对话框内容为自定义view,仅设置内容区
  builder.setContentView();
  //设置对话框为自定义view,设置全部
  builder.setInverseBackgroundForced();
  //已经被弃用,用来更改默认的背景颜色
  builder.setCustomTitle();
  //自定义Title,可设置背景颜色
  builder.setCancelable(true);
  //如果设置为true则是可取消,点击屏幕其他区域,提示框自动消失,若设置false则不可
  builder.setAdapter()
  //设置对话框内容为自定义列表框
  builder.setItems(int id,Listener listener)
  //设置对话框为简单列表项,传入一个资源数组id和一个列表监听器
  builder.setMultiChoiceItems();
  //该方法也是简单列表,传入一个数组和一个boolean类型数组和一个监听器
   

函数真的好多,为了写博客一一验证,改了很多次描述,现在应该比较贴切了
在这里插入图片描述

1.3 AlertDialog的一些问题

AlertDialog.Builder(context).create()的返回值为AlertDialog,但是AlertDialog并不能直接实例化,需要借助AlertDialog.Builder来创建。我们简单的浏览几个重要的源码片段来学习他们的不同。

1.3.1 dialog.show()和builder.show()的区别

public AlertDialog show() {
//在内部创建dialog,最后调用dialog.show(),也就是说builder.show()是调用dialog.show()方法的
            final AlertDialog dialog = create();
            dialog.show();
            return dialog;
        }

1.3.2 builder的一系列设置方法是怎么添加到dialog中的?


    public static class Builder {
    //在builder内部有一个 成员变量P,看名字就知道是“关于显示(dialog)的一些列参数”
    //从builder.create()中可以得到验证
        @UnsupportedAppUsage
        private final AlertController.AlertParams P;
        }

 public AlertDialog create() {
           
            final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
            P.apply(dialog.mAlert);
            //设置dialog的一些列细节信息,如icon,message,都是在Builder中进行设置的,
            //最后调用builder.create()方法,把所有信息传递给dialog
            dialog.setCancelable(P.mCancelable);
            if (P.mCancelable) {
                dialog.setCanceledOnTouchOutside(true);
            }
            dialog.setOnCancelListener(P.mOnCancelListener);
            dialog.setOnDismissListener(P.mOnDismissListener);
            if (P.mOnKeyListener != null) {
                dialog.setOnKeyListener(P.mOnKeyListener);
            }
            return dialog;
        }

1.3.3 AlertDialog的默认布局是如何的?

先用一张图来展示

在这里插入图片描述


之前提到setView()方法可以设置内容区,内容区是在message下面,Buttton上面的一块区域。而setContentView()则可以设置整块区域。可以通过设置style修改默认的AlertDialog的背景。setCustomTitle()其实就是修改setTitle这块的内容,可以传入TextView,并设置TextView的颜色,这样就可以改变默认背景的颜色。

1.3.4 unable to add window的异常

在这里插入图片描述
解决方案:查看传入的Context是否正确。


在这里插入图片描述

二.AlertDialog的实战情景

2.1 消息提示型

简单描述:消息提示类没有复杂的操作,可能只有一个“我知道了”的按钮,是最简单的一种提示。但是默认的提示太丑了,先贴出默认提示,最后再自定义一个消息提示。

  AlertDialog.Builder builder =createMessageDialog(v.getContext());
                builder.setIcon(R.drawable.photo);
                builder.setMessage("明天上午10点,xxx约您在中南海见面");
                builder.setTitle("重要通知");
                builder.setPositiveButton("我知道了", new AlertDialog.OnClickListener(){
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(getApplicationContext(), "您已接受邀请,请准时赴约", Toast.LENGTH_SHORT).show();
                        //这里可以做一些其他操作
                    }
                });
                builder.show();

效果图如下:
在这里插入图片描述


这个提示的代码很简单,下面贴一个自定义的消息提示,时间匆忙,没有做的很好看。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:orientation="vertical"
    android:background="#888888"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:gravity="center_horizontal"
        android:text="重要通知"
        android:textColor="#EEEEEE"
        android:layout_marginTop="8dp"
        android:textSize="22sp"
        android:layout_width="match_parent"
        android:layout_height="40dp">
    </TextView>
    <TextView
        android:layout_marginTop="10dp"
        android:gravity="center_horizontal"
        android:textSize="18sp"
        android:textColor="#CCCCCC"
        android:text="明天上午10点,xxx约您在见面"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </TextView>
    <Button
        android:gravity="center_horizontal"
        android:text="我知道了"
        android:textSize="16sp"
        android:layout_marginTop="30dp"
        android:background="@null"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </Button>
</LinearLayout>
 AlertDialog.Builder builder =createMessageDialog(v.getContext());
                  builder.setView(R.layout.layout_alert);
                  builder.show();
                  //三行代码加布局搞定一切

效果图展示:
在这里插入图片描述
如果需要添加Button的点击,可以通过android:onClick="xxx";并在代码中声明该方法即可。

2.2 逻辑操作型

逻辑操作类型,其实就是底部多了很多按钮,可以进行不同的操作,代码如下:

                AlertDialog.Builder builder =createMessageDialog(v.getContext());
                View view = getLayoutInflater().inflate(R.layout.layout_alert, null);
                builder.setView(view);
                TextView textView = new TextView(v.getContext());
                textView.setText("Android");
                builder.setCancelable(true);
                textView.setBackgroundColor(getResources().getColor(R.color.colorAccent));
                builder.setCustomTitle(textView);
                builder.setNegativeButton("取消", new AlertDialog.OnClickListener(){
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(getApplicationContext(), "您点击了取消", Toast.LENGTH_SHORT).show();
                    }
                });
                builder.setPositiveButton("确定", new AlertDialog.OnClickListener(){
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(getApplicationContext(), "您点击了确定", Toast.LENGTH_SHORT).show();
                    }
                });
                builder.setNeutralButton("中立的", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(getApplicationContext(), "您点击了中立", Toast.LENGTH_SHORT).show();
                    }
                });
                builder.setView(R.layout.layout_alert);
                builder.show();

效果图如下
在这里插入图片描述
这里同样也可以自定义,只需要和之前那样,声明按钮的点击方法即可,就不再演示。

2.3 列表选择型


                builder.setTitle("选择你最喜爱的城市");
                builder.setMultiChoiceItems(province, new boolean[]{true, true, true},
                        new OnMultiChoiceClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                                switch (which) {
                                    case 0:
                                        Toast.makeText(getApplicationContext(), "您选择了A", Toast.LENGTH_SHORT).show();
                                        break;
                                    case 1:
                                        Toast.makeText(getApplicationContext(), "您选择了B", Toast.LENGTH_SHORT).show();
                                        break;
                                    case 2:
                                        Toast.makeText(getApplicationContext(), "您选择了c", Toast.LENGTH_SHORT).show();
                                        break;
                                }
                            }
                        });
                builder.show();



效果展示:


在这里插入图片描述


这里做一个仿网易云播放列表的案例

  builder2.setIcon(R.drawable.play);
                TextView textView1 = new TextView(getApplicationContext());
                textView1.setText("播放列表");
                textView1.setTextSize(22);
                builder2.setCustomTitle(textView1);
                //顶部已经设置好
                String[] songs = new String[]{"演员","聊表心意","花儿与少年","天后","狐狸","七里香","一路向北"};
                String[] singers = new String[]{"薛之谦","薛之谦","薛之谦","陈势安","薛之谦","周杰伦","周杰伦"};
                int[] photo = new int[]{R.drawable.xue,R.drawable.xue,R.drawable.xue,R.drawable.chen,R.drawable.xue,R.drawable.zhou,R.drawable.zhou};
                View view1 = getLayoutInflater().inflate(R.layout.layout_alert, null);
                RecyclerView recyclerView = view1.findViewById(R.id.recyclerview);
                SongAdapter adapter = new SongAdapter(photo, songs, singers, getApplicationContext());
                recyclerView.setAdapter(adapter);
                recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
                builder2.setView(view1);
                builder2.show();

layout_alert

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </androidx.recyclerview.widget.RecyclerView>
</LinearLayout>

song_item

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="80dp">
    <ImageView
        android:layout_margin="6dp"
        android:id="@+id/singer_photo"
        android:src="@drawable/xue"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:scaleType="fitXY">
    </ImageView>
    <LinearLayout
        android:id="@+id/song"
        android:layout_toRightOf="@id/singer_photo"
        android:orientation="vertical"
        android:layout_marginLeft="16dp"
        android:layout_width="wrap_content"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/songs"
            android:textSize="20sp"
            android:text="认真的雪"
            android:textColor="#000000"
            android:layout_marginTop="5dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
        </TextView>
        <TextView
            android:id="@+id/singer"
            android:textSize="16sp"
            android:text="薛之谦"
            android:textColor="#555555"
            android:layout_marginTop="10dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
        </TextView>
    </LinearLayout>


        <ImageView
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:scaleType="center"
            android:layout_marginRight="42dp"
            android:src="@drawable/start"></ImageView>

        <ImageView
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:scaleType="center"
            android:src="@drawable/more"></ImageView>
</RelativeLayout>

SongAdapter

 class SongAdapter extends RecyclerView.Adapter<ViewHolder>{
        private int[] photos;
        private String[] songs;
        private String[] singers;
        private Context context;

        public SongAdapter(int[] photos,String[] songs,String[] singers,Context context){
            this.photos=photos;
            this.songs=songs;
            this.singers=singers;
            this.context=context;
        }


        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(context).inflate(R.layout.song_item,null);
            ViewHolder viewHolder = new ViewHolder(view);
            return viewHolder;
        }

        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
             holder.imageView.setImageDrawable(getResources().getDrawable(photos[position]));
             holder.songs.setText(songs[position]);
             holder.singer.setText(singers[position]);
        }


        @Override
        public int getItemCount() {
            return photos.length;
        }

    }

    class ViewHolder extends RecyclerView.ViewHolder{
        ImageView imageView;
        TextView songs;
        TextView singer;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.singer_photo);
            songs = itemView.findViewById(R.id.songs);
            singer = itemView.findViewById(R.id.singer);
        }
    }

效果图,差的不是一点半点哈哈哈哈哈

在这里插入图片描述



在这里插入图片描述


2.4 自定义提示

自定义提示其实上面已经用到过了,比如自定义的消息提示,自定义的网易云播放列表等,最终要的是思想,我们可以把自定义的布局当成Activity的布局去设计他,大部分情况下,都是可用的。

提一个小案例:淘宝软件上,我们在点击查看已发货时,会弹出一个提示,类似于ViewPager+Fragment结合设计的功能更加复杂的AlertDialog
在这里插入图片描述


自定义提示的步骤如下:

第一步:根据需求,自定义Layout布局
第二步:根据逻辑,将Layout布局转换成view,初始化布局中需要改变的控件。

View view1 = getLayoutInflater().inflate(R.layout.layout_alert, null);
                RecyclerView recyclerView = view1.findViewById(R.id.recyclerview);

第三步:添加事件逻辑,如点击,选择,改变UI等。


2.5 封装提示类

提示在应用中比较常用,建议把AlertDialog封装起来,使用更方便。下面封装一个自定义类型的AlertDialog

public static AlertDialog.Builder 
    createMessageDialog(Context context,String title,String message, int photoId, int layoutId,boolean setview){
       AlertDialog.Builder builder = new AlertDialog.Builder(context);
       if(title!=null){
           builder.setTitle(title);
       }
       if(message!=null){
           builder.setMessage(message);
       }
       try{
            Drawable drawable = context.getResources().getDrawable(photoId);
            builder.setIcon(drawable);
       }catch (NullPointerException e){
            //do something
       }
        View view = LayoutInflater.from(context).inflate(layoutId, null);
       if(setview){
           //设置内容布局
           builder.setView(view);
       }else{
           //设置setContentView,要找builder.show()以后调用
       }
       return builder;
    }

三.AlertDialog高级进阶

3.1 设置AlertDialog入场出场动画

先上效果图:
在这里插入图片描述
这个效果非常简单,就是通过设置动画进行实现的,请看下列实现代码

//this关键字很重要,使用getApplicationContext会出错。
AlertDialog.Builder builder =new AlertDialog.Builder(this);
                builder.setIcon(R.drawable.photo);
                builder.setMessage("明天上午10点,XXX约您在见面");
                builder.setTitle("重要通知");
                builder.setPositiveButton("我知道了", new AlertDialog.OnClickListener(){
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(getApplicationContext(), "您点击了确定", Toast.LENGTH_SHORT).show();
                    }
                });

                Dialog dialog = builder.create();
                //在这里指定动画
                dialog.getWindow().getAttributes().windowAnimations = R.style.dialogWindowAnim;
                dialog.show();

style.xml

 <style name="dialogWindowAnim" parent="android:Animation" mce_bogus="1">  
                <item name="android:windowEnterAnimation">@anim/dialog_enter_anim</item>  
                <item name="android:windowExitAnimation">@anim/dialog_exit_anim</item>  
    </style>

两个简单的动画

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="500"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="0"
        android:toYDelta="1000" >
</translate>

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
     android:duration="100"
     android:fromXDelta="0"
     android:fromYDelta="1000"
     android:toXDelta="0"
     android:toYDelta="0" >
</translate>

3.2 待补充

四 .小结

这篇博客耗时两天,总结了AlertDialog的大部分问题,时间有限,如有错误,请各位前辈指出,感谢各位看官。

先别走,我有一个资源学习群要推荐给你,它是白嫖党的乐园,小白的天堂!
在这里插入图片描述
别再犹豫,一起来学习!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43927892/article/details/106264157