タオバオ商品リストのドロップダウン フィルター ポップアップ ウィンドウに似た、部分的に影のあるポップアップ ウィンドウ

ここに画像の説明を挿入

1. Xpopup ライブラリに基づいて、ドロップダウン フィルターのポップアップ ウィンドウを実現します。

/**
 *  局部阴影的弹窗,类似于淘宝商品列表的下拉筛选弹窗
 */
public abstract class PartShadowPopupView extends BasePopupView {
    protected PartShadowContainer attachPopupContainer;
    public PartShadowPopupView(@NonNull Context context) {
        super(context);
        attachPopupContainer = findViewById(R.id.attachPopupContainer);
        attachPopupContainer.popupView = this;
    }

    @Override
    final protected int getInnerLayoutId() {
        return R.layout._xpopup_partshadow_popup_view;
    }
    protected void addInnerContent() {
        View contentView = LayoutInflater.from(getContext()).inflate(getImplLayoutId(), attachPopupContainer, false);
        attachPopupContainer.addView(contentView);
    }

    @Override
    protected void initPopupContent() {
        if (attachPopupContainer.getChildCount() == 0) addInnerContent();
        // 指定阴影动画的目标View
        if (popupInfo.hasShadowBg) {
            shadowBgAnimator.targetView = getPopupContentView();
        }

        getPopupImplView().setTranslationX(popupInfo.offsetX);
        getPopupImplView().setTranslationY(popupInfo.offsetY);
        getPopupImplView().setAlpha(0);
        XPopupUtils.applyPopupSize((ViewGroup) getPopupContentView(), getMaxWidth(), getMaxHeight(),
                getPopupWidth(), getPopupHeight(), new Runnable() {
            @Override
            public void run() {
                doAttach();
            }
        });
    }

    @Override
    protected void doMeasure() {
        super.doMeasure();
        XPopupUtils.applyPopupSize((ViewGroup) getPopupContentView(), getMaxWidth(), getMaxHeight(),
                getPopupWidth(), getPopupHeight(), new Runnable() {
                    @Override
                    public void run() {
                        doAttach();
                    }
                });
    }

    private boolean hasInit = false;
    private void initAndStartAnimation(){
        if(hasInit) return;
        hasInit = true;
        initAnimator();
        doShowAnimation();
        doAfterShow();
    }

    @Override
    protected void onDismiss() {
        super.onDismiss();
        hasInit = false;
    }

    public boolean isShowUp;
    public void doAttach() {
        if (popupInfo.atView == null)
            throw new IllegalArgumentException("atView() must be called before show()!");

        //1. apply width and height
        ViewGroup.MarginLayoutParams params = (MarginLayoutParams) getPopupContentView().getLayoutParams();
        //1. 获取atView在屏幕上的位置
        Rect rect = popupInfo.getAtViewRect();
        int centerY = rect.top + rect.height() / 2;
        View implView = getPopupImplView();
        FrameLayout.LayoutParams implParams = (LayoutParams) implView.getLayoutParams();
        if ((centerY > getMeasuredHeight() / 2 || popupInfo.popupPosition == PopupPosition.Top) && popupInfo.popupPosition != PopupPosition.Bottom) {
            // 说明atView在Window下半部分,PartShadow应该显示在它上方,计算atView之上的高度
            params.height = rect.top;
            isShowUp = true;
            implParams.gravity = Gravity.BOTTOM;
            if (getMaxHeight() > 0)
                implParams.height = Math.min(implView.getMeasuredHeight(), getMaxHeight());
        } else {
            // atView在上半部分,PartShadow应该显示在它下方,计算atView之下的高度
            params.height = getMeasuredHeight() - rect.bottom;
            isShowUp = false;
            params.topMargin = rect.bottom;
            implParams.gravity = Gravity.TOP;
            if (getMaxHeight() > 0)
                implParams.height = Math.min(implView.getMeasuredHeight(), getMaxHeight());
        }

        getPopupContentView().setLayoutParams(params);
        implView.setLayoutParams(implParams);
        getPopupContentView().post(new Runnable() {
            @Override
            public void run() {
                initAndStartAnimation();
                getPopupImplView().setAlpha(1);
            }
        });
        attachPopupContainer.notDismissArea = popupInfo.notDismissWhenTouchInArea;
        attachPopupContainer.setOnClickOutsideListener(new OnClickOutsideListener() {
            @Override
            public void onClickOutside() {
                if (popupInfo.isDismissOnTouchOutside) dismiss();
            }
        });
    }
    @Override
    protected PopupAnimator getPopupAnimator() {
        return new TranslateAnimator(getPopupImplView(), getAnimationDuration(), isShowUp ?
                PopupAnimation.TranslateFromBottom : PopupAnimation.TranslateFromTop);
    }
}

2. 基本クラスを継承してカスタム ポップアップ ウィンドウを実現します。

class TutorialFilterDialog(context: Context, private val type: Int, private var rvType: Int = 0,
                           private val typeCallback: (selectType: Int, selectText: String) -> Unit
) : PartShadowPopupView(context) {

    override fun getImplLayoutId(): Int {
        return R.layout.layout_tutoriall_search_filter
    }

    override fun onCreate() {
        initView()
        initData()
        initListener()
    }

    private fun initView() {
        
    }

    private fun initData() {

    }

    private fun initListener() {

    }
}

3. ポップアップ ウィンドウを使用します: TutorialFilterDialog

  //显示筛选弹窗
    private fun showFilterDialog(type: Int, rvType: Int) {
        XPopup.Builder(context)
            .atView(binding.llSearch)
            .isDestroyOnDismiss(true)
            .navigationBarColor(ColorUtils.getColor(R.color.white))
            .setPopupCallback(object : SimpleCallback() {
                override fun onDismiss(popupView: BasePopupView?) {

                }
            })
            .asCustom(TutorialFilterDialog(requireContext(), type, rvType) { sType, sText ->

            }).show()
    }

おすすめ

転載: blog.csdn.net/zhijiandedaima/article/details/131072765