popupwindow的源码分析

闲来无事把popupwindow的源码看了一遍,能力有限只看懂了一部分。下面我们来看看源码:

<span style="font-size:14px;">private int mWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;</span>
分析:从这里可以看出来PopupWindow(弹出窗口)实际上是一个子窗口,它是一个独立的类(并不继承于Window)。
<span style="font-size:14px;">public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        mContext = context;
        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);

        final TypedArray a = context.obtainStyledAttributes(
                attrs, R.styleable.PopupWindow, defStyleAttr, defStyleRes);
        final Drawable bg = a.getDrawable(R.styleable.PopupWindow_popupBackground);
        mElevation = a.getDimension(R.styleable.PopupWindow_popupElevation, 0);
        mOverlapAnchor = a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false);

        final int animStyle = a.getResourceId(R.styleable.PopupWindow_popupAnimationStyle, -1);
        mAnimationStyle = animStyle == R.style.Animation_PopupWindow ? -1 : animStyle;

        a.recycle();

        setBackgroundDrawable(bg);
    }
</span>

分析:这个一看就很清楚,这是它的构造函数,里面通过context对象获取了windowManager对象和属性typedArray和一些动画style,a.recycle是释放
typedArray。里面还有很多构造函数,主要是对它进行一些参数的初始化,比如设置contentView、宽、高、焦点等。详细请看源码。
接下来主要介绍的是我们经常要用到的显示popupwindow位置的几个方法。因为严格来说这个PopuWindow就是用来在指定位置显示一个View的。主要方法有下面:
 public void showAsDropDown(View anchor) 
      showAsDropDown(View anchor, int xoff, int yoff)
    showAtLocation(View parent, int gravity, int x, int y) 
下面来看看他们的源码:
public void showAsDropDown(View anchor) {
        showAsDropDown(anchor, 0, 0);
    }
 public void showAsDropDown(View anchor, int xoff, int yoff) {
        showAsDropDown(anchor, xoff, yoff, DEFAULT_ANCHORED_GRAVITY);
    }<pre name="code" class="java">public void showAtLocation(View parent, int gravity, int x, int y) {
        showAtLocation(parent.getWindowToken(), gravity, x, y);
    }


第一个调用的是第二个方法,所以我们直接分析第二个方法:
public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
        if (isShowing() || mContentView == null) {
            return;
        }

        registerForScrollChanged(anchor, xoff, yoff, gravity);

        mIsShowing = true;
        mIsDropdown = true;

        WindowManager.LayoutParams p = createPopupLayout(anchor.getWindowToken());
        preparePopup(p);

        updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, gravity));

        if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;
        if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;

        p.windowAnimations = computeAnimationResource();

        invokePopup(p);
    }
<pre name="code" class="java">public void showAtLocation(IBinder token, int gravity, int x, int y) {
        if (isShowing() || mContentView == null) {
            return;
        }

        unregisterForScrollChanged();

        mIsShowing = true;
        mIsDropdown = false;

        WindowManager.LayoutParams p = createPopupLayout(token);
        p.windowAnimations = computeAnimationResource();
       
        preparePopup(p);
        if (gravity == Gravity.NO_GRAVITY) {
            gravity = Gravity.TOP | Gravity.START;
        }
        p.gravity = gravity;
        p.x = x;
        p.y = y;
        if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;
        if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;
        invokePopup(p);
    }

分析:
 
先解释下参数:
anchor:就是PopupWindow要显示位置的参照物
xoff: PopupWindow相对于anchor的左下角x轴方向的偏移大小
yoff: PopupWindow相对于anchor的左下角y轴方向的偏移大小
我觉得这两个方法的区别就是showAtLocation能够设置popupwindow显示在参照物view的哪个方位然后设置偏移值,而showAsDropDown则是默认弹出窗显示在参照物view的左下角,然后设置偏移值。代码具体分析:
刚开始isShowing()判断当前PopupWindow是否显示,或者mContentView是否为空,是的话就不用去继续执行下面的代码了。然后unregisterForScrollChanged(),为了滑动改变注册,就是有可能anchor有滑动,或者ContentView过大,有的地方放不开。
private void unregisterForScrollChanged() {
        WeakReference<View> anchorRef = mAnchor;
        View anchor = null;
        if (anchorRef != null) {
            anchor = anchorRef.get();
        }
        if (anchor != null) {
            ViewTreeObserver vto = anchor.getViewTreeObserver();
            vto.removeOnScrollChangedListener(mOnScrollChangedListener);
        }
        mAnchor = null;
    }
就是注册一下滑动的全局的监听,注册之前先注销一下之前的注册,防止ViewTreeObserver失效。在这里使用了一个弱引用对anchor,防止anchor这个类已经无用了,anchor仍然无法回收内存。接下来为PopupWindow设置显示参数,调用了createPopupLayout(anchor.getWindowToken())
看下这个方法:
private WindowManager.LayoutParams createPopupLayout(IBinder token) {
        // generates the layout parameters for the drop down
        // we want a fixed size view located at the bottom left of the anchor
        WindowManager.LayoutParams p = new WindowManager.LayoutParams();<span style="color:#ff0000;">//<span style="font-family: Simsun; line-height: 24px;">创建一个WindowManager.LayoutParams的实例</span></span>
        // these gravity settings put the view at the top left corner of the
        // screen. The view is then positioned to the appropriate location
        // by setting the x and y offsets to match the anchor's bottom
        // left corner
        p.gravity = Gravity.START | Gravity.TOP;<span style="color:#ff0000;">//接下来为实例p设置了一系列的参数</span>
        p.width = mLastWidth = mWidth;
        p.height = mLastHeight = mHeight;
        if (mBackground != null) {
            p.format = mBackground.getOpacity();
        } else {
            p.format = PixelFormat.TRANSLUCENT;
        }
        p.flags = computeFlags(p.flags);
        p.type = mWindowLayoutType;
        p.token = token;
        p.softInputMode = mSoftInputMode;
        p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));

        return p;
    }

 
接下来分析方法:invokePopup(p),它才是真正的把PopupWindow显示在特定的位置上。其实就使用Activity中的WindowManager对象对mPopupView进行了添加显示。
<span style="font-size:14px;">private void invokePopup(WindowManager.LayoutParams p) {
        if (mContext != null) {
            p.packageName = mContext.getPackageName();
        }
        mPopupView.setFitsSystemWindows(mLayoutInsetDecor);
        setLayoutDirectionFromAnchor();
        mWindowManager.addView(mPopupView, p);//<span style="color: rgb(255, 0, 0); font-family: Arial; line-height: 26px;">调用addView完成添加</span>
    }</span>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
嗨!对于你关于 Android PopupWindow 的问题,我可以给你一些基本的信息。PopupWindow 是 Android 中的一个弹出式窗口,它可以覆盖在其他视图之上,提供一种临时性的用户界面。你可以使用 PopupWindow 来显示额外的内容、菜单或者交互提示。 要创建一个 PopupWindow,首先你需要实例化一个 PopupWindow 对象,并为其设置一些基本属性,例如宽度、高度、背景等。然后,你可以将任何视图或布局添加到 PopupWindow 中,并通过设置位置参数来控制它的显示位置。 下面是一个简单的示例代码,展示如何创建和显示一个 PopupWindow: ```java // 创建一个 PopupWindow 对象 PopupWindow popupWindow = new PopupWindow(context); // 设置 PopupWindow 的宽度和高度 popupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); // 设置 PopupWindow 的内容视图 View contentView = LayoutInflater.from(context).inflate(R.layout.popup_layout, null); popupWindow.setContentView(contentView); // 设置 PopupWindow 的背景 popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); // 显示 PopupWindow popupWindow.showAtLocation(anchorView, Gravity.CENTER, 0, 0); ``` 在上面的示例中,我们创建了一个 PopupWindow 对象,并设置了宽度和高度为包裹内容。然后,我们通过调用 `setContentView` 方法将一个自定义的布局文件 `R.layout.popup_layout` 添加到 PopupWindow 中。最后,我们使用 `showAtLocation` 方法将 PopupWindow 显示在屏幕中央。 希望这些信息对你有帮助!如果你对 PopupWindow 有更多的问题,或者需要更详细的示例代码,请随时告诉我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值