关于PopupWindow的showAsDropDown()和showAtLocation()使用方式及其区别
先看下demo的效果图,说明都在代码里面注释。
以下是个人编写代码:
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相熟)
- 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.csdn.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>