1. 程式人生 > >關於PopupWindow的showAsDropDown()和showAtLocation()使用方式,popupWindow的各種彈出

關於PopupWindow的showAsDropDown()和showAtLocation()使用方式,popupWindow的各種彈出

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.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>
轉載至:http://www.bozhiyue.com/anroid/boke/2016/0421/32970.html
原始碼下載地址 http://download.csdn.net/detail/lnn368/9495250