美文网首页
PopUpWindow 模拟IOS微信长按弹出选择框,选项过多时

PopUpWindow 模拟IOS微信长按弹出选择框,选项过多时

作者: feifei_fly | 来源:发表于2019-06-19 15:29 被阅读0次

PopUpWindow 有两个常用接口:

一、public void showAsDropDown(View anchor, int xoff, int yoff)

showAsDropDown(View anchor, int xoff, int yoff)这个API见名思意就是PopupWindow显示在anchor周围。默认的坐标原点是anchor的左下角。

off/yoff的坐标系也是以anchor这个View的左下角为坐标原点。

xoff为正PopupWindow就会向右偏;yoff为正PopupWindow就向下偏。


   /**
     * Display the content view in a popup window anchored to the bottom-left
     * corner of the anchor view. If there is not enough room on screen to show
     * the popup in its entirety, this method tries to find a parent scroll
     * view to scroll. If no parent scroll view can be scrolled, the
     * bottom-left corner of the popup is pinned at the top left corner of the
     * anchor view.
     *
     * @param anchor the view on which to pin the popup window
     *
     * @see #dismiss()
     */
public void showAsDropDown(View anchor)

    /**
     * Display the content view in a popup window anchored to the bottom-left
     * corner of the anchor view offset by the specified x and y coordinates.
     * If there is not enough room on screen to show the popup in its entirety,
     * this method tries to find a parent scroll view to scroll. If no parent
     * scroll view can be scrolled, the bottom-left corner of the popup is
     * pinned at the top left corner of the anchor view.
     * <p>
     * If the view later scrolls to move <code>anchor</code> to a different
     * location, the popup will be moved correspondingly.
     *
     * @param anchor the view on which to pin the popup window
     * @param xoff A horizontal offset from the anchor in pixels
     * @param yoff A vertical offset from the anchor in pixels
     *
     * @see #dismiss()
     */
public void showAsDropDown(View anchor, int xoff, int yoff)

二、 public void showAtLocation(View parent, int gravity, int x, int y)

showAtLocation() 可以让PopUpWindow显示在DecorView的任意地方,参数x和y的坐标也是相对于整个Screen来说的。


    /**
     * <p>
     * Display the content view in a popup window at the specified location. If the popup window
     * cannot fit on screen, it will be clipped. See {@link android.view.WindowManager.LayoutParams}
     * for more information on how gravity and the x and y parameters are related. Specifying
     * a gravity of {@link android.view.Gravity#NO_GRAVITY} is similar to specifying
     * <code>Gravity.LEFT | Gravity.TOP</code>.
     * </p>
     *
     * @param parent a parent view to get the {@link android.view.View#getWindowToken()} token from
     * @param gravity the gravity which controls the placement of the popup window
     * @param x the popup's x location offset
     * @param y the popup's y location offset
     */
    public void showAtLocation(View parent, int gravity, int x, int y)

1、第一个参数parent,popUpWindow从parent获取WindowToken,该参数不影响popupWindow的位置。

a parent view to get the {@link android.view.View#getWindowToken()} token from

2、第二个参数gravity就是设置屏幕坐标原点。

Gravity.LEFT | Gravity.TOP就是以屏幕左上角为坐标原点。

3、第三个参数x就是在屏幕坐标系上的x坐标,第四个参数就是y坐标了。

  • 以屏幕的左上角为坐标原点。popUpWindwo的左上角定位到(100,200)的位置。
    或者可以理解为将屏幕的左上角为坐标原点,首先将popupWindow 的左上角放置到屏幕左上角,然后将popupWindow向右移动100,向下移动200
gravity = Gravity.LEFT | Gravity.TOP
x = 100
y = 200
  • 以屏幕的右上角为坐标原点。popUpWindwo的右上角定位到(100,200)的位置。
    或者可以理解为将屏幕的右上角为坐标原点,首先将popupWindow 的右上角放置到屏幕的右上角,然后将popupWindow向左移动100,向下移动200
gravity = Gravity.RIGHT | Gravity.TOP
x = 100
y = 200
  • 以屏幕的左下角为坐标原点。popUpWindwo的左下角定位到(100,200)的位置。
    或者可以理解为将屏幕的左下角为坐标原点,首先将popupWindow 的左下角放置到屏幕的左下角,然后将popupWindow向右移动100,向上移动200
gravity = Gravity.LEFT | Gravity.BOTTOM
x = 100
y = 200
  • 以屏幕的右下角为坐标原点。popUpWindwo的右下角定位到(100,200)的位置。
    或者可以理解为将屏幕的右下角为坐标原点,首先将popupWindow 的右下角放置到屏幕的右下角,然后将popupWindow向左移动100,向上移动200
gravity = Gravity.RIGHT | Gravity.BOTTOM
x = 100
y = 200

三、利用popUpWindow 模仿IOS 的长按弹出选择框控件,选项超出屏幕宽度后,支持分屏显示。


public class PopSelectWindow extends PopupWindow {

    public static final String TAG =PopSelectWindow.class.getSimpleName();

    private PopSelectWindow(Context context){
        super(context);
        mContext = context;
    }

    public PopSelectWindow(Builder builder){
        super(builder.mContext);
        mContext = builder.mContext;
        mSelectOptions.clear();
        mSelectOptions.addAll(builder.mSelectOptions);
        mListeners.clear();
        mListeners.putAll(builder.mListeners);
        mTextSize = builder.mTextSize;
        mPopUpViewWidth = builder.mPopUpViewWidth;
        mPopUpViewHeight = builder.mPopUpViewHeight;
        mOption_margin = builder.mOption_margin;
        mPopUpViewMarginTop = builder.mPopUpViewMarginTop;
        mPopUpviewMarginBottom = builder.mPopUpviewMarginBottom;
    }


    public static final int DefaultTextSize = 18;
    public static final int DefaultPopUpViewWidth = 470;
    public static final int DefaultPopUpViewHeight = 62;
    public static final int DefaultPopUpViewMarginTop = 5;
    public static final int DefaultPopUpViewMarginBottom = 5;
    public static final int DefaultOptionMargin = 10;

    private Context mContext;
    private int mTextSize = DefaultTextSize;//选项文本字体大小sp
    private int mPopUpViewWidth = DefaultPopUpViewWidth;// 470
    private int mPopUpViewHeight = DefaultPopUpViewHeight;//popUpWindow 的高度,单位px
    private int mPopUpViewMarginTop = DefaultPopUpViewMarginTop;//popUpView 距离AnchorView的距离
    private int mPopUpviewMarginBottom = DefaultPopUpViewMarginBottom;
    private int mOption_margin = DefaultOptionMargin;//px //选项之前的间隔,单位px

    private List<String>mSelectOptions = new ArrayList<>();
    private Map<String,PopSelectionListener> mListeners = new HashMap();
    private Map<Integer,List<TheOption>> mPageData = new HashMap<>();// Integer 代表页面的编号,List<TheOption> 代表该页面对应的选项集合(包括左箭头和右箭头)

    private int mTotalPage = 0;//总分页数
    public int mCurrentPage = 0;//当前的页码


    public void putPageData(Integer page,TheOption theOption){
        List<TheOption> theOptionList = mPageData.get(page);
        if(theOptionList == null){
            theOptionList = new ArrayList<>();
        }
        theOptionList.add(theOption);
        mPageData.put(page,theOptionList);
    }
    public void addLeftArrow(List<TheOption>theOptions){
        if(theOptions != null){
            theOptions.add(0,TheOption.createLeftArrow());
        }
    }

    public void addRightArrow(List<TheOption>theOptions){
        if(theOptions != null){
            theOptions.add(TheOption.createRightArrow());
        }
    }


    public int calculateSingleOptionWidth(String optionStr){
        TextView textView = new TextView(mContext);
        textView.setTextSize(mTextSize);
        TextPaint textPaint = textView.getPaint();
        float width = textPaint.measureText(optionStr);
        int finalWidth = (int)width+ mOption_margin*2;
        LogUtil.d(TAG,"calculateTotalNeedWidth:"+width+",option:"+optionStr);
        return finalWidth;
    }


    public void calculate(){
        int totalNeedWidth = 0;
        int totalPages = 0;
        for(int i = 0;i< mSelectOptions.size();i++){
            String optionStr = mSelectOptions.get(i);
            TheOption theOption = new TheOption();
            theOption.mOptionName = optionStr;
            theOption.needWidth = calculateSingleOptionWidth(optionStr);
            theOption.mListener = mListeners.get(optionStr);
            totalNeedWidth+=theOption.needWidth;
            boolean isPageFull = totalNeedWidth> mPopUpViewWidth;

            if(isPageFull){
                totalPages++;
                totalNeedWidth= theOption.needWidth;
            }

            theOption.page = totalPages;
            putPageData(totalPages,theOption);
        }
        LogUtil.d(TAG,"calculate:"+totalPages);
        mTotalPage = totalPages;
        for(int i = 0 ;i <= mTotalPage;i++){

            if(mTotalPage > 0 ){ //数据多于一页
                if(i == 0 ){ //针对第一页:如果数据多于一页,则为第一页 尾部增加一个右向箭头
                    addRightArrow(mPageData.get(i));
                }else if(i == mTotalPage){//针对最后一页:如果数据多余一页,则为最后一页头部,怎家一个左向箭头
                    addLeftArrow(mPageData.get(i));
                }else {//针对中间的选项:如果数据多余一页,则为该页数据 增加左向箭头和右向箭头
                    addLeftArrow(mPageData.get(i));
                    addRightArrow(mPageData.get(i));
                }
            }else {//数据只有一页,则不用添加左向箭头和右向箭头
                //do nothing
            }

        }
//        printData();
    }

    public void printData(){
        for(Integer index:mPageData.keySet()){
            LogUtil.d(TAG,"feifei page---------------:"+index);
            List<TheOption> options = mPageData.get(index);
            if(options == null){
                return;
            }

            for(int i = 0 ;i< options.size();i++){
                LogUtil.d(TAG,"feifei page- selection:"+options.get(i).mOptionName+",needWidth:"+options.get(i).needWidth);
            }
        }
    }


    LinearLayout ll_content;
    ImageView iv_top_arrow;
    ImageView iv_bottom_arrow;


    public void show_AtLocation(View anchorView,int leftX,int topY,int screenCenterY){

        View container = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.layout_pop_selection, null);

        ll_content = (LinearLayout) container.findViewById(R.id.ll_content);
        iv_top_arrow = (ImageView)container.findViewById(R.id.iv_top_arrow);
        iv_bottom_arrow = (ImageView)container.findViewById(R.id.iv_bottom_arrow);


        DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
        int screenHeigth = SystemFacade.getScreenHeight(anchorView.getContext());
        int screenWidth = SystemFacade.getScreenWidth(anchorView.getContext());
        int anchorViewHeidht = anchorView.getHeight();
        int anchorViewWidth = anchorView.getWidth();

        boolean needShowUp = false;
        if(topY+anchorViewHeidht+ mPopUpViewHeight >screenHeigth){
            needShowUp = true;
        }

        int moveX = 0;
        int moveY = 0;

        int centerY_Up = (topY - mPopUpViewHeight -mPopUpViewMarginTop);
        int centerY_Down = (topY + anchorViewHeidht+mPopUpviewMarginBottom);

        //centerY_Up和centerY_Down 哪个距离屏幕中心位置较近,则以哪个为准,进行显示。
        if(screenCenterY-centerY_Up < centerY_Down-screenCenterY){
            needShowUp = true;
        }else {
            needShowUp = false;
        }

        if(needShowUp){ //需要在上放显示
            iv_top_arrow.setVisibility(View.GONE);
            iv_bottom_arrow.setVisibility(View.VISIBLE);
            moveX = (screenWidth- mPopUpViewWidth)/2;
            moveY = (topY - mPopUpViewHeight -mPopUpViewMarginTop);
        }else {
            iv_bottom_arrow.setVisibility(View.GONE);
            iv_top_arrow.setVisibility(View.VISIBLE);
            moveX = (screenWidth- mPopUpViewWidth)/2;
            moveY = (topY + anchorViewHeidht+mPopUpviewMarginBottom);
        }
        moveX = mPopUpViewWidth;
        moveY = mPopUpViewHeight;

        calculate();
        updateView();
        this.setContentView(container);
        this.setBackgroundDrawable(new ColorDrawable(0x00000000));
        this.setOutsideTouchable(false);
        this.setWidth(mPopUpViewWidth);
        this.setFocusable(true);
        //以屏幕左上角未原点,向左和向下移动(moveX, moveY)个距离
//        this.showAtLocation(anchorView, Gravity.TOP|Gravity.LEFT, moveX, moveY);
        this.showAsDropDown(anchorView,moveX,moveY);

    }


    public void updateView(){
        ll_content.removeAllViews();
        if(mCurrentPage < mPageData.size()) {
            List<TheOption> thePageDatas = mPageData.get(mCurrentPage);
            if (thePageDatas != null) {
                for (int index = 0; index < thePageDatas.size(); index++) {
                    TheOption theOption = thePageDatas.get(index);
                    if (theOption.type == TYPE_LEFT_ARROW) {
                        createArrow(theOption.type);

                    } else if (theOption.type == TYPE_OPTION) {

                        createText(theOption);
                        boolean shouldCreateLine = false;
                        if(index == thePageDatas.size() -1 ){ //最后一列 不显示竖线
                            shouldCreateLine = false;
                        }else {
                            if(thePageDatas.size() > 2 && index == thePageDatas.size()-2  //是 某一页中 倒数第二项,切最后一项是箭头,则不显示横线
                                    && thePageDatas.get(index+1).type == TYPE_RIGHT_ARROW){
                                shouldCreateLine = false;
                            }else{
                                shouldCreateLine = true;
                            }
                        }

                        if(shouldCreateLine){
                            createLine();
                        }

                    } else if (theOption.type == TYPE_RIGHT_ARROW) {

                        createArrow(theOption.type);
                    }
                }
            }
        }
    }

    public TextView createLine(){
        TextView line = new TextView(mContext);
        LinearLayout.LayoutParams lineParams = new LinearLayout.LayoutParams(1, 40);
        lineParams.gravity = Gravity.CENTER_VERTICAL;
        line.setLayoutParams(lineParams);
        line.setBackgroundColor(mContext.getColor(R.color.color_252525));
        ll_content.addView(line);
        return line;
    }

    public ImageView createArrow(int type){

        ImageView imageView = new ImageView(mContext);

        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT);
        layoutParams.gravity = Gravity.CENTER_VERTICAL;

        imageView.setLayoutParams(layoutParams);
        imageView.setPadding(5,0,5,0);
        if(type == TYPE_LEFT_ARROW){
            imageView.setImageResource(R.drawable.selctor_selection_left_arrow);
        }else {
            imageView.setImageResource(R.drawable.selector_selection_right_arrow);
        }


        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(type == TYPE_LEFT_ARROW){
                    go2prevPage();
                }else {
                    go2nextPage();
                }

            }
        });
        ll_content.addView(imageView);
        return imageView;
    }

    public void createText(final TheOption theOption){
        TextView textView = new TextView(mContext);
        textView.setTextSize(mTextSize);
        textView.setText(theOption.mOptionName);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT);
        layoutParams.weight = 1.0f;
        textView.setLayoutParams(layoutParams);
        textView.setGravity(Gravity.CENTER);
        textView.setTextColor(mContext.getColor(R.color.color_dddddd));
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                PopSelectWindow.this.dismiss();
                if(theOption.mListener!=null){
                    theOption.mListener.clicked(theOption.mOptionName);
                }
            }
        });
        textView.setBackgroundColor(mContext.getColor(R.color.color_3a3a3a));
        ll_content.addView(textView);

    }

    public void go2nextPage(){
        mCurrentPage++;
        if(mCurrentPage >= mTotalPage){
            mCurrentPage = mTotalPage;
        }
        updateView();
        LogUtil.d(TAG,"go2nextPage:"+mCurrentPage+",totalPage:"+mTotalPage);
    }


    public void go2prevPage(){

        mCurrentPage--;
        if(mCurrentPage <= 0){
            mCurrentPage = 0;
        }
        updateView();
        LogUtil.d(TAG,"go2prevPage:"+mCurrentPage+",totalPage:"+mTotalPage);
    }


    public static class TheOption{
        String mOptionName = "";
        int needWidth = 0;
        int type = TYPE_OPTION;
        int page;
        PopSelectionListener mListener;


        public static TheOption createLeftArrow(){
            TheOption theOption = new TheOption();
            theOption.type = TYPE_LEFT_ARROW;
            theOption.mOptionName="<-";
            return theOption;
        }

        public static TheOption createRightArrow(){
            TheOption theOption = new TheOption();
            theOption.type = TYPE_RIGHT_ARROW;
            theOption.mOptionName="->";
            return theOption;
        }

    }
    public static final int TYPE_LEFT_ARROW = 0;
    public static final int TYPE_OPTION = 1;
    public static final int TYPE_RIGHT_ARROW = 2;





    public static class Builder{

        private Context mContext;
        private List<String>mSelectOptions = new ArrayList<>();
        private Map<String,PopSelectionListener> mListeners = new HashMap();
        private int mTextSize = 18;//选项文本字体大小sp
        private int mPopUpViewWidth = 200;
        private int mOption_margin = 10;//
        private int mPopUpViewHeight = 62;//popUpWindow 的高度,单位px
        private int mPopUpViewMarginTop = 5;//popUpView 距离AnchorView的距离
        private int mPopUpviewMarginBottom = 5;

        public Builder(Context context){
            mContext = context;
        }

        public Builder setTextSize(int textSize){
            mTextSize = textSize;
            return this;
        }

        public Builder setPopUpViewWidth(int width){
            mPopUpViewWidth = width;
            return this;
        }

        public Builder setOptionMargin(int option_margin){
            mOption_margin = option_margin;
            return this;
        }

        public Builder setPopUpViewHeight(int height){
            mPopUpViewHeight = height;
            return this;
        }

        public Builder setPopUpViewMarginTop(int margin_top){
            this.mPopUpViewMarginTop = margin_top;
            return this;
        }

        public Builder setPopUpViewMarginBottom(int margin_bottom){
            this.mPopUpviewMarginBottom = margin_bottom;
            return this;
        }


        public  Builder addItem(String selection,PopSelectionListener listener){
            mSelectOptions.add(selection);
            mListeners.put(selection,listener);
            return this;
        }

        public PopSelectWindow build(){
            PopSelectWindow popSelectWindow = new PopSelectWindow(this);
            return popSelectWindow;
        }
    }

    public interface  PopSelectionListener{
        public void clicked(String msg);
    }



调用方法:

     int navigationHeight = 80; //导航栏高度
         int scrreenHeight = SystemFacade.getScreenHeight(this);
         int screenCenterY = (scrreenHeight-navigationHeight)/2;
          popupWindow = new PopSelectWindow.Builder(this)
                  .setTextSize(18)
                  .setPopUpViewWidth(200)
                  .setPopUpViewHeight(62)
                  .setPopUpViewMarginBottom(5)
                  .setPopUpViewMarginTop(5)
                  .setOptionMargin(10)
                  .addItem(getString(R.string.full_show), new PopSelectWindow.PopSelectionListener() {
                      @Override
                      public void clicked(String msg) {
                          go2BigView(item);
                          LogUtil.d(TAG,"clicked:"+msg);
                      }
                  }).addItem(getString(R.string.text_favorite), new PopSelectWindow.PopSelectionListener() {
                      @Override
                      public void clicked(String msg) {
                          doSinglefavoirteAction(item);
                          LogUtil.d(TAG,"clicked:"+msg);

                      }
                  })
                  .addItem(getString(R.string.text_multi_select), new PopSelectWindow.PopSelectionListener() {
                      @Override
                      public void clicked(String msg) {
                          setMultiSelectMode(true);
                          LogUtil.d(TAG,"clicked:"+msg);
                      }
                  }).addItem(getString(R.string.delete), new PopSelectWindow.PopSelectionListener() {
                      @Override
                      public void clicked(String msg) {
                          showDeleteDialog(item);
                          LogUtil.d(TAG,"clicked:"+msg);
                      }
                  }).addItem(getString(R.string.feedback), new PopSelectWindow.PopSelectionListener() {
                      @Override
                      public void clicked(String msg) {
                          g2oTranslateFeedBack(item);
                          LogUtil.d(TAG,"clicked:"+msg);
                      }
                  })
                  .build();
        popupWindow.show_AtLocation(anchorView,leftX,topY,screenCenterY);

参考文章:

https://www.jianshu.com/p/754a88e7f411

相关文章

网友评论

      本文标题:PopUpWindow 模拟IOS微信长按弹出选择框,选项过多时

      本文链接:https://www.haomeiwen.com/subject/pjskqctx.html