Resumen del cuadro de viñetas de Android

una breve introduccion

1.1 El cuadro emergente se refiere a la ventana que flota en la página, como el cuadro emergente del teclado, el cuadro emergente de brindis, el cuadro emergente de confirmación, el cuadro de selección desplegable, el cuadro flotante de la aplicación, etc.

1.2 También hay muchos controles de cuadro de viñetas, como el Spinner, Dialog, Toast, PopWindow, etc., que se usan comúnmente, así como los recientemente agregados SnackBar, DialogFragment, etc.

Selección desplegable de dos Spinner para usar

2.1 Spinner root Listview, Gridview, etc. son productos de la misma era, por lo que el uso es similar a ellos, principalmente usando BaseAdapter para cargar fuentes de datos

2.2  Use el adaptador proporcionado por el sistema , que es fácil de usar, pero el estilo es fijo, el modelo de datos es fijo y solo puede ser de tipo String.

representaciones

Archivo de diseño, agregar control Spinner

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

El archivo java establece la fuente de datos y la configuración.

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();
            }
        });
    }

Nota: El estilo del adaptador del sistema es fijo, existen los siguientes tipos

simple_spinner_dropdown_item (espaciado más alto en la lista es mejor)
simple_spinner_item (el espaciado ajustado en la lista no es atractivo)
simple_list_item_checked (casilla de verificación seleccionada con ranura verde)
simple_list_item_single_choice (botón de radio)

2.3 Adaptador personalizado , alta flexibilidad, puede configurar cualquier tipo de fuente de datos y estilo

representaciones

Diseño de artículo personalizado 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>

Fuente de datos personalizada FruitBean.java

public class FruitBean {
    public String name;

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

Adaptador personalizado 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;

    }
}

adaptador personalizado de configuración giratoria

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);
}

El uso de tres Diálogo

3.1 Dialog es el cuadro de viñetas que se usa con más frecuencia además de Toast. Varios cuadros de carga, cuadros de solicitud y cuadros de selección se usan principalmente en Dialog

3.2 Dialog admite cualquier diseño y posición emergente, por lo que es muy flexible.

3.2 Representaciones de ejemplo

3.3 Crear un cuadro de diálogo personalizado

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>

Configure el estilo de diálogo custom_dialog.style, translucidez, título, fondo, animación emergente, 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>

Necesita heredar la clase principal Dialog del sistema

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();

    }
}

usar

 /**
     * 确认取消提示
     */
    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 Establezca el cuadro de diálogo que considera la ubicación, la siguiente representación se encuentra en la esquina superior derecha de la pantalla y hay una distancia de compensación

 La raíz es la misma que el Diálogo normal, pero se necesita pasar una vista en el constructor, es decir, para que aparezca esa vista, la posición de desplazamiento del Diálogo se establece obteniendo la posición de la vista en la pantalla. el siguiente ejemplo

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 Notas sobre el uso de DIalog:

Dado que DIalog debe depender de una actividad, si la actividad se destruye accidentalmente, aparecerá el cuadro de diálogo o el mensaje no encontrará la actividad, lo que provocará un bloqueo. La solución es la siguiente:

  • Establezca la actividad como una referencia débil para que cuando la actividad se destruya, el objeto que contiene la actividad se pueda reciclar a tiempo.
  • Determine si la actividad está viva antes de que el cuadro de diálogo muestre el mensaje, a fin de garantizar la ventana emergente o el mensaje seguro.

Trátelo de la siguiente manera:

@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();
}

Cuarto, el uso de Toast

4.1 El más fácil de usar, llame al sistema api

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

4.2 Establecer la posición de Toast, superior, medio, inferior, etc.

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

4.3 Controlar la frecuencia emergente en poco tiempo

 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 Personalizar el estilo de diseño de Brindis

 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 Notas sobre el uso:

Después de Android 30, el parámetro de posición de Toast no será válido y la posición establecida seguirá la posición del sistema, por lo que Google recomienda reemplazar Toast con SnackBar.

Si insiste en usar Toast, recomiende una biblioteca de Toast, puede configurar la ubicación de Toast y agregar la biblioteca dependiente de la siguiente manera

implementation 'com.hjq:toast:8.8'

Inicializar en la aplicación

ToastUtils.init(this);

Pop up the Toast en otros lugares

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

Five SnackBar

5.1 

5.2 Fácil de usar

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

El primer parámetro es Contexto, 
el segundo parámetro es la vista que se mostrará,
el tercer parámetro es la cadena que se mostrará
y el cuarto parámetro es la duración de la visualización. Hay tres tipos de duración:
Snackbar.LENGTH_SHORT y Toast.LENGHT_SHORT ( aproximadamente 1 segundo más) desaparecerá automáticamente después de un breve período de visualización.
Snackbar.LENGTH_LONG es lo mismo que Toast.LENGHT_LONG (alrededor de 3 segundos) y
desaparecerá automáticamente después de un período de tiempo relativamente largo.

5.3 Uso interactivo

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 Diseño personalizado SnackBar

diseño 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>

Clase de herramienta 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);
    }
}

 Llame a la clase de herramienta SnackBarUtil

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

Uso del cuadro desplegable Six PopWindow

6.1 PopWindow también es un cuadro emergente Comparado con Dialog, se usa más en la ventana emergente en función de una determinada posición de control, y también admite diseño y estilo arbitrarios.

6.2 Ejemplo, agregar archivo de diseño, 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 Personalizar ventana emergente

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 Configuración del modelo de datos 

publicclass BindSizeListDTO{
        public String id;
        public String name;

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

6.5 Haga aparecer PopupWindow en la posición de vista especificada

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);
}

Siete fragmentos de diálogo

7.1 Dialog depende del ciclo de vida de Activity La diferencia entre DialogFragment y Dialog es que es esencialmente un Fragment, que también tiene el ciclo de vida propiedad de Fragment.

7.1 La forma de crear DialogFragment, use onCreateDialog para crear el Diálogo provisto por el sistema

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

Llame al DialogFragment en la Actividad

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");
    }
}

Efecto:

7.2 Fragmento de diálogo de diseño personalizado

Cree un archivo de diseño 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>

Crear fragmento de diálogo, 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;
    }

}

Actividad llama al DialogFragment

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

Demostración de efectos

Marco de suspensión de ocho sistemas

8.1 El marco flotante del sistema sigue el ciclo de vida de la aplicación, no puede estar por encima de la actividad, no depende de la actividad y es adecuado para el marco emergente del ciclo de vida global

8.2 Use, cree un nuevo archivo de diseño, 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 Agregar permiso de marco flotante

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

8.3 Cree un nuevo FloatWindowsActivity.java y agregue un diseño de marco flotante

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 Representación

Se puede mostrar en cualquier actividad

 También puede volver al escritorio y seguir mostrando

Supongo que te gusta

Origin blog.csdn.net/qq_29848853/article/details/131057663
Recomendado
Clasificación