Android PopupWindow的使用

下面是一個彈出帶ListView和TextView的PopupWindow實例:android

import android.app.Activity;
import android.content.Context;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * Created by SRain on 2015/10/15.
 * <p/>
 * 彈出框
 */
public class PopupWindowUtils implements View.OnClickListener {

    private PopupWindow popupWindow;
    private Context context;
    private View view;
    private TextView tvClose;
    private JSONArray jsonArray;
    private BasicPopuListAdapter adapter; //ListView的適配器

    public PopuWindowUtils(Context context, View view, JSONArray jsonArray, int index) {
        this.context = context;
        this.view = view;
        this.jsonArray = jsonArray;
        initPopuWindow(index);
    }

    /**
     * 彈出popupwindow
     *
     * @param index 彈出框樣式標識
     */
    private void initPopuWindow(final int index) {
        View contentView = LayoutInflater.from(context).inflate(R.layout.layout_popupwindow, null);
        ListView listView = (ListView) contentView.findViewById(R.id.lv_files);
        tvClose = (TextView) contentView.findViewById(R.id.tvClose);
        tvClose.setVisibility(View.VISIBLE);
        tvClose.setOnClickListener(this);

        /*
         * 建立PopupWindow實例
         * getScreenWidth(), (int) (getScreenWidth() * 0.6))分別是寬度和高度
         */
        if (popupWindow == null) {
            popupWindow = new PopupWindow(contentView, getScreenWidth(), (int) (getScreenWidth() * 0.6));
        }

        // 自定義view添加觸摸事件
        contentView.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (popupWindow != null && popupWindow.isShowing()) {             
                    popupWindow.dismiss();
                    return true;
                }

                // 這裏若是返回true的話,touch事件將被攔截
                // 攔截後 PopupWindow的onTouchEvent不被調用,這樣點擊外部區域沒法dismiss
                return false;
            }
        });

        switch (index) {
            case 1:
                adapter = new RoutePupuAdapter(context, jsonArray);
                break;
        }

        listView.setAdapter(adapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                try {
                    adapter.setSelectedPosition(position);
                    // 更新列表框
                    adapter.notifyDataSetInvalidated();
                    JSONObject object = jsonArray.getJSONObject(position);
                    clickFunction(index, object);
                } catch (JSONException e) {
                    Log.e("onItemClick", e.toString());
                }
            }
        });

        popupWindow.setAnimationStyle(R.style.PopupAnimation);
        popupWindow.setFocusable(true);
        /*
         * 彈出框位置
         */
        popupWindow.showAsDropDown(view, 0, -110);
        //popupWindow.showAtLocation(MainActivity.this.findViewById(R.id.main), Gravity.BOTTOM|Gravi        //ty.CENTER_HORIZONTAL, 0, 0); //設置layout在PopupWindow中顯示的位置,從底部彈出
    }

    /**
     * 根據屏幕寬度設置高度值
     */
    private int getScreenWidth() {
        //獲取屏幕寬度
        DisplayMetrics dm = new DisplayMetrics();
        double densityDpi = dm.density;
        //獲取屏幕信息
        ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
        int screenWidth = dm.widthPixels;
        return screenWidth;
    }


    public void clickFunction(int index, JSONObject json) {
        switch (index) {
            case 1:
                ((LocationMapActivity) context).initRoadLines(json);
                break;
        }
    }

    /**
     * 銷燬PopupWindow
     */
    public boolean dismissPopu() {
        if (popupWindow != null && popupWindow.isShowing()) {
            popupWindow.dismiss();
            return true;
        }
        return false;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.tvClose:
                dismissPopu();
                break;
        }
    }
}

 

//這是BasicPopuListAdapter代碼,本身的listview中adapter繼承它就能夠了:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import org.json.JSONArray;
import org.json.JSONObject;

/**
 * Created by SRain on 2015/10/20.
 * <p/>
 * 普通listview適配器
 */
public abstract class BasicPopuListAdapter extends BaseAdapter {

    protected Context context;
    protected JSONArray array;
    protected LayoutInflater mInflater;

    private int selectedPosition = -1;

    public BasicPopuListAdapter(Context context, JSONArray array) {
        this.context = context;
        this.array = array;
        mInflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return array.length();
    }

    @Override
    public Object getItem(int position) {
        JSONObject object = null;
        try {
            object = array.getJSONObject(position);
        } catch (Exception e) {

        }
        return object;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public abstract View getView(int position, View convertView, ViewGroup parent);

    public abstract void setSelectedPosition(int position);

    public JSONArray getData(){
        return this.array;
    }
}

這是彈出框的佈局文件:json

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

    <ListView
        android:id="@+id/lv_files"
        android:layout_weight="1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <TextView
        android:id="@+id/tvClose"
        android:layout_marginTop="2dp"
        android:visibility="gone"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:background="@color/green"
        android:gravity="center"
        android:text="關閉"
        android:textColor="@color/white" />
</LinearLayout>

style中添加:app

<style name="PopupAnimation" mce_bogus="1" parent="android:Animation">
    <item name="android:windowEnterAnimation">@anim/dialog_enter</item>
    <item name="android:windowExitAnimation">@anim/dialog_exit</item>
</style>

drawable中添加dialog_enter.xml和dialog_exit.xml:ide

<!--dialog_enter-->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="500"
        android:fromYDelta="500"
        android:toYDelta="0" />
</set>
<!--dialog_exit-->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="500"
        android:fromYDelta="0"
        android:toYDelta="500" />
</set>

補充:
在用PopupWindow實現底部彈出菜單的時候要注意幾個問題:
  1)若是彈出菜單中有EditText這種輸入控件,若是不給PopupWindow設置可獲取焦點的話,EditText是沒法獲取輸入的。
  2)必定要設置 虛擬軟鍵盤隨須要更改屏幕顯示內容的大小,不然虛擬軟鍵盤會被底部彈出菜單遮擋。
  3)若是設置了PopupWindow可獲取焦點的話,此時會遇到一個問題就是當PopupWindow中的控件好比EditText獲取焦點以後,點擊PopupWindow以外的控件是不會有響應的,若是用setBackgroundDrawable(new BitmapDrawable())進行設置的話,則不會出現這種狀況。
//設置能夠獲取焦點,不然彈出菜單中的EditText是沒法獲取輸入的
popWindow.setFocusable(true);
//這句是爲了防止彈出菜單獲取焦點以後,點擊activity的其餘組件沒有響應
popWindow.setBackgroundDrawable(new BitmapDrawable()); 
//防止虛擬軟鍵盤被彈出菜單遮住
popWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
//在底部顯示
popWindow.showAtLocation(this,Gravity.BOTTOM, 0, 0);佈局

    4)popupWindow.setBackgroundDrawable(new BitmapDrawable());  // 須要設置一下此參數,點擊外邊可消失, 若是不設置PopupWindow的背景,不管是點擊外部區域仍是Back鍵都沒法dismiss彈框this

            popupWindow.setOutsideTouchable(true);  // 設置popwindow若是點擊外面區域,便關閉。
            popupWindow.setFocusable(true);  // 設置此參數得到焦點,不然沒法點擊  
            popupWindow.update();spa

5)PopupWindow和AlertDialog的區別線程

Android的對話框有兩種:PopupWindow和AlertDialog。它們的不一樣點在於:code

  • AlertDialog的位置固定,而PopupWindow的位置能夠隨意
  • AlertDialog是非阻塞線程的,而PopupWindow是阻塞線程的

PopupWindow的位置按照有無偏移分,能夠分爲偏移和無偏移兩種;按照參照物的不一樣,能夠分爲相對於某個控件(Anchor錨)和相對於父控件。具體以下xml

  • showAsDropDown(View anchor):相對某個控件的位置(正左下方),無偏移
  • showAsDropDown(View anchor, int xoff, int yoff):相對某個控件的位置,有偏移
  • showAtLocation(View parent, int gravity, int x, int y):相對於父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),能夠設置偏移或無偏移
相關文章
相關標籤/搜索