Android开发丶列表底部列表弹窗Dialog同时包含选择和自适应高度功能

前一段时间接到一个需求,点击弹出一个底部弹窗,弹窗的内容以列表的方式来呈现,同时包含选择条目和自适应以及固定高度,需求不难,就是一些细节的东西绕了一些弯路,现在做下汇总。

国际惯例,先看下效果图。

下面说下实现方法。

1.首先新建一个dialog的style。

<!--底部弹窗-->
<style name="DialogStyle" parent="android:style/Theme.Dialog">
    <!--背景透明-->
    <item name="android:windowBackground">@android:color/white</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>
</style>

1.首先新建一个继承Dialog的dialog文件,生成一个构造函数,把上面新建dialog的style引进去。

public ListViewDialog(Context context) {
    super(context, R.style.AppTheme);
}

2.在构造方法中通过initViews()配置组件,主要是引入含listview的xml文件,并引用列表控件设置adapter适配器。

/**
 * 配置组件
 */
private void initViews() {
    View view= LayoutInflater.from(context).inflate(R.layout.dialog_main, null);
    listview= view.findViewById(R.id.main_listview);
    adapter= new MainAdapter(context, new ArrayList<MainBean>());
    listview.setAdapter(adapter);
}

adapter适配器不复杂,item条目只有一个显示title的TextView,完整代码如下

/**
 * 列表的adapter
 */
private class MainAdapter extends BaseAdapter {

    private final Context context;
    private List<MainBean> list;
    private TextView titleTv;

    public MainAdapter(Context context, List<MainBean> list) {
        this.context= context;
        this.list= list;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        View contentView= LayoutInflater.from(context).inflate(R.layout.item_main, null);
        titleTv= contentView.findViewById(R.id.main_titleTv);
        titleTv.setText(list.get(i).getTitle());
        return contentView;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int i) {
        return list.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    /**
     * 设置新数据
     * @param list
     */
    public void setNewList(List<MainBean> list){
        this.list= list;
        notifyDataSetChanged();
    }
}

3.在视图Activity里启动dialog,为了节省资源,我们做一个非空判断,不用每次都new一个dialog。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (dialog== null){
        dialog= new ListViewDialog(MainActivity.this);
    }
    dialog.show();
}

4.启动app,数据应该出来了。

根据需求,此时我们把弹窗移到屏幕底部,并且调整一下宽度充满屏幕。

在构造函数调用一下如下方法。

/**
 * 设置宽高度
 */
private void setHeight() {
    Window window= getWindow();
    DisplayMetrics metrics= context.getResources().getDisplayMetrics();
    WindowManager.LayoutParams params= window.getAttributes();
    params.width= metrics.widthPixels;
    window.setAttributes(params);
    window.setGravity(Gravity.BOTTOM);
}

安装app看下效果:

此时我们添加更多的测试数据,就会发现:

屏幕被全占了,原来这是自适应高度,弹窗的高度会随着条目的数量增加而增加,这种显示效果自然不是我们想要的,所以我们要对它的高度也做下限制,比如说最多不能高于屏幕高度的百分之六十。

回到setHeight方法中,增加以下这行

params.height= (int) (metrics.heightPixels* 0.6);

运行,看效果:

很棒吧,高度已经限制屏幕的60%了,那么问题又来了,如果条目过少呢

看吧,如果条目过少,高度也已固定,弹窗下方就会空出一大片空白区域,因此,我们应该设定当高度不足以到达屏幕高度的百分之六十时,我们就设置其高度自适应。

回到setHeight方法,在设置高度时增加这样的判断条件

if (window.getDecorView().getHeight() >= (int) (metrics.heightPixels * 0.6)) {
    params.height = (int) (metrics.heightPixels * 0.6);

}

运行。

条目过少时,高度自适应。

条目过多时,高度固定屏幕高度的60%。

蛤?没生效。。。经过度娘查找,因为高度动态改变,随之会发生弹窗焦点失去的状况,此时我们只需要将sehHeight()方法放在这个方法中即可。

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    setHeight(); //设置宽高度
}

运行,正常了。

 

接下来,我们给列表加上选择功能,当选中某个条目时,其会变成蓝色,并把选中条目的值返回。

打开列表bean,增加一个自定义字段isChecked;

private boolean isChecked;

public boolean isChecked() {
    return isChecked;
}
public void setChecked(boolean checked) {
    isChecked = checked;
}

打开adapter适配器,在getView()方法中增加以下代码。

titleTv.setTextColor(list.get(i).isChecked()? Color.BLUE: Color.GRAY);

即当某个条目的iChecked为true即选中时,文字改为蓝色,反之则为黑色。

增加控件的点击方法。

titleTv.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        for (int i = 0; i < list.size(); i++) {
            list.get(i).setChecked(false);
        }
        list.get(i).setChecked(true);
        notifyDataSetChanged();
    }
});

代码的意思就是先将所有条目都的isChecked都设为false,再把点击条目的isChecked设为true,从而实现单选效果。

运行起来瞅瞅。

成功!现在我们把选中的值返回到主界面。

这里我们通过接口回调的方式来完成。

先把adapter的数值传回dialog中。

打开adapter,新建:

public interface onItemViewClickListener{
    void onItemViewClick(String title);
}
titleTv.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        .........
        if (listener!= null){
            listener.onItemViewClick(list.get(i).getTitle());
        }
    }
});
同理打开dialog
public interface onItemViewClickListener{
    void onItemViewClick(String title);
}
adapter = new MainAdapter(context, new ArrayList<MainBean>(), new MainAdapter.onItemViewClickListener() {
    @Override
    public void onItemViewClick(String title) {
        if (listener!= null){
            listener.onItemViewClick(title);
            dismiss();
        }
    }
});

接下来打开视图Activity。在xml文件中放置一个用来显示返回文字的TextView,然后修改dialog的构造方法,通过回调获取传递的值。

tv.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (dialog== null){
            dialog= new ListViewDialog(MainActivity.this, new ListViewDialog.onItemViewClickListener() {
                @Override
                public void onItemViewClick(String title) {
                    titleTv.setText(title);
                }
            });
        }
        dialog.show();
    }
});

运行起来~

成功!

至此全部完成,demo附上!

资源下载

 

 

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android弹窗dialog可以通过使用PopupWindow和Dialog来实现。PopupWindow是一个在屏幕上方显示的浮动控件,而Dialog是一个模态对话框。对于PopupWindow的使用,可以通过创建一个布局文件,然后在代码中使用PopupWindow类来显示该布局。而对于Dialog的使用,可以通过创建一个AlertDialog.Builder对象,设置对话框的标题、内容和按钮等属性,最后调用show()方法显示对话框。 下面是一个使用PopupWindow的示例代码: ```java // 创建PopupWindow对象 PopupWindow popupWindow = new PopupWindow(context); // 设置要显示的布局 View view = LayoutInflater.from(context).inflate(R.layout.popup_layout, null); popupWindow.setContentView(view); // 设置PopupWindow的宽度和高度 popupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); // 设置PopupWindow的背景 popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); // 设置PopupWindow是否可点击 popupWindow.setTouchable(true); // 设置PopupWindow是否获取焦点 popupWindow.setFocusable(true); // 设置PopupWindow的位置 popupWindow.showAtLocation(anchorView, Gravity.CENTER, 0, 0); ``` 下面是一个使用Dialog的示例代码: ```java // 创建AlertDialog.Builder对象 AlertDialog.Builder builder = new AlertDialog.Builder(context); // 设置对话框的标题 builder.setTitle("提示"); // 设置对话框的内容 builder.setMessage("这是一个对话框"); // 设置对话框的按钮 builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 点击确定按钮的逻辑处理 } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 点击取消按钮的逻辑处理 } }); // 创建并显示对话框 AlertDialog dialog = builder.create(); dialog.show(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值