preface

The effect of the design drawing

End result

Final code common_TV_right_more click event

if (view.getId() == R.id.common_tv_right_more) { new PopTop.Builder(this) .setView(findViewById(r.id.mon_tv_right_more)) // Below some space.setPopToponclick (new poptop.poptoponclick () {@override Public void DelOnclick() {public void DelOnclick() {public void DelOnclick() {public void DelOnclick() {public void DelOnclick() {public void DelOnclick() { }Copy the code

Then I started thinking and learning how to do it.

PopupWindow, as the name implies, is a PopupWindow, which can be seen in many scenarios. Such as an ActionBar/Toolbar option popover, a container for a set of options, or a window for a collection of lists, etc.

The basic use

Using PopupWindow is simple and can be summarized in three steps:

Create PopupWindow instance;

2. Set the background, register event listeners, and add animations;

3. Display PopupWindow.

// View View for PopupWindow contentView= Layoutinflater.from (context).inflate(layoutRes, null, false); // Create the PopupWindow object, where: // The first argument is for the View in PopupWindow, the second argument is for the width of PopupWindow, the third argument is for the height of PopupWindow, PopupWindow =new PopupWindow(contentView, 100, 100, true); / / set the background of PopupWindow window. SetBackgroundDrawable (new ColorDrawable (Color. TRANSPARENT)); / / set the PopupWindow can response to external window. Click on the event setOutsideTouchable (true); // Set PopupWindow to respond to the click event window.settouchable (true); // Display PopupWindow, where: // The first argument is the anchor point of PopupWindow, the second and third arguments are the x and Y offsets of PopupWindow relative to the anchor point window.showAsDropDown(anchor, xoff, yoff); // Alternatively, you can call this method to display PopupWindow, where: // The first argument is the parent View of PopupWindow, the second argument is the position of PopupWindow relative to the parent View, // window. ShowAtLocation (parent, gravity, x, y); // Window.Copy the code

Use the showAsDropDown method to display PopupWindow

Normally, PopupWindow will drop down to the lower left of the anchor after calling the showAsDropDown method. However, if you want PopupWindow to appear above or in the middle of an anchor, you need to use the xoff and yoff arguments of the showAsDropDown method.

Our purpose here is not only to cover the two cases mentioned above (above or in the middle of the anchor), but to cover 5 horizontal and vertical display modes:

  1. Horizontal direction:
    • ALIGN_LEFT: inside the anchor point to the left;
    • ALIGN_RIGHT: inside the anchor point to the right;
    • CENTER_HORI: in the middle of the anchor level;
    • TO_RIGHT: outside the anchor point to the right;
    • TO_LEFT: outside the anchor point to the left.
  2. Vertical direction:
    • ALIGN_ABOVE: Above the inside of the anchor;
    • ALIGN_BOTTOM: below the inside of the anchor point;
    • CENTER_VERT: perpendicular to the middle of the anchor point;
    • TO_BOTTOM: below the outside of the anchor point;
    • TO_ABOVE: Above the outside of the anchor point.

Here’s a picture:

ShowAsDropDown specifies the effects of showAsDropDown

The desired effect is under a control and also has an offset Angle, so the offset Angle is roughly how much to debug. So the main method falls under showAsDropDown. It is not impossible to write generic, don’t think so much, do it first, achieve the current effect again.

View contentView= Layoutinflater.from (context).inflate(layoutRes, null, false);

The output of the view, so that it can be isolated, in a separate page and XML processing, background and Angle, as well as click events in the view as a whole, and not so verbose, look at the simple code, we use build design pattern, highlights the advantages of this pattern. Keep adding Settings.

Build Design mode

I’ve written about design patterns before.

The first thing to look at is when you create a view or output a view for display purposes

Public PopTop(Builder Builder) {// Window layout super(builder.context); this.builder = builder; Create(); Public void Create() {// Window layout setContentView(mainView = LayoutInflater. From (builder.context).inflate(r.layout.pop_top,  null)); // Set the width setWidth(dip2px(builder.context, 100)); / / set the height setHeight (LinearLayout. LayoutParams. WRAP_CONTENT); setTouchable(true); setFocusable(true); // setAnimationStyle(r.style.animtools); // setBackgroundDrawable(new ColorDrawable()); /* / Click on the window displayed a * / cancel getContentView () setOnFocusChangeListener (new View. OnFocusChangeListener () {@ Override public void onFocusChange(View v, boolean hasFocus) { if (! hasFocus) { dismiss(); }}}); // Initialize the control click event handler initView(mainView); }Copy the code

Now look at what build does

public static class Builder { protected final Context context; protected View view; PopTopOnClick popTopOnClick; public Builder setPopTopOnClick(PopTopOnClick popTopOnClick) { this.popTopOnClick = popTopOnClick; return this; } public Builder setView(View view) { this.view = view; return this; } public Builder(@NonNull Context context) { this.context = context; } @UiThread public PopupWindow build() { return new PopTop(this); } @UiThread public PopupWindow show() { PopupWindow popTop = build(); int windowPos[] = calculatePopWindowPos(view); windowPos[0] -= 15; WindowPos [1] -= 10; . / / y offset up 10 pixels popTop showAtLocation (view, Gravity. TOP | Gravity. START, windowPos [0], windowPos [1]). return popTop; }}Copy the code

Mainly in show

The handling of offsets, and the handling in place, is described in the basics above.

/** * The calculated position of the anchorView is aligned above and below the y direction and aligned to the right of the screen. * If the anchorView position changes, * * @param anchorView calls window view * @return Window displays the xOff in the upper left corner. YOff coordinates */ public static int[] calculatePopWindowPos(final View anchorView) {final int windowPos[] = new int[2]; final int anchorLoc[] = new int[2]; / / get the anchor point of View on the screen in the upper left corner coordinates anchorView. GetLocationOnScreen (anchorLoc); final int anchorHeight = anchorView.getHeight(); Final int screenHeight = getScreenHeight(anchorView.getContext()); final int screenWidth = getScreenWidth(anchorView.getContext()); mainView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); / / calculate the height to width contentView final int windowHeight = mainView. GetMeasuredHeight (); final int windowWidth = mainView.getMeasuredWidth(); Final Boolean isNeedShowUp = (screenHeight - anchorLoc[1] - anchorHeight < windowHeight); if (isNeedShowUp) { windowPos[0] = screenWidth - windowWidth; windowPos[1] = anchorLoc[1] - windowHeight; } else { windowPos[0] = screenWidth - windowWidth; windowPos[1] = anchorLoc[1] + anchorHeight; } return windowPos; }Copy the code

So that’s the general flow, the click event, the event listening, is also passed from the pop generated.

All of the code

import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;

 

public class PopTop extends PopupWindow implements View.OnClickListener {

    public static View mainView;
    protected final Builder builder;
    protected TextView popTvCustomerEdit;
    protected TextView popTvCustomerDel;
    protected LinearLayout popLlEdit;
    protected TextView popTvCustomerSys;
    protected TextView popTvCustomerCreate;
    protected LinearLayout popLlCustomer;

    public PopTop(Builder builder) {
        //窗口布局
        super(builder.context);
        this.builder = builder;
        Create();
    }

    public void Create() {
        //窗口布局
        setContentView(mainView = LayoutInflater.from(builder.context).inflate(R.layout.pop_top, null));
        //设置宽度
        setWidth(dip2px(builder.context, 100));
        //设置高度
        setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
        setTouchable(true);
        setFocusable(true);
        //设置显示隐藏动画
//        setAnimationStyle(R.style.AnimTools);
        //设置背景透明
        setBackgroundDrawable(new ColorDrawable());
        /*          //监听窗口的焦点事件,点击窗口外面则取消显示*/
        getContentView().setOnFocusChangeListener(new View.OnFocusChangeListener() {

            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (!hasFocus) {
                    dismiss();
                }
            }
        });
        initView(mainView);
    }

    @Override
    public void onClick(View view) {
        dismiss();
        if (view.getId() == R.id.pop_tv_customer_edit) {
            if(builder.popTopOnClick != null){
                builder.popTopOnClick.EditOnclick();
            }
        } else if (view.getId() == R.id.pop_tv_customer_del) {
            if(builder.popTopOnClick != null){
                builder.popTopOnClick.hashCode();
            }
        } else if (view.getId() == R.id.pop_tv_customer_sys) {
            if(builder.popTopOnClick != null){
                builder.popTopOnClick.SysOnclick();
            }
        } else if (view.getId() == R.id.pop_tv_customer_create) {
            if(builder.popTopOnClick != null){
                builder.popTopOnClick.CreateOnclick();
            }
        }
    }

    private void initView(View rootView) {
        popTvCustomerEdit = (TextView) rootView.findViewById(R.id.pop_tv_customer_edit);
        popTvCustomerEdit.setOnClickListener(PopTop.this);
        popTvCustomerDel = (TextView) rootView.findViewById(R.id.pop_tv_customer_del);
        popTvCustomerDel.setOnClickListener(PopTop.this);
        popLlEdit = (LinearLayout) rootView.findViewById(R.id.pop_ll_edit);
        popTvCustomerSys = (TextView) rootView.findViewById(R.id.pop_tv_customer_sys);
        popTvCustomerSys.setOnClickListener(PopTop.this);
        popTvCustomerCreate = (TextView) rootView.findViewById(R.id.pop_tv_customer_create);
        popTvCustomerCreate.setOnClickListener(PopTop.this);
        popLlCustomer = (LinearLayout) rootView.findViewById(R.id.pop_ll_customer);

        popLlEdit.setVisibility(View.GONE);
        popLlCustomer.setVisibility(View.GONE);

        

    }

    public static class Builder {
        protected final Context context;
        protected View view; 
        PopTopOnClick popTopOnClick;

        public Builder setPopTopOnClick(PopTopOnClick popTopOnClick) {
            this.popTopOnClick = popTopOnClick;
            return this;
        }

        
        public Builder setView(View view) {
            this.view = view;
            return this;
        }

        public Builder(@NonNull Context context) {
            this.context = context;
        }

        @UiThread
        public PopupWindow build() {
            return new PopTop(this);
        }

        @UiThread
        public PopupWindow show() {
            PopupWindow popTop = build();
            int windowPos[] = calculatePopWindowPos(view);
            windowPos[0] -= 15; //x 轴向左偏移15像素
            windowPos[1] -= 10; //y 轴向上偏移10像素
            popTop.showAtLocation(view, Gravity.TOP | Gravity.START, windowPos[0], windowPos[1]);
            return popTop;
        }
    }

    public int dip2px(Context context, float dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

    /**
     * 计算出来的位置,y方向就在anchorView的上面和下面对齐显示,x方向就是与屏幕右边对齐显示
     * 如果anchorView的位置有变化,就可以适当自己额外加入偏移来修正
     *
     * @param anchorView 呼出window的view
     * @return window显示的左上角的xOff, yOff坐标
     */
    public static int[] calculatePopWindowPos(final View anchorView) {

        final int windowPos[] = new int[2];
        final int anchorLoc[] = new int[2];
        // 获取锚点View在屏幕上的左上角坐标位置
        anchorView.getLocationOnScreen(anchorLoc);
        final int anchorHeight = anchorView.getHeight();
        // 获取屏幕的高宽
        final int screenHeight = getScreenHeight(anchorView.getContext());
        final int screenWidth = getScreenWidth(anchorView.getContext());
        mainView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
        // 计算contentView的高宽
        final int windowHeight = mainView.getMeasuredHeight();
        final int windowWidth = mainView.getMeasuredWidth();
        // 判断需要向上弹出还是向下弹出显示
        final boolean isNeedShowUp = (screenHeight - anchorLoc[1] - anchorHeight < windowHeight);
        if (isNeedShowUp) {
            windowPos[0] = screenWidth - windowWidth;
            windowPos[1] = anchorLoc[1] - windowHeight;
        } else {
            windowPos[0] = screenWidth - windowWidth;
            windowPos[1] = anchorLoc[1] + anchorHeight;
        }
        return windowPos;
    }

    /**
     * 获取屏幕高度(px)
     */
    public static int getScreenHeight(Context context) {
        return context.getResources().getDisplayMetrics().heightPixels;
    }

    /**
     * 获取屏幕宽度(px)
     */
    public static int getScreenWidth(Context context) {
        return context.getResources().getDisplayMetrics().widthPixels;
    }

    public interface PopTopOnClick{
        void EditOnclick();
        void DelOnclick();
        void SysOnclick();
        void CreateOnclick();
    }

}
Copy the code

Eventually you can

if (view.getId() == R.id.common_tv_right_more) { new PopTop.Builder(this) .setView(findViewById(r.id.mon_tv_right_more)) // Below some space.setPopToponclick (new poptop.poptoponclick () {@override Public void DelOnclick() {public void DelOnclick() {public void DelOnclick() {public void DelOnclick() {public void DelOnclick() {public void DelOnclick() { }Copy the code

Last kind of thought

You can write a comment on pop for example

Click the pop-up keyboard pop display processing, keyboard disappear pop disappear. There was also a project about this before, but it was not written in this way. It was just piled together and there was no reflection. At that time, there was no blog.