Android bullet box summary

a brief introduction

1.1 The pop-up box refers to the window floating on the page, such as keyboard pop-up box, toast pop-up box, confirmation pop-up box, drop-down selection box, application floating box, etc.

1.2 There are also many bullet box controls, such as the commonly used Spinner, Dialog, Toast, PopWindow, etc., as well as the newly added SnackBar, DialogFragment, etc.

Two Spinner drop-down selection to use

2.1 Spinner root Listview, Gridview, etc. are products of the same era, so the usage is similar to them, mainly using BaseAdapter to load data sources

2.2  Use the Adapter provided by the system , which is easy to use, but the style is fixed, the data model is fixed, and it can only be of String type.

renderings

Layout file, add Spinner control

<FrameLayout
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:layout_gravity="center_horizontal"
	android:layout_marginTop="40dp"
	android:background="#eeeeee">

	<Spinner
		android:id="@+id/spinner"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content" />
</FrameLayout>

The java file sets the data source and configuration

private void initSystemAdapter(){
        //设置数据源
        List<String> list = new ArrayList<String>();
        list.add("苹果");
        list.add("香蕉");
        list.add("橘子");
        list.add("香蕉");
        //设置系统适配器
        ArrayAdapter<String> adapter=new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,list);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);
        //设置弹出偏移位置
        spinner.setDropDownVerticalOffset(40);
        //点击监听
        spinner.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(SpinnerActivity.this, list.get(position), Toast.LENGTH_SHORT).show();
            }
        });
    }

Note: The system Adapter style is fixed, there are the following types

simple_spinner_dropdown_item (list-higher spacing is better)
simple_spinner_item (list-tight spacing is not good-looking)
simple_list_item_checked (check box-selected with green groove)
simple_list_item_single_choice (radio button)

2.3 Custom adapter , high flexibility, can set any type of data source and style

renderings

Custom item layout item_fruit_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="100dp"
        android:layout_height="30dp"
        android:background="#00ffff"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:text="条目"
        android:textSize="15sp" />
</LinearLayout>

Custom data source FruitBean.java

public class FruitBean {
    public String name;

    public FruitBean(String name) {
        this.name = name;
    }
}

Custom adapter CustomerAdapter.java

public class CustomerAdapter extends BaseAdapter {
    private Context mContext;
    private List<FruitBean> mList;

    public CustomerAdapter(Context mContext, List<FruitBean> mList) {
        this.mContext = mContext;
        this.mList = mList;
    }

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

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_fruit_list, null);
            holder.tvName = (TextView) convertView.findViewById(R.id.tv_name);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.tvName.setText(mList.get(position).name);
        return convertView;
    }

    class ViewHolder {
        public TextView tvName;

    }
}

spinner configuration custom adapter

private void initCustomerAdapter(){
	//设置数据源
	List<FruitBean> list = new ArrayList<>();
	list.add(new FruitBean("苹果"));
	list.add(new FruitBean("香蕉"));
	list.add(new FruitBean("橘子"));
	list.add(new FruitBean("香蕉"));
	//设置系统适配器
	CustomerAdapter customerAdapter=new CustomerAdapter(this,list);
	spinner.setAdapter(customerAdapter);
	//设置弹出偏移位置
	spinner.setDropDownVerticalOffset(40);
}

The use of three Dialog

3.1 Dialog is the most frequently used bullet box besides Toast. Various loading boxes, prompt boxes, and selection boxes are also mostly used in Dialog

3.2 Dialog supports any layout and pop-up position, so it is very flexible.

3.2 Example renderings

3.3 Create a custom Dialog

dialog_confirm.xm

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="match_parent"
	android:layout_height="wrap_content"
	android:background="@drawable/shape_bg_fffff_corner10"
	android:orientation="vertical"
	android:paddingLeft="25dp"
	android:paddingTop="20dp"
	android:paddingRight="25dp"
	android:paddingBottom="@dimen/dimen_20">

	<TextView
		android:id="@+id/tv_title"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:layout_gravity="center_horizontal"
		android:text="退出提示"
		android:textColor="@color/color_333333"
		android:textSize="16sp"
		android:textStyle="bold" />


	<TextView
		android:id="@+id/tv_content"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:layout_gravity="center"
		android:layout_marginTop="15dp"
		android:gravity="center"
		android:text="是否对本地编辑的内容进行保存?"
		android:textColor="@color/color_333333"
		android:textSize="@dimen/text_14" />


	<LinearLayout
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:layout_marginTop="@dimen/dimen_20"
		android:orientation="horizontal">

		<TextView
			android:id="@+id/tv_cancel"
			android:layout_width="0dp"
			android:layout_height="wrap_content"
			android:layout_marginRight="10dp"
			android:layout_weight="1"
			android:background="@drawable/shape_bg_1677ff_corners7_border"
			android:gravity="center"
			android:paddingTop="@dimen/dimen_9"
			android:paddingBottom="@dimen/dimen_9"
			android:text="取消"
			android:textColor="@color/color_1677ff"
			android:textSize="14sp" />

		<TextView
			android:id="@+id/tv_sure"
			android:layout_width="0dp"
			android:layout_height="wrap_content"
			android:layout_marginLeft="10dp"
			android:layout_weight="1"
			android:background="@drawable/shape_bg_1677ff_corners7"
			android:gravity="center"
			android:paddingTop="@dimen/dimen_9"
			android:paddingBottom="@dimen/dimen_9"
			android:text="立即充值"
			android:textColor="@color/white"
			android:textSize="@dimen/sp_14" />

	</LinearLayout>
</LinearLayout>

Set the dialog style custom_dialog.style, translucency, title, background, popup animation, etc.

<style name="custom_dialog" parent="@android:style/Theme.Dialog">
	<item name="android:windowFrame">@null</item>
	<!-- Dialog的windowFrame框为无 -->
	<item name="android:windowIsFloating">true</item>
	<!-- 是否漂现在activity上 -->
	<item name="android:windowIsTranslucent">true</item>
	<!-- 是否半透明 -->
	<item name="android:windowNoTitle">true</item>
	<item name="android:background">@null</item>
	<item name="android:windowBackground">@android:color/transparent</item>
	<item name="android:windowContentOverlay">@null</item>
	<!-- 去除黑色边框的关键设置项 -->
	<item name="android:backgroundDimEnabled">true</item>
	<!-- 屏幕背景是否变暗 -->
	<item name="android:backgroundDimAmount">0.7</item>
</style>

Need to inherit the system Dialog parent class

public class ConfirmDialog extends Dialog {
    private Context context;

    private TextView tvTitle;
    private TextView tvContent;
    private TextView tvCancel;
    private TextView tvSure;



    private String title, content, cancelString, sureString;

    public interface OnViewClickLiatener {
        void sureClick();
        void cancelClick();
    }

    public OnViewClickLiatener onViewClickLiatener;

    public void setOnViewClickLiatener(OnViewClickLiatener onViewClickLiatener) {
        this.onViewClickLiatener = onViewClickLiatener;
    }

    public ConfirmDialog(Context context) {
        this(context, R.style.custom_dialog);
    }

    public ConfirmDialog(Context context, int themeResId) {
        super(context, themeResId);
        this.context = context;
    }

    public ConfirmDialog(Context context, int themeResId, String title, String content, String cancelString, String sureString) {
        super(context, themeResId);
        this.context = context;
        this.title = title;
        this.content = content;
        this.cancelString = cancelString;
        this.sureString = sureString;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dialog_confirm);
        setCanceledOnTouchOutside(true);
        WindowManager.LayoutParams params = getWindow().getAttributes();
        params.width = (int) (ScreenUtils.getScreenWidth((Activity) context) * 0.8f);
        params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
        getWindow().setGravity(Gravity.CENTER);
        getWindow().setAttributes(params);
        getWindow().setBackgroundDrawableResource(R.color.trans);
        initView();
        setData();

    }

    public void initView() {
        tvTitle = (TextView) findViewById(R.id.tv_title);
        tvContent = (TextView) findViewById(R.id.tv_content);
        tvCancel = (TextView) findViewById(R.id.tv_cancel);
        tvSure = (TextView) findViewById(R.id.tv_sure);
    }
    public void setData() {
        if (!TextUtils.isEmpty(title)) {
            tvTitle.setText(title);
        }

        if (!TextUtils.isEmpty(content)) {
            tvContent.setText(content);
        }
        if (!TextUtils.isEmpty(cancelString)) {
            tvCancel.setText(cancelString);
        }

        if (!TextUtils.isEmpty(sureString)) {
            tvSure.setText(sureString);
        }


        tvCancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dismiss();
                if (onViewClickLiatener != null) {
                    onViewClickLiatener.cancelClick();
                }
            }
        });
        tvSure.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dismiss();
                if (onViewClickLiatener != null) {
                    onViewClickLiatener.sureClick();
                }
            }
        });
    }


    @Override
    public void dismiss() {
        super.dismiss();

    }
}

use

 /**
     * 确认取消提示
     */
    ConfirmDialog showCancelDialog;

    public void showCancelDialog(String reportOrderNo, String storeCode) {
        if (showCancelDialog == null) {
            showCancelDialog = new ConfirmDialog(activity, "取消提醒", "取消后将不再对已添加的内容进行保存", "暂不取消", "确认取消");
            showCancelDialog.setOnViewClickLiatener(new ConfirmDialog.OnViewClickLiatener() {
                @Override
                public void sureClick() {
                    if (TextUtils.isEmpty(reportOrderNo)) {
                        activity.finish();
                    } else {
                        httpReportOrderCancel(reportOrderNo, storeCode);
                    }
                }

                @Override
                public void cancelClick() {

                }
            });
        }

        if (!showCancelDialog.isShowing()) {
            showCancelDialog.show();
        }
    }

3.4 Set the dialog that considers the location, the following rendering is in the upper right corner of the screen, and there is an offset distance

 The root is the same as the normal Dialog, but a view needs to be passed in the constructor, that is, for that view to pop up, the offset position of the Dialog is set by obtaining the position of the view on the screen. The following example

public class OtherUserMainMoreDialog extends Dialog {

    private DialogViewListener listener;
    private Activity mContext;
    private View locationView;

    private LinearLayout llRemarks;
    private LinearLayout llPullBlack;
    private LinearLayout llDeleteFriend;

    public interface DialogViewListener {
        void remarksClick();

        void pullBlackClick();

        void deleteFriend();
    }

    public OtherUserMainMoreDialog(Activity context) {
        super(context);
        mContext = context;
    }

    public void setDialogViewListener(DialogViewListener listener) {
        this.listener = listener;
    }

    public OtherUserMainMoreDialog(Activity context, int themeResId, View locationView) {
        super(context, themeResId);
        mContext = context;
        this.locationView = locationView;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = LayoutInflater.from(mContext).inflate(R.layout.dialog_other_more, null);
        setContentView(view);
        //设置Dialog点击外部消失
        setCanceledOnTouchOutside(true);
        setCancelable(true);

        //获取控件 textview 的绝对坐标,( y 轴坐标是控件上部到屏幕最顶部(不包括控件本身))
        //location [0] 为x绝对坐标;location [1] 为y绝对坐标
        int[] location = new int[2];
        locationView.getLocationInWindow(location); //获取在当前窗体内的绝对坐标
        //获取当前Activity所在的窗体
        Window window = getWindow();
        WindowManager.LayoutParams wlp = window.getAttributes();
        //获取通知栏高度  重要的在这,获取到通知栏高度
        int notificationBar = Resources.getSystem().getDimensionPixelSize(
                Resources.getSystem().getIdentifier("status_bar_height", "dimen", "android"));
        wlp.x = location[0];//对 dialog 设置 x 轴坐标
        wlp.y = location[1] + locationView.getHeight() - notificationBar - 15; //对dialog设置y轴坐标
        wlp.gravity = Gravity.TOP;
        wlp.width = WindowManager.LayoutParams.MATCH_PARENT;
        window.setAttributes(wlp);

        llRemarks = (LinearLayout) findViewById(R.id.ll_remarks);
        llPullBlack = (LinearLayout) findViewById(R.id.ll_pull_black);
        llDeleteFriend = (LinearLayout) findViewById(R.id.ll_delete_friend);

        llPullBlack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (listener != null) {
                    listener.pullBlackClick();
                }
                cancel();
            }
        });

        llRemarks.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (listener != null) {
                    listener.remarksClick();
                }
                cancel();
            }
        });
        llDeleteFriend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (listener != null) {
                    listener.deleteFriend();
                }
                cancel();
            }
        });

    }

}

3.5 Notes on using DIalog:

Since DIalog must depend on an Activity, if the Activity is accidentally destroyed, the Dialog will pop up or the message will not find the Activity, resulting in a crash. The solution is as follows:

  • Set the Activity as a weak reference so that when the Activity is destroyed, the object holding the Activity can be recycled in time.
  • Determine whether the Activity is alive before the Dialog pops up the message, so as to ensure the safe popup or message

Treat it as follows:

@Override
public void dismiss() {
	if (context == null || ((Activity) context).isDestroyed() || ((Activity) context).isFinishing()) {
		return;
	}
	super.dismiss();

}

@Override
public void show() {
	if (context == null || ((Activity) context).isDestroyed() || ((Activity) context).isFinishing()) {
		return;
	}
	super.show();
}

Fourth, the use of Toast

4.1 The easiest to use, call the system api

Toast.makeText(context, "提示消息", Toast.LENGTH_SHORT).show();

4.2 Set the position of Toast, top, middle, bottom, etc.

Toast toast = Toast.makeText(context, "提示消息", Toast.LENGTH_SHORT);
toast.setGravity(Gravity.TOP, 0, 0);
toast.show();

4.3 Control the pop-up frequency in a short time

 private static String oldMsg;
    protected static Toast toast = null;
    private static long oneTime = 0;
    private static long twoTime = 0;
    public static void showToast(Context context, String s, int gravity, int offX, int offY) {
        if (toast == null) {
            toast = Toast.makeText(context, s, Toast.LENGTH_SHORT);
            toast.setGravity(gravity, offX, offY);
            toast.show();
            oneTime = System.currentTimeMillis();
        } else {
            twoTime = System.currentTimeMillis();
            if (s.equals(oldMsg)) {
                if (twoTime - oneTime > Toast.LENGTH_SHORT) {
                    toast.show();
                }
            } else {
                oldMsg = s;
                toast.setText(s);
                toast.show();
            }
        }
        oneTime = twoTime;
    }

4.4 Customize Toast layout style

 private static TextView textView;
    /**
     * 自定义样式的吐司
     * <p/>
     * 静态toast 只创建一个toast实例 可以实时显示弹出的内容
     *
     * @param context
     * @param text
     */
    public static void showPicToast(Context context, String text) {

        if (toast == null) { // 1. 创建前 2.消失后toast为null
            // 获取打气筒
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            //创建视图
            View view = inflater.inflate(R.layout.toast_bg, null);
            textView = (TextView) view.findViewById(R.id.tv_toast_text);
            //创建土司
            toast = new Toast(context);
            //设置居中方式  默认在底部
            //toast.setGravity(Gravity.CENTER, 0, 0);//如果不设置剧中方式,使用系统默认的吐司位置
            //设置土司的持续时长
            toast.setDuration(Toast.LENGTH_SHORT);
            toast.setGravity(Gravity.CENTER, 0, 0);
            //设置土司的背景View
            toast.setView(view);
        }
        //设置土司的显示额内容
        textView.setText(text);
        toast.show();
    }

4.5 Notes on use:

After Android 30, the Toast position parameter will be invalid, and the set position will follow the system position, so Google recommends replacing Toast with SnackBar.

If you insist on using Toast, then recommend a Toast library, you can set the Toast location, and add the dependent library as follows

implementation 'com.hjq:toast:8.8'

Initialize in application

ToastUtils.init(this);

Pop up the Toast in other places

ToastUtils.show("提示消息");

Five SnackBar

5.1 

5.2 Easy to use

 public void snackbar1(View view) {
   Snackbar.make(this,llRootLayout,"snack bar",Snackbar.LENGTH_SHORT).show();
}

The first parameter is Context, 
the second parameter is the view to be displayed,
the third parameter is the string to be displayed
, and the fourth parameter is the display duration. There are three types of duration:
Snackbar.LENGTH_SHORT and Toast.LENGHT_SHORT (about 1 second more ) will automatically disappear after a short duration of display.
Snackbar.LENGTH_LONG is the same as Toast.LENGHT_LONG (about 3 seconds) and
will automatically disappear after a relatively long period of time.

5.3 Interactive use

public void snackbar2(View view) {
	Snackbar snack_bar = Snackbar.make(this,view, "确定退出吗?", Snackbar.LENGTH_INDEFINITE);
	snack_bar.setAction("确认", new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			//退出
		}
	});
	snack_bar.show();
}

5.4 Custom layout SnackBar

layout snackbar_view.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="#000000">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="12dp"
        android:layout_marginLeft="12dp"
        android:textColor="@color/black"
        android:textSize="11sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="24dp"
        android:layout_height="24dp"
        android:layout_marginEnd="12dp"
        android:layout_marginRight="12dp"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="@+id/textView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@+id/textView" />

    <TextView
        android:id="@+id/textViewSub"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_marginEnd="5dp"
        android:layout_marginRight="5dp"
        android:gravity="center"
        android:paddingStart="8dp"
        android:paddingEnd="8dp"
        android:text=""
        android:textColor="#ffffff"
        android:textSize="11sp"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Tool class SnackBarUtil.java 

public class SnackBarUtil {
    //自定义 SnackBar 布局
    public static void show(Activity activity, View view, String msg, String action, SnackBarOnClick listener) {
        //获取示例 findViewById(android.R.id.content) //LENGTH_LONG/LENGTH_SHORT: 会自动消失 LENGTH_INDEFINITE: 需要手动点击消失
        Snackbar snackbar = Snackbar.make(view, "", Snackbar.LENGTH_SHORT);
        //设置 Snackbar 的深度,避免被其他控件遮挡
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            snackbar.getView().setElevation(0);
        }
        //设置背景透明,避免自带黑色背景影响
        snackbar.getView().setBackgroundColor(Color.TRANSPARENT);
        //设置padding 取消自定义时黑色边框
        snackbar.getView().setPadding(0, 0, 0, 0);
        Snackbar.SnackbarLayout snackbarLayout = (Snackbar.SnackbarLayout) snackbar.getView();
        //设置SnackBar的显示位置
        //ViewGroup.LayoutParams layoutParams = snackbarLayout.getLayoutParams();
        FrameLayout.LayoutParams flp = new FrameLayout.LayoutParams(dip2px(activity,260),dip2px(activity,32)); // 将原来Snackbar的宽高传入新的LayoutParams
        flp.gravity = Gravity.CENTER | Gravity.BOTTOM; // 设置显示位置
        flp.bottomMargin = dip2px(activity,8);
        ((View) snackbarLayout).setLayoutParams(flp);
        //获取自定义布局
        View inflate = LayoutInflater.from(activity).inflate(R.layout.snackbar_view, null);
        //获取布局内控件
        TextView textView = inflate.findViewById(R.id.textView);
        //TextView 前边添加图片
        //Drawable drawable = getResources().getDrawable(R.mipmap.ic_launcher_round);//图片自己选择
        //drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
        //textView.setCompoundDrawables(drawable, null, null, null);
        //增加文字和图标的距离
        //textView.setCompoundDrawablePadding(20);
        //设置文本
        textView.setText(msg);
        if (action != null && listener != null) {
            TextView textViewSub = inflate.findViewById(R.id.textViewSub);
            textViewSub.setVisibility(View.VISIBLE);
            textViewSub.setText(action);
            textViewSub.setOnClickListener(v -> {
                if (listener != null) {
                    listener.clickEvent(snackbar);
                }
            });
        }
        //添加图片 获取布局内控件
        //ImageView imageView = inflate.findViewById(R.id.imageView2);
        //获取图片资源
        //Drawable drawable = activity.getResources().getDrawable(closeIcon);
        //设置图片
        //imageView.setImageDrawable(drawable);
        //将自定义布局添加到 Snackbar 中
        snackbarLayout.addView(inflate);
        //显示
        snackbar.show();
    }

    public interface SnackBarOnClick {
        void clickEvent(Snackbar snackbar);
    }

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dip2px(Activity activity, float dpValue) {
        final float scale = activity.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}

 Call tool class SnackBarUtil

public void snackbar3(View view) {
        SnackBarUtil.show(this, view, "确定退出吗?", "确认", new SnackBarUtil.SnackBarOnClick() {
            @Override
            public void clickEvent(Snackbar snackbar) {
                //退出
            }
        });
    }

Six PopWindow drop-down box use

6.1 PopWindow is also a pop-up box. Compared with Dialog, it is more used in the pop-up based on a certain control position, and also supports arbitrary layout and style.

6.2 Example, add layout file, popup_size_listview.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="@dimen/dp_80"
    android:layout_height="wrap_content">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rcl_view"
        android:layout_width="@dimen/dp_80"
        android:layout_height="wrap_content" />
</RelativeLayout>

6.3 Customize PopupWindow

public class PopupviewSizeModel extends PopupWindow {
    private IPopuWindowListener mOnClickListener;
    private Activity mContext;
    private RecyclerView recyclerView;
    private PopupModelListAdapter popupModelListAdapter;
    private List<InfoBean.BindSizeListDTO> listString=new ArrayList<>();

    /**
     * 暴露给外面的设置单击事件
     */
    public void setPopuWindowListener(IPopuWindowListener mOnClickListener) {
        this.mOnClickListener = mOnClickListener;
    }

    public PopupviewSizeModel(Activity context) {
        super(context);
        this.mContext = context;
        //获取布局文件
        View mContentView = LayoutInflater.from(mContext).inflate(R.layout.popup_size_listview, null);
        initView(mContentView);
        //设置布局
        setContentView(mContentView);
        int width = context.getWindowManager().getDefaultDisplay().getWidth();
        setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
        setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
        //设置可以点击外部消息
        //开始
        setOutsideTouchable(true);
        setFocusable(true);
//        setBackgroundDrawable(new BitmapDrawable());
        setBackgroundDrawable(context.getResources().getDrawable(android.R.color.transparent));
        setAnimationStyle(R.style.pop_animation);

    }
    private void initView(View contentView) {
        recyclerView = (RecyclerView) contentView.findViewById(R.id.rcl_view);
        LinearLayoutManager manager = new LinearLayoutManager(mContext);
        recyclerView.setLayoutManager(manager);
        recyclerView.setNestedScrollingEnabled(false);
        popupModelListAdapter = new PopupModelListAdapter(mContext, R.layout.item_popup_size_list, listString);
        recyclerView.setAdapter(popupModelListAdapter);
        popupModelListAdapter.setOnItemClickListener(new MultiItemTypeAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, RecyclerView.ViewHolder holder, int position) {
                dismiss();
                if(mOnClickListener!=null){
                    mOnClickListener.onItemClick(position);
                }

            }

            @Override
            public boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position) {
                return false;
            }
        });
    }

    public void setListData(List<InfoBean.BindSizeListDTO> list) {
        listString.clear();
        listString.addAll(list);
        popupModelListAdapter.setData(listString);
        popupModelListAdapter.notifyDataSetChanged();
    }
//     /***
//     * 在android7.0上,如果不主动约束PopuWindow的大小,比如,设置布局大小为 MATCH_PARENT,那么PopuWindow会变得尽可能大,以至于 view下方无空间完全显示PopuWindow,而且view又无法向上滚动,此时PopuWindow会主动上移位置,直到可以显示完全。
//     * 解决办法:主动约束PopuWindow的内容大小,重写showAsDropDown方法:
//     * @param anchor
//     */
//    @Override
//    public void showAsDropDown(View anchor,int xoff,int yoff,int gravity) {
//        if (Build.VERSION.SDK_INT >= 24) {
//            Rect visibleFrame = new Rect();
//            anchor.getGlobalVisibleRect(visibleFrame);
//            int height = anchor.getResources().getDisplayMetrics().heightPixels - visibleFrame.bottom;
//            setHeight(height);
//            showAsDropDown(anchor, xoff, yoff,gravity);
//        } else {
//           showAsDropDown(anchor, xoff, yoff,gravity);
//        }
//        super.showAsDropDown(anchor);
//    }

    public interface IPopuWindowListener {
        void onItemClick(int position);
    }
}

6.4 Setting up the data model 

publicclass BindSizeListDTO{
        public String id;
        public String name;

        public BindSizeListDTO(String name) {
            this.name = name;
        }
    }

6.5 Pop up the PopupWindow at the specified view position

private PopupviewSizeModel popupviewModelSize;
List<InfoBean.BindSizeListDTO> listStringSize = new ArrayList<>();
private void showSizePopup() {
	listStringSize.add(new InfoBean.BindSizeListDTO("230x150"));
	listStringSize.add(new InfoBean.BindSizeListDTO("270x200"));
	listStringSize.add(new InfoBean.BindSizeListDTO("300x200"));
	listStringSize.add(new InfoBean.BindSizeListDTO("330x225"));
	listStringSize.add(new InfoBean.BindSizeListDTO("340x239"));
	if (popupviewModelSize == null) {
		popupviewModelSize = new PopupviewSizeModel(mContext);
		popupviewModelSize.setPopuWindowListener(new PopupviewSizeModel.IPopuWindowListener() {
			@Override
			public void onItemClick(int position) {
				Toast.makeText(SnackBarActivity.this, "点击了条目", Toast.LENGTH_SHORT).show();

			}
		});
	}
	popupviewModelSize.setListData(listStringSize);
	popupviewModelSize.showAsDropDown(tvSize);
}

Seven DialogFragment

7.1 Dialog is dependent on the life cycle of Activity. The difference between DialogFragment and Dialog is that it is essentially a Fragment, which also has the life cycle owned by Fragment.

7.1 The way to create DialogFragment, use onCreateDialog to create the Dialog provided by the system

public class SystemDialogFragment extends DialogFragment {

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        AlertDialog dialog = new AlertDialog.Builder(getContext())
                .setTitle("系统弹窗")
                .setMessage("信息")
                //.setIcon(R.drawable.assign_set_question_ic_v2)
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                    }
                }).setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(getContext(), "确认", Toast.LENGTH_SHORT).show();
                    }
                }).create();
        return dialog;
    }
}

Call the DialogFragment in the Activity

public class DialogFragmentActivity extends ComponentActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activty_dialog_fragment);
    }

    public void alertdialog(View view) {
        SystemDialogFragment systemDialogFragment=new SystemDialogFragment();
        systemDialogFragment.show(getFragmentManager(),"ss");
    }
}

Effect:

7.2 Custom layout DialogFragment

Create a layout file dialog_confirm.xml

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ffffff"
    android:orientation="vertical"
    android:paddingLeft="25dp"
    android:paddingTop="20dp"
    android:paddingRight="25dp"
    android:paddingBottom="20dp">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="退出提示"
        android:textColor="#333333"
        android:textSize="16sp"
        android:textStyle="bold" />


    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="15dp"
        android:gravity="center"
        android:text="是否对本地编辑的内容进行保存?"
        android:textColor="#333333"
        android:textSize="14sp" />


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tv_cancel"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:layout_weight="1"
            android:gravity="center"
            android:paddingTop="9dp"
            android:paddingBottom="9dp"
            android:text="取消"
            android:textColor="#666666"
            android:textSize="14sp" />

        <TextView
            android:id="@+id/tv_sure"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:layout_weight="1"
            android:gravity="center"
            android:paddingTop="9dp"
            android:paddingBottom="9dp"
            android:text="立即充值"
            android:textColor="#000000"
            android:textSize="14sp" />

    </LinearLayout>
</LinearLayout>

Create DialogFragment, CustomerDialogFragment.java

public class CustomerDialogFragment extends DialogFragment {

    public View mRootView;

    private TextView tvTitle;
    private TextView tvContent;
    private TextView tvCancel;
    private TextView tvSure;


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        if (mRootView == null){
            //获取布局
            mRootView = inflater.inflate(R.layout.dialog_confirm,container,false);
        }


        tvTitle = (TextView) mRootView.findViewById(R.id.tv_title);
        tvContent = (TextView) mRootView.findViewById(R.id.tv_content);
        tvCancel = (TextView) mRootView.findViewById(R.id.tv_cancel);
        tvSure = (TextView) mRootView.findViewById(R.id.tv_sure);
        tvCancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dismiss();
            }
        });
        tvSure.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getActivity(), "点击确定", Toast.LENGTH_SHORT).show();
                dismiss();
            }
        });
        return mRootView;
    }

}

Activity calls the DialogFragment

 public void customerdialog(View view) {
     CustomerDialogFragment systemDialogFragment=new CustomerDialogFragment();
     systemDialogFragment.show(getFragmentManager(),"Customer");
 }

Effect demonstration

Eight system suspension frame

8.1 The system floating frame follows the application life cycle, it may not be above Acitivity, does not depend on Acitivity, and is suitable for the pop-up frame of the global life cycle

8.2 Use, create a new layout file, float_layout_window.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:id="@+id/linear"
        android:layout_width="200dp"
        android:orientation="vertical"
        android:gravity="center"
        android:background="@color/purple_200"
        android:layout_height="200dp">
        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:text="移动"
            android:layout_height="wrap_content" />
        <TextView

            android:layout_width="wrap_content"
            android:text="移动"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

8.2 Add floating frame permission

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />

8.3 Create a new FloatWindowsActivity.java and add a floating frame layout

public class FloatWindowsActivity extends ComponentActivity {
    public WindowManager mWindowManager;
    public View mWindowView;
    public LinearLayout mText;
    public WindowManager.LayoutParams wmParams;

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

    public void folatwindows(View view) {
        checkFloatPermission();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode==0){
            checkFloatPermission();
        }
    }

    /**
     * 检查是否开启悬浮框权限
     */
    public void checkFloatPermission(){
        if(!Settings.canDrawOverlays(FloatWindowsActivity.this)) {

            Toast.makeText( FloatWindowsActivity.this, "当前无权限,请授权", Toast.LENGTH_SHORT);

            startActivityForResult( new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse( "package:"+ getPackageName())), 0);

        }else {
            initWindowParams();
        }

    }
    /**
     * 初始化Window对象的参数
     */
    private void initWindowParams() {
        //1,获取系统级别的WindowManager
        mWindowManager = (WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE);
        wmParams = new WindowManager.LayoutParams();
        //2,添加系统参数,确保悬浮框能显示到手机上
        //电话窗口。它用于电话交互(特别是呼入)。它置于所有应用程序之上,状态栏之下。
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        // flag 设置 Window 属性
        wmParams.flags
                |= WindowManager.LayoutParams.FLAG_FULLSCREEN
                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

        //期望的位图格式。默认为不透明
        wmParams.format = PixelFormat.TRANSLUCENT;
        //不许获得焦点
        wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        //窗口停靠位置
        wmParams.gravity = Gravity.LEFT | Gravity.TOP;
        wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

        addWindowViewZWindow();
        initClick();
    }


    /**
     * 添加View到桌面Window界面上
     */
    private void addWindowViewZWindow() {
        if(mWindowView==null){
            mWindowView = LayoutInflater.from(getApplication()).inflate(R.layout.float_layout_window, null);
            mText = (LinearLayout) mWindowView.findViewById(R.id.linear);
        }
        mWindowManager.addView(mWindowView, wmParams);
    }

    /**
     * 点击事件和拖拽事件
     */
    int mStartX, mStartY;
    int mEndX, mEndY;

    private void initClick() {
        mText.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    //按下鼠标的时候记录下屏幕的位置
                    case MotionEvent.ACTION_DOWN:
                        mStartX = (int) event.getRawX();
                        mStartY = (int) event.getRawY();

                        break;
                    case MotionEvent.ACTION_MOVE:
                        mEndX = (int) event.getRawX();
                        mEndY = (int) event.getRawY();
                        if (needIntercept()) {
                            //getRawX是触摸位置相对于整个屏幕的位置,getX是控触摸点相对于控件最左边的位置
                            wmParams.x = (int) event.getRawX() - mWindowView.getMeasuredWidth() / 2;
                            wmParams.y = (int) event.getRawY() - mWindowView.getMeasuredHeight() / 2;
                            mWindowManager.updateViewLayout(mWindowView, wmParams);
                            return true;
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                        if (needIntercept()) {
                            return true;
                        }
                        break;
                }

                return false;
            }
        });

        mText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(FloatWindowsActivity.this, "点击悬浮框", Toast.LENGTH_SHORT).show();
            }
        });
    }

    /**
     * 判断是否拦截,根据滑动的距离
     *
     * @return
     */
    private boolean needIntercept() {
        if (Math.abs(mStartX - mEndX) > 30 || Math.abs(mStartY - mEndY) > 30) {
            return true;
        }
        return false;
    }
}

8.4 Rendering

Can be displayed in any Activity

 You can also return to the desktop and still display

Guess you like

Origin blog.csdn.net/qq_29848853/article/details/131057663