仿唯品会尺码助手弹框 带箭头叉号的popupwindow BubbleLayout

产品大大要一个唯品会一样的尺码助手弹框。首先找到了BubbleLayout,基于BubbleLayout实现该功能。
BubbleLayout项目地址
放一下实现效果吧
这里写图片描述

1.思路:尺码这一部分是一个GridView,没啥说的,在其item的点击事件上监听点击后在原来给尺码赋选取值的基础上弹出popupwindow,popupwindow上的布局外层用相对布局里面嵌套BubbleLayout带三角和一个叉号,里面也是一个GridView用于显示尺码助手
2.具体实现:
popupwindow的布局

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@color/transparent"
    >

    <com.okbuy.android.ui.component.SizeRemindLayout.BubbleLayout

        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/bl_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="10dp"
        android:layout_marginTop="10dp"
        android:padding="0dp"
        app:bl_arrowDirection="bottom"
        app:bl_arrowHeight="5dp"
        app:bl_arrowPosition="0dp"
        app:bl_arrowWidth="8dp"
        app:bl_bubbleColor="#cc000000"
        app:bl_cornersRadius="2dp"
        >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <LinearLayout
                android:id="@+id/ll_only_had"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:orientation="vertical"
                android:paddingTop="4dp"
                android:visibility="gone">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:orientation="horizontal">

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="仅剩"
                        android:textColor="#FFFFFF"
                        android:textSize="10dp"
                        />

                    <TextView
                        android:id="@+id/tv_only_had"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textColor="#D70057"
                        android:textSize="10dp"
                        />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="件"
                        android:textColor="#FFFFFF"
                        android:textSize="10dp"
                        />
                </LinearLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="1dp"
                    android:layout_marginTop="4dp"
                    android:background="#66FFFFFF"/>
            </LinearLayout>

            <com.okbuy.android.ui.recommend.MyGridView
                android:id="@+id/gv_size_table_help"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="0dp"
                android:horizontalSpacing="0dp"
                android:listSelector="@android:color/transparent"
                android:scrollbars="none"
                android:stretchMode="columnWidth"
                android:verticalSpacing="0dp">
            </com.okbuy.android.ui.recommend.MyGridView>
        </LinearLayout>
    </com.okbuy.android.ui.component.SizeRemindLayout.BubbleLayout>

    <ImageView
        android:id="@+id/iv_close"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/image_product_close"/>
</RelativeLayout>

GridView顶部会有仅剩几件的提醒,根据接口数据显示或者隐藏。
这里边有几点是做的时候比较费劲的地方,如BubbleLayout中三角的偏移量是变化的,BubbleLayout提供.setArrowPosition()方法来设置偏移量所以我们只需求得每个item的偏移量即可;由于尺码助手的提示内容不确定导致GridView的长度不是固定的需要获取BubbleLayout的宽高;popupwindow的显示位置。
(1)先来看BubbleLayout的宽高的获取,一开始想法是正常的控价获取宽高:int[] location = new int[2]; 和 .getLocationInWindow方法。但是发现该方法如果是固定的控件比如Textview可以正常获取宽高,GridView的内容不定直接这么写获取不到。所以想来想去只能拆开来计算,计算单个item的宽高在叠加:

        int rows = 1;
        int columns=dataHelper.size();

        int horizontalBorderHeight=(new TeldToastUtils(mContext)).dp2px(9);

        int itemWith = 0;

        int totalHeight = 0;

            //只计算每项高度*行数
            View listItem = listAdapter.getView(0, null, gridView);
            listItem.measure(0, 0); // 计算子项View 的宽高
            totalHeight = listItem.getMeasuredHeight(); // 统计子项的高度
            itemWith = listItem.getMeasuredWidth();
        gridViewHeight = totalHeight+horizontalBorderHeight;
        //宽度+padding以及竖线的宽
        gridViewWith = itemWith * columns+((new TeldToastUtils(mContext)).dp2px(8)*(columns-1));

这里注意的是要考虑padding和分割线的宽度,高度也是根据实际的UI来计算。

(2)三角偏移量
当前我们在尺码的点击onclick中可以得到尺码item的宽高及位置。

                //尺码item的位置
                int[] location = new int[2];
                v.getLocationInWindow(location);
                 //获取屏幕宽高
  WindowManager wm = (WindowManager) mContext
                                    .getSystemService(Context.WINDOW_SERVICE);

   int pmWidth = wm.getDefaultDisplay().getWidth();
   int pmHeight = wm.getDefaultDisplay().getHeight();
   //三角偏移量
   float x;
   if((location[0]+v.getWidth()/2)<(width/2)){
      x = location[0]+(v.getWidth()/2);
   }else {
      if((pmWidth-location[0]-(v.getWidth()/2))<(width/2)){
      x = widthP - pmWidth + location[0]+v.getWidth()/2;
      }else{
      x = widthP/2;
   }
}

这里偏移量的计算公式可以画个草图就知道了,当然前提条件是popupwindow如果空间够大是显示在尺码item的正上方左右对称的基础上此时偏移量就是popupwindow宽度的一半,在靠左和靠右时保证显示的位置是在尺码item的一半的位置。
(3)popupwindow的显示位置。
这个也是最坑爹的,这里有两个方法:popupWindow.showAtLocation()和popupWindow.showAsDropDown()之前一直用第二个在尝试,最后发现第二个方法巨坑,他在整个尺码再屏幕上位置考下时右下的item位置会显示错乱,最后的摸索到一点点规律,在屏幕一半以下的右边会错乱但是不是完全的。很崩溃,最后用第一个方法实现的。现在的已知条件:尺码item的位置以及宽高,popupwindow弹窗的宽高。还是在之上画画找到计算位置的公式(其中width和height是弹窗的宽高,高度动态添加“仅剩”的高度):

 popupWindow.showAtLocation(v, Gravity.TOP|Gravity.LEFT, location[0]+(v.getWidth()/2)-(width/2), location[1]-height);

整个onclick的代码:

  @Override
        public void onClick(View v) {
             // 如果可点击
            if (v.isEnabled()) {


                mRecommendSize = "";
                setSelectSize(position);

                mCallback.selectSize(getSelectSize());

                //尺码弹窗
                RelativeLayout rl  = (RelativeLayout) LayoutInflater.from(mContext).inflate(R.layout.layout_size_remain_bubble, null);
                ImageView ivClose = (ImageView) rl.findViewById(R.id.iv_close);

                bubbleLayout = (BubbleLayout) rl.findViewById(R.id.bl_layout);
                //设置三角朝下
                bubbleLayout.setArrowDirection(ArrowDirection.BOTTOM);

                ivClose.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if(popupWindow.isShowing()){
                            popupWindow.dismiss();
                        }
                    }
                });

                int[] location = new int[2];
                v.getLocationInWindow(location);

                GridView mSizeTableGrid = (GridView) bubbleLayout.findViewById(R.id.gv_size_table_help);
                LinearLayout onlyHad = (LinearLayout) bubbleLayout.findViewById(R.id.ll_only_had);
                TextView textViewOnly = (TextView) bubbleLayout.findViewById(R.id.tv_only_had);

                if(mDetailInfo != null){

                    if (mDetailInfo.getSizeTable() != null) {

                        List<ProductSizeHelper> dataHelper = mDetailInfo.getSizeHelper().get(pSize.sizeName);
                        //还有的尺码没有对照表!!!
                        if(dataHelper !=null && dataHelper.size()>0){

                            mSizeTableGrid.setAdapter(new SizeTableHelperAdapter(mContext, dataHelper));
                            mSizeTableGrid.setNumColumns(dataHelper.size());

                            getGridViewHeight(mSizeTableGrid,dataHelper);

                            if(pSize.leftSizeCount <= 5 ){
                                onlyHad.setVisibility(View.VISIBLE);
                                textViewOnly.setText(""+pSize.leftSizeCount);
                            }else {
                                onlyHad.setVisibility(View.GONE);
                            }

                            //获取尺码弹窗的大小
                            int w = View.MeasureSpec.makeMeasureSpec(0,
                                    View.MeasureSpec.UNSPECIFIED);
                            int h = View.MeasureSpec.makeMeasureSpec(0,
                                    View.MeasureSpec.UNSPECIFIED);
                            onlyHad.measure(w, h);
                            //“仅剩几件”的高度
                            int heightOnly = onlyHad.getMeasuredHeight();
                            //尺码弹窗的高
                            int height = 0;

                            if(pSize.leftSizeCount <= 5 ){
                                height = gridViewHeight+(int)(bubbleLayout.getArrowHeight())+heightOnly;
                            }else{
                                height = gridViewHeight+(int)(bubbleLayout.getArrowHeight());
                            }
                            //尺码弹窗的宽
                            int width = gridViewWith;
                            //偏移量忽略“x”
                            int widthP = gridViewWith-(new TeldToastUtils(mContext)).dp2px(5);

                            //获取屏幕宽高
                            WindowManager wm = (WindowManager) mContext
                                    .getSystemService(Context.WINDOW_SERVICE);

                            int pmWidth = wm.getDefaultDisplay().getWidth();
                            int pmHeight = wm.getDefaultDisplay().getHeight();

                            //三角偏移量
                            float x;

                            if((location[0]+v.getWidth()/2)<(width/2)){
                                x = location[0]+(v.getWidth()/2);
                            }else {

                                if((pmWidth-location[0]-(v.getWidth()/2))<(width/2)){
                                    x = widthP - pmWidth + location[0] +v.getWidth()/2;
                                }else{
                                    x = widthP/2;
                                }
                            }
                            bubbleLayout.setArrowPosition(x);

                            popupWindow = BubblePopupHelper.create(v.getContext(), rl,width);
                            popupWindow.showAtLocation(v, Gravity.TOP|Gravity.LEFT, location[0]+(v.getWidth()/2)-(width/2), location[1]-height);

//                popupWindow.showAsDropDown(v,-(width-v.getWidth())/2,-hWeizhi);
                        }
                    }
                }
            }
        }

这里因为是线上代码,数据源和一些回调可以忽略,根据实际需求就可以。有时间会拆分出demo。

总结:这里主要是获取弹窗的宽高,用于偏移量的计算和设置popupWindow位置,popupwindow的显示位置记得用.showAtLocation()他二者的区别可以自己研究研究,一个是相对于整个的屏幕,一个是相对于父控件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值