Android自定义底部弹出窗-dialog(2种实现分析+源码)
Android自定义底部弹出窗-dialog(2种实现分析+源码)
上线项目功能抽取,在项目开发中,我们会在许多地方会用到底部自定义弹窗,比如设置:个人账户退出,切换,照片的拍照或者相册的调出,或者一些底部弹出列表,本文对自定义底部弹出窗-dialog,做个开发记录,希望对读者有所帮助.
本文实现的抽取的代码实例:安卓两种底部弹出窗dialog实现方式,一种是列表弹窗实现,2是灵活底部弹窗,传入布局以及控件id
实现方式一:
实现方式二:
一 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布局
简单的两个按钮控件
<?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_anim
<?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.xml
<?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经验,那么请学会使用轮子,再到感受制造轮子的乐趣,你会发现原来编程那么美妙.如有错误或不当之处,请读者留言,博主好吸取经验,互相交流学习,对你有帮助请点赞,粉一波哦