(原创)关于PopupWindow的showAsDropDown()跟showAtLocation()使用方式及其区别

(原创)关于PopupWindow的showAsDropDown()和showAtLocation()使用方式及其区别

(原创)关于PopupWindow的showAsDropDown()和showAtLocation()使用方式及其区别

先看下demo的效果图,说明都在代码里面注释。

(原创)关于PopupWindow的showAsDropDown()跟showAtLocation()使用方式及其区别

以下是个人编写代码:

1.MainActivity部分

package com.example.lainanzhou.popupwindoewlocation;

import android.app.Activity;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.Interpolator;
import android.view.animation.ScaleAnimation;
import android.widget.Button;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;

/**
 * Android的对话框有两种:PopupWindow和AlertDialog。它们的不同点在于:
 * •AlertDialog的位置固定,而PopupWindow的位置可以随意
 * •AlertDialog是非阻塞线程的,而PopupWindow是阻塞线程的
 * •PopupWindow的位置按照有无偏移分,可以分为偏移和无偏移两种;按照参照物的不同,
 * 可以分为相对于某个控件(Anchor锚)和相对于父控件。具体如下
 * •showAsDropDown(View anchor):相对某个控件的位置(正左下方),无偏移
 * •showAsDropDown(View anchor,int xoff,int yoff):相对某个控件的位置,有偏移
 * •showAtLocation(View parent,int gravity,int x,int y):相对于父控件的位置
 * (例如正*Gravity.CENTER,下方Gravity.BOTTOM等),可以设置偏移或无偏移
 */


public class MainActivity extends Activity implements View.OnClickListener {

    private TextView mTv;
    private TextView mMainView;
    private RelativeLayout mRl_parent;
    private PopupWindow mPopupWindow;
    private int mWidth;
    private boolean mIsClick5;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTv = (TextView) findViewById(R.id.tv);
        mMainView = (TextView) findViewById(R.id.tv_mainView);
        mRl_parent = (RelativeLayout) findViewById(R.id.rl_parent);
        Button mButton01 = (Button) findViewById(R.id.button01);
        Button mButton02 = (Button) findViewById(R.id.button02);
        Button mButton03 = (Button) findViewById(R.id.button03);
        Button mButton04 = (Button) findViewById(R.id.button04);
        Button mButton05 = (Button) findViewById(R.id.button05);
        mButton01.setOnClickListener(this);
        mButton02.setOnClickListener(this);
        mButton03.setOnClickListener(this);
        mButton04.setOnClickListener(this);
        mButton05.setOnClickListener(this);
    }

    /**
     * 根据类型设置显示的popupWindow方式
     *
     * @param type 1.为直接显示在某控件下方+点击外部不可关闭
     *             2.显示在某控件下方+点击外部可关闭
     *             3.相对父容器中心显示位置+点击外部可关闭
     *             4.相对父容器脚部显示位置+点击外部可关闭
     *             5.默认点击外部可关闭
     */
    private void initPopupWindow(int type) {
        LayoutInflater layoutInflater = LayoutInflater.from(this);
        View popupWindow = layoutInflater.inflate(R.layout.popup_window, null);
        //mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。
        // MeasureSpec.EXACTLY是(完全)精确尺寸,父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小;
        //      当我们将控件的layout_width或layout_height指定为具体数值时
        //      如andorid:layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。
        // MeasureSpec.AT_MOST是(至多)最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,
        //      控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。
        //      因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
        // MeasureSpec.UNSPECIFIED是未指定尺寸,父元素不对子元素施加任何束缚,子元素可以得到任意想要的大小;
        //      这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。
        //以下方式是为了在popupWindow还没有弹出显示之前就测量获取其宽高(单位是px相熟)~只能UNSPECIFIED模式下测量
        int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        TextView mTextView = (TextView) popupWindow.findViewById(R.id.tv_popupTv);
        mTextView.measure(w, h);
        mWidth = mTextView.getMeasuredWidth();//获取测量宽度px
        int mHeight = mTextView.getMeasuredHeight();//获取测量高度px

        //设置点击popupWindow里面文本可以dismiss该popupWindow
        popupWindow.findViewById(R.id.tv_popupTv).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mPopupWindow != null && mPopupWindow.isShowing()) {
                    mPopupWindow.dismiss();
                }
            }
        });
        // 创建一个PopupWindow
        // 参数1:contentView 指定PopupWindow的显示View
        // 参数2:width 指定PopupWindow的width可以固定死某些数值:
        //       如果不想固定死可以设置为ViewGroup.LayoutParams.WRAP_CONTENT/MATCH_CONTENT
        // 参数3:height 指定PopupWindow的height
        mPopupWindow = new PopupWindow(popupWindow, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

        //设置动画两种方式:动画效果可以参考该网址 http://blog.****.net/xiaanming/article/details/8997260
        //方式1:xml配置文件
        //        mPopupWindow.setAnimationStyle(R.anim.popupwindow_enter);
        //方式2:直接设置该popupWindow中的View的动画
        //        setPopupAnimation(popupWindow);

        mPopupWindow.setFocusable(true); //这里很重要,设置该popupWindow可以获取焦点,不然无法响应点击事件

        switch (type) {
            case 1:
                //方式2:直接设置该popupWindow中的View的动画
                setPopupAnimation(popupWindow);
                //6.0无效
                mPopupWindow.setOutsideTouchable(false);//设置点击外面不可以消失~注意该效果在设置背景的情况下是无效的
                break;
            case 2:
                //方式1:xml配置文件
                mPopupWindow.setAnimationStyle(R.anim.popupwindow_enter);
                mPopupWindow.setBackgroundDrawable(new BitmapDrawable());
                mPopupWindow.setOutsideTouchable(true);//设置点击外面可以消失~注意则必须要设置该popupWindow背景才有效
                break;
            case 3:
                //方式2:直接设置该popupWindow中的View的动画
                setPopupAnimation(popupWindow);
                //6.0无效
                mPopupWindow.setOutsideTouchable(false);//设置点击外面不可以消失~注意该效果在设置背景的情况下是无效的
                break;
            case 4:
                //方式1:xml配置文件
                mPopupWindow.setAnimationStyle(R.anim.popupwindow_enter);
                mPopupWindow.setBackgroundDrawable(new BitmapDrawable());
                mPopupWindow.setOutsideTouchable(true);//设置点击外面可以消失~注意则必须要设置该popupWindow背景才有效
                break;
            case 5:
                mMainView.setVisibility(mIsClick5 ? View.VISIBLE : View.GONE);
                RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, dip2px(48));
                mMainView.measure(w, h);
                int mMainViewWidth = mMainView.getMeasuredWidth();//获取测量宽度px
                int width = (mTv.getWidth() - mMainViewWidth) / 2;//获取x轴偏移量px
                params.setMargins(mTv.getLeft() + width, mTv.getHeight(), 0, 0);
                mMainView.setLayoutParams(params);//设置位置
                if (mIsClick5)
                    mMainView.setAnimation(getAnimation());//设置动画
                break;
            default:
                //方式1:xml配置文件
                mPopupWindow.setAnimationStyle(R.anim.popupwindow_enter);
                mPopupWindow.setBackgroundDrawable(new BitmapDrawable());
                mPopupWindow.setOutsideTouchable(true);//设置点击外面可以消失~注意则必须要设置该popupWindow背景才有效
                break;

        }
    }

    /**
     * 动画效果
     *
     * @return
     */
    public Animation getAnimation() {
        AlphaAnimation localAlphaAnimation = new AlphaAnimation(0.0F, 1.0F);
        localAlphaAnimation.setInterpolator(new Interpolator() {
            public float getInterpolation(float paramFloat) {
                return 10.0F * paramFloat;
            }
        });
        localAlphaAnimation.setDuration(500L);
        ScaleAnimation localScaleAnimation = new ScaleAnimation(0.0F, 1.0F, 0.0F, 1.0F, 1, 0.5F, -1, 0.0F);
        localScaleAnimation.setDuration(500L);
        AnimationSet localAnimationSet = new AnimationSet(true);
        localAnimationSet.addAnimation(localScaleAnimation);
        localAnimationSet.addAnimation(localAlphaAnimation);
        return localAnimationSet;
    }

    /**
     * 设置组合动画
     *
     * @param paramView
     */
    private void setPopupAnimation(View paramView) {
        //透明度动画
        AlphaAnimation localAlphaAnimation = new AlphaAnimation(0.0F, 1.0F);
        localAlphaAnimation.setInterpolator(new Interpolator() {
            public float getInterpolation(float paramFloat) {
                return 10.0F * paramFloat;
            }
        });
        localAlphaAnimation.setDuration(800L);//动画持续时长
        //缩放动画:
        // 参数:
        // 1.为x轴起始缩放度 2.为x结束缩放度
        // 3.为y起始缩放度 4.为y结束缩放度
        // 5.为相对x轴类型为顶部 6.为该类型上起始度(0.5f为中间位置)
        // 7.为相对y轴类型 8.为该类型起始位置(0F为原位置)
        ScaleAnimation localScaleAnimation = new ScaleAnimation(0F, 1.0F, 0F, 1.0F, Animation.ZORDER_TOP, 0.5F, Animation.ZORDER_TOP, 0F);
        localScaleAnimation.setDuration(500L);//动画持续时长
        AnimationSet localAnimationSet = new AnimationSet(true);
        localAnimationSet.addAnimation(localScaleAnimation);
        localAnimationSet.addAnimation(localAlphaAnimation);
        paramView.startAnimation(localAnimationSet);
    }

    /**
     * dip与px之间转换
     *
     * @param dipValue
     * @return
     */

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

    private int px2dip(float pxValue) {
        final float scale = getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            // 相对某个控件的位置(正左下方),无偏移
            case R.id.button01:
                initPopupWindow(1);
                mPopupWindow.showAsDropDown(mTv);
                break;

            // 相对某个控件的位置(正左下方),有偏移
            case R.id.button02:
                initPopupWindow(2);
                //以下为分步介绍控件获取中间位置偏移量方式:(对应控件宽度-popup宽度)/2
                int tv_width = mTv.getWidth();//获取对应的控件view宽度px值
                int popup_width = dip2px(120);//将popupWindow宽度转为px值(这里的popup宽度是写死了的)
                int width = (tv_width - mWidth) / 2;//获取x轴偏移量px
                mPopupWindow.showAsDropDown(mTv, width, 0);//设置x轴偏移量:注意单位为px
                break;

            // 相对于父控件的位置,无偏移~参数1为父容器~参数2为相对父容器相对类型~参数34为偏移量
            case R.id.button03:
                initPopupWindow(3);
                //int[] locaitons = new int[2];//存放相应控件在屏幕的xy轴坐标点;单位px
                //mTv.getLocationOnScreen(locaitons);//locaitons[0]为x轴 locaitons[1]为y轴
                // X、Y方向偏移量:设置x轴偏移量为相应控件中心;y轴无偏移
                mPopupWindow.showAtLocation(mRl_parent, Gravity.CENTER, 0, 0);
                break;

            // 相对于父控件的位置,有偏移~参数1为父容器~参数2为相对父容器相对类型~参数34为偏移量
            case R.id.button04:
                initPopupWindow(4);
                mPopupWindow.showAtLocation(mRl_parent, Gravity.BOTTOM, 0, 0);
                break;
            case R.id.button05:
                mIsClick5 = !mIsClick5;
                initPopupWindow(5);
                break;
            default:
                break;

        }
    }
}

2.activity_main.xml部分

<RelativeLayout android:id="@+id/rl_parent"
                xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent">

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:gravity="center"
        android:text="popupwindow相对该view显示位置"/>

    <TextView
        android:id="@+id/tv_mainView"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:gravity="center"
        android:text="我是MainView"
        android:textColor="#333333"
        android:background="#dddddd"
        android:visibility="gone"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="18dp"
        android:orientation="vertical">

        <Button
            android:id="@+id/button01"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="直接显示在某控件下方,不偏移且点击外面不可关闭"/>

        <Button
            android:id="@+id/button02"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="显示在某控件下方,有偏移且点击外面可关闭"/>

        <Button
            android:id="@+id/button03"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="相对父容器中心显示位置,不偏移且点击外面不可关闭"/>

        <Button
            android:id="@+id/button04"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="相对父容器脚部显示位置,下方中间且点击外面可关闭"/>

        <Button
            android:id="@+id/button05"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="直接使用view显示,随便设置弹出位置"/>

    </LinearLayout>
</RelativeLayout>

3.popup_window.xml部分

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#dddddd"
                android:orientation="vertical">

    <TextView
        android:id="@+id/tv_popupTv"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:text="我是PopupWindow"
        android:textColor="#333333"/>


</RelativeLayout>

4.popupwindow_enter.xml动画xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!--位移动画:1为持续时长;2为X轴起始位置;3为X轴到达位置 ~看需求还可以添加设置Y轴位置-->
    <!--X轴相对左右方向,Y轴相对上下方向-->
    <translate
        android:duration="500"
        android:fromYDelta="-100"
        android:toYDelta="0"/>
</set>

以上为相关代码。

源码下载链接:源码下载




1楼lnn368前天 09:28
源码下载地址:http://download.****.net/detail/lnn368/9495250