IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android通用PopupWindow的封装 -> 正文阅读

[移动开发]Android通用PopupWindow的封装

日常开发中或多或少都会使用到PopupWindow,每次都需要自定义继承至PopupWindow的view,写多了不胜其烦,今天我们对PopupWindow做个封装,可通过链式构建,支持View方式或ViewDataBinding方式设置ContentView(类似的封装可看我的另外一篇文章Android通用Dialog的封装)。
在这里插入图片描述
先看使用示例:

1、通过View的方式构建,这里的SortingFilterLayout是我们自定义的一个View

new CommonPopupWindow.ViewBuilder<SortingFilterLayout>()
                    .width(ConstraintLayout.LayoutParams.WRAP_CONTENT)
                    .height(ConstraintLayout.LayoutParams.WRAP_CONTENT)
                    .outsideTouchable(true)
                    .focusable(true)
                    .animationStyle(R.style.sorting_filter_pop_animation)
                    .clippingEnabled(false)
                    .alpha(0.618f)
                    .view(new SortingFilterLayout(context))
                    .intercept(new CommonPopupWindow.ViewEvent<SortingFilterLayout>() {
                        @Override
                        public void getView(CommonPopupWindow commonPopupWindow, SortingFilterLayout view) {
                            /*在这里可做初始化相关操作*/
                        }
                    })
                    .onShowBefore(new CommonPopupWindow.OnShowBefore<SortingFilterLayout>() {
                        @Override
                        public void showBefore(CommonPopupWindow popupWindow, SortingFilterLayout view) {
                            /*每次show之前都会回调*/
                        }
                    })
                    .onDismissListener(new PopupWindow.OnDismissListener() {
                        @Override
                        public void onDismiss() {
                             /*每次dismiss都会回调*/
                        }
                    })
                    .build(context)
                    .showAtLocation(view, Gravity.RIGHT, 0, 0);

2、通过ViewDataBinding的方式构建,这里的layout_sorting_filter是我们自定义View的xml文件,LayoutSortingFilterBinding是对应的ViewDataBinding

new CommonPopupWindow.ViewDataBindingBuilder<LayoutSortingFilterBinding>()
            .width(ConstraintLayout.LayoutParams.WRAP_CONTENT)
            .height(ConstraintLayout.LayoutParams.WRAP_CONTENT)
            .outsideTouchable(true)
            .focusable(true)
            .animationStyle(R.style.sorting_filter_pop_animation)
            .clippingEnabled(false)
            .alpha(0.618f)
            .layoutId(mRootView.getActivity(),R.layout.layout_sorting_filter)
            .intercept(new CommonPopupWindow.ViewEvent<LayoutSortingFilterBinding>() {
                @Override
                public void getView(CommonPopupWindow commonPopupWindow, LayoutSortingFilterBinding binding) {
                    /*在这里可做初始化相关操作*/
                }
            })
            .onShowBefore(new CommonPopupWindow.OnShowBefore<LayoutSortingFilterBinding>() {
                @Override
                public void showBefore(CommonPopupWindow popupWindow, LayoutSortingFilterBinding binding) {
                     /*每次show之前都会回调*/
                }
            })
            .onDismissListener(new PopupWindow.OnDismissListener() {
                @Override
                public void onDismiss() {
                     /*每次dismiss都会回调*/
                }
            })
            .build(context)
            .showAtLocation(view,Gravity.RIGHT,0,0);

在这里插入图片描述
CommonPopupWindow完整的代码如下:

import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.PopupWindow;

import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;

/**
 * 作者:可口可乐的可乐 on 2020/01/07 17:57
 * Email : 1966353889@qq.com
 * Describe:通用PopupWindow
 */
public abstract class CommonPopupWindow<V extends View, Binding extends ViewDataBinding> extends PopupWindow {
    private OnDismissListener onDismissListener;

    private CommonPopupWindow(Context context, ViewDataBindingBuilder<Binding> builder) {
        super(context);
        getIntercept().intercept();
        setContentView(builder.mBinding.getRoot());
        setWidth(builder.mWidth);
        setHeight(builder.mHeight);
        setOutsideTouchable(builder.mOutsideTouchable);
        setBackgroundDrawable(builder.mBackground);
        setFocusable(builder.mFocusable);
        /*
         * 结合showAtLocation使用精准定位,需设置mClippingEnabled为false,否则当内容过多时会移位,比如设置在某
         * 个控件底下内容过多时popupwindow会上移
         */
        setClippingEnabled(builder.mClippingEnabled);
        setAnimationStyle(builder.mAnimationStyle);
        onDismissListener = builder.onDismissListener;
        super.setOnDismissListener(new OnDismissListener() {
            @Override
            public void onDismiss() {
                if (context instanceof Activity) {
                    WindowManager.LayoutParams lp = ((Activity) context).getWindow().getAttributes();
                    if (lp != null && lp.alpha != 1.0f) {
                        lp.alpha = 1.0f; /* 0.0~1.0*/
                        ((Activity) context).getWindow().setAttributes(lp);
                    }
                }
                if (onDismissListener != null) {
                    onDismissListener.onDismiss();
                }
                if (builder.mBinding != null) {
                    builder.mBinding.unbind();
                }
            }
        });
    }


    private CommonPopupWindow(Context context, ViewBuilder<V> builder) {
        super(context);
        getIntercept().intercept();
        setContentView(builder.view);
        setWidth(builder.mWidth);
        setHeight(builder.mHeight);
        setOutsideTouchable(builder.mOutsideTouchable);
        setBackgroundDrawable(builder.mBackground);
        setFocusable(builder.mFocusable);
        /*
         * 结合showAtLocation使用精准定位,需设置mClippingEnabled为false,否则当内容过多时会移位,比如设置在某
         * 个控件底下内容过多时popupwindow会上移
         */
        setClippingEnabled(builder.mClippingEnabled);
        setAnimationStyle(builder.mAnimationStyle);
        onDismissListener = builder.onDismissListener;
        super.setOnDismissListener(new OnDismissListener() {
            @Override
            public void onDismiss() {
                if (context instanceof Activity) {
                    WindowManager.LayoutParams lp = ((Activity) context).getWindow().getAttributes();
                    if (lp != null && lp.alpha != 1.0f) {
                        lp.alpha = 1.0f; /* 0.0~1.0*/
                        ((Activity) context).getWindow().setAttributes(lp);
                    }
                }
                if (onDismissListener != null) {
                    onDismissListener.onDismiss();
                }
            }
        });
    }

    @Override
    public void showAsDropDown(View anchor, int xoff, int yoff) {
        if (getContentView() != null) {
            Context context = getContentView().getContext();
            if (context instanceof Activity) {
                WindowManager.LayoutParams lp = ((Activity) context).getWindow().getAttributes();
                if (lp != null && lp.alpha != getAlpha()) {
                    lp.alpha = getAlpha();
                    ((Activity) context).getWindow().setAttributes(lp);
                }
            }
        }
        getIntercept().showBefore();
        super.showAsDropDown(anchor, xoff, yoff);
        getIntercept().showAfter();
    }

    @Override
    public void showAtLocation(View parent, int gravity, int x, int y) {
        if (getContentView() != null) {
            Context context = getContentView().getContext();
            if (context instanceof Activity) {
                WindowManager.LayoutParams lp = ((Activity) context).getWindow().getAttributes();
                if (lp != null && lp.alpha != getAlpha()) {
                    lp.alpha = getAlpha();
                    ((Activity) context).getWindow().setAttributes(lp);
                }
            }
        }
        getIntercept().showBefore();
        super.showAtLocation(parent, gravity, x, y);
        getIntercept().showAfter();
    }

    @Override
    public void setOnDismissListener(OnDismissListener onDismissListener) {
        this.onDismissListener = onDismissListener;
    }

    abstract float getAlpha();

    abstract CommonPopupWindow getInstance();

    abstract InterceptTransform getIntercept();

    public static class ViewDataBindingBuilder<Binding extends ViewDataBinding> {
        private Binding mBinding;
        private int mWidth;
        private int mHeight;
        private boolean mOutsideTouchable;
        private ViewEvent<Binding> mEvent;
        private Drawable mBackground;
        private boolean mFocusable;
        /**
         * 设置窗口弹出时背景的透明度
         * 0f(透明)~1.0f(正常)
         * 设置了alpha时需要在onDismiss恢复窗口的alpha至默认值即1.0f
         */
        private float alpha = 1.0f;
        /**
         * 结合showAtLocation使用精准定位,需设置mClippingEnabled为false,否则当内容过多时会移位,比如设置在某
         * 个控件底下内容过多时popupwindow会上移
         */
        private boolean mClippingEnabled = true;
        private OnShowBefore<Binding> mOnShowBefore;
        private OnShowAfter<Binding> mOnShowAfter;
        private int mAnimationStyle = -1;
        private OnDismissListener onDismissListener;

        public ViewDataBindingBuilder<Binding> layoutId(Context context, int layoutId) {
            this.mBinding = DataBindingUtil.inflate(LayoutInflater.from(context), layoutId, null, false);
            return this;
        }

        public ViewDataBindingBuilder<Binding> viewDataBinding(Binding mBinding) {
            this.mBinding = mBinding;
            return this;
        }

        public ViewDataBindingBuilder<Binding> width(int width) {
            this.mWidth = width;
            return this;
        }

        public ViewDataBindingBuilder<Binding> height(int height) {
            this.mHeight = height;
            return this;
        }

        public ViewDataBindingBuilder<Binding> outsideTouchable(boolean outsideTouchable) {
            this.mOutsideTouchable = outsideTouchable;
            return this;
        }

        public ViewDataBindingBuilder<Binding> backgroundDrawable(Drawable background) {
            this.mBackground = background;
            return this;
        }

        public ViewDataBindingBuilder<Binding> focusable(boolean focusable) {
            this.mFocusable = focusable;
            return this;
        }

        public ViewDataBindingBuilder<Binding> alpha(float alpha) {
            this.alpha = alpha;
            return this;
        }

        public ViewDataBindingBuilder<Binding> clippingEnabled(boolean clippingEnabled) {
            this.mClippingEnabled = clippingEnabled;
            return this;
        }

        public ViewDataBindingBuilder<Binding> onShowBefore(OnShowBefore<Binding> showBefore) {
            this.mOnShowBefore = showBefore;
            return this;
        }

        public ViewDataBindingBuilder<Binding> onShowAfter(OnShowAfter<Binding> showAfter) {
            this.mOnShowAfter = showAfter;
            return this;
        }

        public ViewDataBindingBuilder<Binding> animationStyle(int animationStyle) {
            this.mAnimationStyle = animationStyle;
            return this;
        }

        public ViewDataBindingBuilder<Binding> intercept(ViewEvent<Binding> event) {
            this.mEvent = event;
            return this;
        }

        public ViewDataBindingBuilder<Binding> onDismissListener(OnDismissListener onDismissListener) {
            this.onDismissListener = onDismissListener;
            return this;
        }

        public <V extends View> CommonPopupWindow<V, Binding> build(Context context) {
            return new CommonPopupWindow<V, Binding>(context, this) {
                @Override
                public float getAlpha() {
                    return alpha;
                }

                @Override
                CommonPopupWindow getInstance() {
                    return this;
                }

                @Override
                InterceptTransform getIntercept() {
                    return new InterceptTransform<Binding>() {
                        @Override
                        public void showBefore() {
                            if (mOnShowBefore != null) {
                                mOnShowBefore.showBefore(getInstance(), mBinding);
                            }
                        }

                        @Override
                        public void showAfter() {
                            if (mOnShowAfter != null) {
                                mOnShowAfter.showAfter(getInstance(), mBinding);
                            }
                        }

                        @Override
                        public void intercept() {
                            if (mEvent != null) {
                                mEvent.getView(getInstance(), mBinding);
                            }
                        }
                    };
                }
            };
        }
    }

    public static class ViewBuilder<V extends View> {
        private V view;
        private int mWidth;
        private int mHeight;
        private boolean mOutsideTouchable;
        private ViewEvent<V> mEvent;
        private Drawable mBackground;
        private boolean mFocusable;
        /**
         * 设置窗口弹出时背景的透明度
         * 0f(透明)~1.0f(正常)
         * 设置了alpha时需要在onDismiss恢复窗口的alpha至默认值即1.0f
         */
        private float alpha = 1.0f;
        /**
         * 结合showAtLocation使用精准定位,需设置mClippingEnabled为false,否则当内容过多时会移位,比如设置在某
         * 个控件底下内容过多时popupwindow会上移
         */
        private boolean mClippingEnabled = true;
        private OnShowBefore<V> mOnShowBefore;
        private OnShowAfter<V> mOnShowAfter;
        private int mAnimationStyle = -1;
        private OnDismissListener onDismissListener;

        public ViewBuilder<V> view(@NonNull V view) {
            this.view = view;
            return this;
        }

        public ViewBuilder<V> width(int width) {
            this.mWidth = width;
            return this;
        }

        public ViewBuilder<V> height(int height) {
            this.mHeight = height;
            return this;
        }

        public ViewBuilder<V> outsideTouchable(boolean outsideTouchable) {
            this.mOutsideTouchable = outsideTouchable;
            return this;
        }

        public ViewBuilder<V> backgroundDrawable(Drawable background) {
            this.mBackground = background;
            return this;
        }

        public ViewBuilder<V> focusable(boolean focusable) {
            this.mFocusable = focusable;
            return this;
        }

        public ViewBuilder<V> alpha(float alpha) {
            this.alpha = alpha;
            return this;
        }

        public ViewBuilder<V> clippingEnabled(boolean clippingEnabled) {
            this.mClippingEnabled = clippingEnabled;
            return this;
        }

        public ViewBuilder<V> onShowBefore(OnShowBefore<V> showBefore) {
            this.mOnShowBefore = showBefore;
            return this;
        }

        public ViewBuilder<V> onShowAfter(OnShowAfter<V> showAfter) {
            this.mOnShowAfter = showAfter;
            return this;
        }

        public ViewBuilder<V> animationStyle(int animationStyle) {
            this.mAnimationStyle = animationStyle;
            return this;
        }

        public ViewBuilder<V> intercept(ViewEvent<V> event) {
            this.mEvent = event;
            return this;
        }

        public ViewBuilder<V> onDismissListener(OnDismissListener onDismissListener) {
            this.onDismissListener = onDismissListener;
            return this;
        }

        public <T extends ViewDataBinding> CommonPopupWindow<V, T> build(Context context) {
            return new CommonPopupWindow<V, T>(context, this) {

                @Override
                public float getAlpha() {
                    return alpha;
                }

                @Override
                CommonPopupWindow getInstance() {
                    return this;
                }

                @Override
                InterceptTransform getIntercept() {
                    return new InterceptTransform<V>() {
                        @Override
                        public void showBefore() {
                            if (mOnShowBefore != null) {
                                mOnShowBefore.showBefore(getInstance(), view);
                            }
                        }

                        @Override
                        public void showAfter() {
                            if (mOnShowAfter != null) {
                                mOnShowAfter.showAfter(getInstance(), view);
                            }
                        }

                        @Override
                        public void intercept() {
                            if (mEvent != null) {
                                mEvent.getView(getInstance(), view);
                            }
                        }
                    };
                }
            };
        }
    }

    public interface ViewEvent<T> {
        void getView(CommonPopupWindow popupWindow, T view);
    }

    public static abstract class InterceptTransform<V> {
        public abstract void showBefore();

        public abstract void showAfter();

        public abstract void intercept();
    }

    public interface OnShowBefore<V> {
        void showBefore(CommonPopupWindow popupWindow, V view);
    }

    public interface OnShowAfter<V> {
        void showAfter(CommonPopupWindow popupWindow, V view);
    }
}

代码的注释比较清晰,就不做过多说明了,有疑问的朋友欢迎在评论区留言。
在这里插入图片描述
搞定,收工。

希望本文可以帮助到您,也希望各位不吝赐教,提出您在使用中的宝贵意见,谢谢。

如果可以的话,也可以扫一扫下方的二维码请作者喝一杯奶茶哈
在这里插入图片描述
谢谢您的观看。
有问题可发送至:1966353889@qq.com
欢迎交流,共同进步。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-23 10:54:40  更:2021-07-23 10:56:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/28 17:12:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码