Android自定义底部弹出窗-dialog(2种实现分析+源码)

Android自定义底部弹出窗-dialog(2种实现分析+源码)

上线项目功能抽取,在项目开发中,咱们会在许多地方会用到底部自定义弹窗,好比设置:我的帐户退出,切换,照片的拍照或者相册的调出,或者一些底部弹出列表,本文对自定义底部弹出窗-dialog,作个开发记录,但愿对读者有所帮助.java

本文实现的抽取的代码实例:安卓两种底部弹出窗dialog实现方式,一种是列表弹窗实现,2是灵活底部弹窗,传入布局以及控件idandroid

实现方式一:
实现一web

实现方式二:编程

实现方式二

一 MainActivity代码

两种dialog实现方式的调用服务器

package com.kx.kxbottomdialog;

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        init();
    }

    private void init() {
        mContext = this;
        findViewById(R.id.bt1).setOnClickListener(this);
        findViewById(R.id.bt2).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt1:
                bt1ListView();
                break;
            case R.id.bt2://退出登陆
                Bt2Loginout();
                break;
        }
    }

    /**
     * 底部列表弹窗
     */
    private void bt1ListView() {
        List<String> names = new ArrayList<>();
        names.add("随堂测验");
        names.add("单元考试");
        names.add("期中(末)考试");
        showDialog(new BottomCirTraDialog.SelectDialogListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                switch (position) {
                    case 0: //随堂测验
                        showToast("随堂测验");
                        break;
                    case 1://单元考试
                        showToast("单元考试");
                        break;
                    case 2://期中(末)考试
                        showToast("期中(末)考试");
                        break;
                    default:
                        break;
                }

            }
        }, names);
    }

    private BottomCirTraDialog showDialog(BottomCirTraDialog.SelectDialogListener listener, List<String> names) {
        BottomCirTraDialog dialog = new BottomCirTraDialog(this, R.style.transparentFrameWindowStyle, listener, names);
        if (!this.isFinishing()) {
            dialog.show();
        }
        return dialog;
    }

    /**
     * 退出登陆
     * 传入布局实现
     */
    private void Bt2Loginout() {
        BottomDialog dialog = new BottomDialog(mContext, R.layout.dialog_login_out,
                new int[]{R.id.tv_choice_out, R.id.tv_cancel});
        dialog.show();
        dialog.setOnBottomItemClickListener(new BottomDialog.OnBottomItemClickListener() {
            @Override
            public void onBottomItemClick(BottomDialog dialog, View view) {
                switch (view.getId()) {
                    case R.id.tv_choice_out:   //退出登陆
                        //服务器登出  mCenterPI.logout();
                        dialog.cancel();
                        break;
                    case R.id.tv_cancel:  //取消
                        dialog.cancel();
                        break;
                }
            }
        });
    }


    /**
     * Toast
     *
     * @param s
     */
    public void showToast(String s) {
        ToastUtil.toast(this, s);
    }
}

二 页面XML布局

简单的两个按钮控件app

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.kx.kxbottomdialog.MainActivity">

    <TextView
        android:padding="10dp"
        android:textColor="#000"
        android:gravity="center_horizontal"
        android:text="自定义底部弹窗"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:text="列表弹窗"
        android:id="@+id/bt1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:text="传入布局"
        android:id="@+id/bt2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>


</LinearLayout>

三 列表弹窗详细代码自定义控件

package com.kx.kxbottomdialog;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import java.util.List;

/**
 * @ 建立:   kx
 * @ 时间:    2018/10/22
 * @ 描述:
 */

public class BottomCirTraDialog extends Dialog implements AdapterView.OnItemClickListener {

    private List<String> mList;
    private SelectDialogListener mListener;
    private Activity mActivity;
    private boolean mUseCustomColor = false;
    private int mFirstItemColor;
    private int mOtherItemColor;
    private Button mBtnCancel;

    public BottomCirTraDialog(@NonNull Context context) {
        super(context);
    }

    public BottomCirTraDialog(Activity activity, int theme, SelectDialogListener listener, List<String> names) {
        super(activity, theme);
        mActivity = activity;
        mListener = listener;
        mList = names;
        //点击Dialog外部消失
        setCanceledOnTouchOutside(true);
    }


    public interface SelectDialogListener {
        void onItemClick(AdapterView<?> parent, View view, int position, long id);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = getLayoutInflater().inflate(R.layout.dialog_exam_type, null);
        setContentView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        Window window = getWindow();

        //设置动画
        window.setWindowAnimations(R.style.main_menu_animstyle);
        WindowManager.LayoutParams attributes = window.getAttributes();
        attributes.x = 0;
        attributes.y = mActivity.getWindowManager().getDefaultDisplay().getHeight();

        //保证按钮水平满屏
        attributes.width = ViewGroup.LayoutParams.MATCH_PARENT;
        attributes.height = ViewGroup.LayoutParams.WRAP_CONTENT;

        //设置显示位置
        onWindowAttributesChanged(attributes);

        initView();
    }

    private void initView() {
        DialogAdapter dialogAdapter = new DialogAdapter(mList);
        ListView listView = findViewById(R.id.dialog_list);
        mBtnCancel = (Button) findViewById(R.id.btn_cancel);
        listView.setOnItemClickListener(this);
        listView.setAdapter(dialogAdapter);
        mBtnCancel.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                if(mCancelListener != null){
                    mCancelListener.onCancelClick(v);
                }
                dismiss();
            }
        });
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        mListener.onItemClick(parent, view, position, id);
        dismiss();
    }


    private class DialogAdapter extends BaseAdapter {
        private List<String> mStrings;
        private Viewholder viewholder;
        private LayoutInflater layoutInflater;

        public DialogAdapter(List<String> strings) {
            this.mStrings = strings;
            this.layoutInflater = mActivity.getLayoutInflater();
        }

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

        @Override
        public Object getItem(int position) {
            return mStrings.get(position);
        }

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

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (null == convertView) {
                viewholder = new Viewholder();
                convertView = layoutInflater.inflate(R.layout.view_dialog_item, null);
                viewholder.dialogItemButton = (TextView) convertView.findViewById(R.id.dialog_item_bt);
                convertView.setTag(viewholder);
            } else {
                viewholder = (Viewholder) convertView.getTag();
            }
            viewholder.dialogItemButton.setText(mStrings.get(position));
            if (!mUseCustomColor) {
                mFirstItemColor = mActivity.getResources().getColor(R.color.color_0073FF);
                mOtherItemColor = mActivity.getResources().getColor(R.color.color_0073FF);
            }

            //根据数量 设置圆角  数量为1,其余上下,剩余中
            if (1 == mStrings.size()) {
                viewholder.dialogItemButton.setTextColor(mFirstItemColor);
                viewholder.dialogItemButton.setBackgroundResource(R.drawable.dialog_item_bg_only);
            } else if (position == 0) {
                viewholder.dialogItemButton.setTextColor(mFirstItemColor);
                viewholder.dialogItemButton.setBackgroundResource(R.drawable.select_dialog_item_bg_top);
            } else if (position == mStrings.size() - 1) {
                viewholder.dialogItemButton.setTextColor(mOtherItemColor);
                viewholder.dialogItemButton.setBackgroundResource(R.drawable.select_dialog_item_bg_buttom);
            } else {
                viewholder.dialogItemButton.setTextColor(mOtherItemColor);
                viewholder.dialogItemButton.setBackgroundResource(R.drawable.select_dialog_item_bg_center);
            }
            return convertView;
        }

    }

    public static class Viewholder {
        public TextView dialogItemButton;
    }


    /**
     * 取消事件监听接口
     *
     */
    private SelectDialogCancelListener mCancelListener;

    public interface SelectDialogCancelListener {
        void onCancelClick(View v);
    }
}

四 传入布局自定义弹窗

package com.kx.kxbottomdialog;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;


/**
 * @ 建立:   kx
 * @ 时间:    2018/10/22
 * @ 描述:
 */

public class BottomDialog extends Dialog implements View.OnClickListener {
    private Context context;
    private int layoutRes;
    private View view;
    private int[] clickIds;   //须要设置点击事件的ID.须要其余ID,在dialog实例化后在dialog上fbc.

    public BottomDialog(Context context, int layoutRes, int[] clickIds) {
        super(context, R.style.dialog_full);    //设置主题
        this.context = context;
        this.layoutRes = layoutRes;
        this.clickIds = clickIds;
    }

    public BottomDialog(Context context, View view, int[] clickIds) {
        super(context, R.style.dialog_full);    //设置主题
        this.context = context;
        this.view = view;
        this.clickIds = clickIds;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Window window = getWindow();
        //底部弹出的Dialog
        window.setGravity(Gravity.BOTTOM);
        //底部弹出的动画
        window.setWindowAnimations(R.style.DialogBottomAnimation);
        if(view != null) {
            setContentView(view);
        }else{
            setContentView(layoutRes);
        }

        getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.MATCH_PARENT);
        //点击Dialog外部消失
        setCanceledOnTouchOutside(true);
        //禁用返回键
        setCancelable(true);
        //设置点击事件
        if (clickIds != null) {
            for (int id : clickIds) {
                findViewById(id).setOnClickListener(this);
            }
        }
    }

    public View getView() {
        if (view == null) {
            return getLayoutInflater().inflate(layoutRes, null);
        }
        return view;
    }

    private OnBottomItemClickListener listener;

    public interface OnBottomItemClickListener {
        void onBottomItemClick(BottomDialog dialog, View view);
    }

    public void setOnBottomItemClickListener(OnBottomItemClickListener listener) {
        this.listener = listener;
    }

    @Override
    public void onClick(View v) {
        listener.onBottomItemClick(this, v);
    }
}

五 styles

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <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>

    <!--自定义Dialog弹出的全屏样式,不要继承系统Dialog的样式会出现抖动的状况-->
    <style name="dialog_full">
        <item name="android:windowIsFloating">true</item>   <!--是否悬浮在界面上-->
        <item name="android:windowIsTranslucent">true</item>   <!--是否半透明-->
        <item name="android:windowNoTitle">true</item> <!--是否有标题-->
        <item name="android:windowBackground">@android:color/transparent</item>  <!--窗口背景色透明-->
        <item name="android:backgroundDimEnabled">true</item>  <!--背景是否模糊显示-->
    </style>

    <!--自定义Dialog的底部弹出的动画,直接从中间弹出的不加动画-->
    <style name="DialogBottomAnimation"  parent="android:Animation">
        <item name="android:windowEnterAnimation">@anim/dialog_bottom_enter</item>
        <item name="android:windowExitAnimation">@anim/dialog_bottom_exit</item>
    </style>
</resources>

六 相关的资源动画

photo_dialog_in_animide

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromXDelta="0"
        android:fromYDelta="1000"
        android:toXDelta="0"
        android:toYDelta="0" />

</set>

photo_dialog_out_anim.xmlsvg

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="300"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="0"
        android:toYDelta="1000" />

</set>

尾言

为本身技术增值,量变引发质变.对象亦来源于生活,模式亦来源于验证的OO经验,那么请学会使用轮子,再到感觉制造轮子的乐趣,你会发现原来编程那么美妙.若有错误或不当之处,请读者留言,博主好吸收经验,互相交流学习,对你有帮助请点赞,粉一波哦布局