標籤:android des style blog http java
版本:1.0
日期:2014.4.29
著作權:© 2014 kince 轉載註明出處
關於View的拖動大家應該比較瞭解了,比如對一個控制項IamgeView拖動,或者一個視圖View拖動,實現方式也很容易,繼承OnTouchListener介面,然後重寫onTouch方法,在觸屏事件進行處理即可。但是Popupwindow如何?拖動呢,我們都知道它和普通的View不一樣,因為它不是繼承於View類的,但是它的實現卻是和View密切相關的,因為我們都知道Android視圖的顯示都是由View來處理的,所以一定離不開它。從Popupwindow的實現就可以看出來,
import com.android.internal.R;import android.content.Context;import android.content.res.Resources;import android.content.res.TypedArray;import android.graphics.PixelFormat;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.graphics.drawable.StateListDrawable;import android.os.Build;import android.os.IBinder;import android.util.AttributeSet;import android.view.Gravity;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.View;import android.view.View.OnTouchListener;import android.view.ViewGroup;import android.view.ViewTreeObserver;import android.view.ViewTreeObserver.OnScrollChangedListener;import android.view.WindowManager;import java.lang.ref.WeakReference;
上面是它的導包情況,基本上不是和View相關,就是和繪圖相關。因此關於Popupwindow的拖動這一塊,也和View有聯絡。首先看一下它的API,看一看有沒有和View移動、變化相關的方法,果然在最後有幾個update()方法,如下:
update()方法用來更新Popupwindow的位置和大小的,那麼問題就好解決了。看代碼:
package com.example.drag_and_drop_movablepopupwindow;import android.support.v7.app.ActionBarActivity;import android.graphics.Color;import android.os.Bundle;import android.view.Gravity;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuItem;import android.view.MotionEvent;import android.view.View;import android.view.View.OnTouchListener;import android.view.ViewGroup.LayoutParams;import android.widget.Button;import android.widget.PopupWindow;import android.widget.TextView;public class MainActivity extends ActionBarActivity {private Button btnOpenPopup;private int mCurrentX;private int mCurrentY;private PopupWindow mPopup; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btnOpenPopup = (Button) findViewById(R.id.openpopup);btnOpenPopup.setOnClickListener(new Button.OnClickListener() {@Overridepublic void onClick(View arg0) {creatPopubWindow_1();}});}/** * 1 */private void creatPopubWindow_1() {LayoutInflater layoutInflater = (LayoutInflater) getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);View popupView = layoutInflater.inflate(R.layout.popup, null);final PopupWindow popupWindow = new PopupWindow(popupView,200, 200);Button btnDismiss = (Button) popupView.findViewById(R.id.dismiss);btnDismiss.setOnClickListener(new Button.OnClickListener() {@Overridepublic void onClick(View v) {popupWindow.dismiss();}});popupWindow.showAsDropDown(btnOpenPopup, 50, 50);popupView.setOnTouchListener(new OnTouchListener() {int orgX, orgY;int offsetX, offsetY;@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:orgX = (int) event.getX();orgY = (int) event.getY();break;case MotionEvent.ACTION_MOVE:offsetX = (int) event.getRawX() - orgX;offsetY = (int) event.getRawY() - orgY;popupWindow.update(offsetX, offsetY, -1, -1, true);break;}return true;}});}}
效果
首先對Popupwindow設定觸摸事件,然後在回調方法中進行計算,如果手指拖動了Popupwindow,那麼就調用update()方法來更新它的位置。有些同學可能不太理解參數-1是什麼意思,在上面的API中,寫明的是寬和高,這裡怎麼變成-1了呢,看一下Popupwindow原始碼就明白了。
/** * <p>Updates the position and the dimension of the popup window. Width and * height can be set to -1 to update location only. Calling this function * also updates the window with the current popup state as * described for {@link #update()}.</p> * * @param x the new x location * @param y the new y location * @param width the new width, can be -1 to ignore * @param height the new height, can be -1 to ignore * @param force reposition the window even if the specified position * already seems to correspond to the LayoutParams */ public void update(int x, int y, int width, int height, boolean force) { if (width != -1) { mLastWidth = width; setWidth(width); } if (height != -1) { mLastHeight = height; setHeight(height); } if (!isShowing() || mContentView == null) { return; } WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams(); boolean update = force; final int finalWidth = mWidthMode < 0 ? mWidthMode : mLastWidth; if (width != -1 && p.width != finalWidth) { p.width = mLastWidth = finalWidth; update = true; } final int finalHeight = mHeightMode < 0 ? mHeightMode : mLastHeight; if (height != -1 && p.height != finalHeight) { p.height = mLastHeight = finalHeight; update = true; } if (p.x != x) { p.x = x; update = true; } if (p.y != y) { p.y = y; update = true; } final int newAnim = computeAnimationResource(); if (newAnim != p.windowAnimations) { p.windowAnimations = newAnim; update = true; } final int newFlags = computeFlags(p.flags); if (newFlags != p.flags) { p.flags = newFlags; update = true; } if (update) { setLayoutDirectionFromAnchor(); mWindowManager.updateViewLayout(mPopupView, p); } }
前兩個if判斷已經說得很清楚了,如果參數是-1的話,就不改變Popupwindow的大小了,因為我們只是移動位置,所以才這樣寫。那關於Popupwindow的移動最後是怎麼實現的呢,可以看出就是調用WindowManager的updateViewLayout()方法,這個方法在WindowManager中並沒有實現,它是ViewManager介面裡面的方法,WindowManager繼承了ViewManager。說到ViewManager,它裡面定義的方法都很常用,看代碼:
/** Interface to let you add and remove child views to an Activity. To get an instance * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}. */public interface ViewManager{ /** * Assign the passed LayoutParams to the passed View and add the view to the window. * <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming * errors, such as adding a second view to a window without removing the first view. * <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a * secondary {@link Display} and the specified display can‘t be found * (see {@link android.app.Presentation}). * @param view The view to be added to this window. * @param params The LayoutParams to assign to view. */ public void addView(View view, ViewGroup.LayoutParams params); public void updateViewLayout(View view, ViewGroup.LayoutParams params); public void removeView(View view);}
這下大家應該明了,我們經常用的addView、removeView方法就是在這裡面定義的,那麼誰去實現呢?就是Layout控制項,比如LinearLayout、RelativeLayout等,所以我們剛才用的updateViewLayout()方法也是在xml布局檔案中的layout定義好的。