【Android開發】動畫彈出PopupWindow並使背景變暗
阿新 • • 發佈:2019-01-03
我們在平常的android應用開發過程中,當應用資料太多太繁雜時,通常都會通過分類篩選讓使用者更好的找到自己想要的資訊。因此利用PopupWindow或Dialog讓使用者快速選擇定位是一個很好的選擇。如我們想在美團上查詢附近有什麼電影院時:
點選按鈕彈出popupwindow,popupwindow是很好實現的,只需要使用PopupWindow的構造方法再將自己寫的佈局引入進去即可:
View popupView = getLayoutInflater().inflate(R.layout.layout_popupwindow, null);
mPopupWindow = new PopupWindow(popupView, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, true);
//設定點選空白處消失
mPopupWindow.setTouchable(true);
mPopupWindow.setOutsideTouchable(true);
mPopupWindow.setBackgroundDrawable(new BitmapDrawable(getResources(), (Bitmap) null));
最後通過
mPopupWindow.showAsDropDown (anchor,xoff,yoff);
彈出popupwindow。
但是這樣實現出來的效果只是在原來某個view旁彈出一個選項框,其他地方沒有發生任何變化。如果想要在介面上實現一層黑色半透明遮罩將彈出框與主介面區分開來給使用者更好的體驗,這黑色透明背景又如何實現呢?
通過網上翻看資料,有各種各樣的實現方法。其中有一種是在popupwindow彈出時改變window的透明度的屬性,而監聽到popupwindow dismiss的事件時再將其改回來。主要程式碼實現如下:
// 設定背景顏色變暗
WindowManager.LayoutParams lp = getWindow().getAttributes ();
lp.alpha = 0.7f;
getWindow().setAttributes(lp);
mPopupWindow.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss() {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.alpha = 1f;
getWindow().setAttributes(lp);
}
});
//摘自:http://blog.csdn.net/harryweasley/article/details/46914121
如果當PopupWindow是在螢幕中間或者從下方彈出時,這是一種很好的實現方式,但是如果我想要它從ActionBar正下方彈出,就會發現ActionBar的背景也變暗了,這樣會顯得介面很不協調。
由上面聯想到,如果我在介面最上層自己放一個黑色半透明的View,平常讓它隱藏掉,當PopupWindow顯示的時候讓它也顯示出來就OK了,PopupWindow可以使用動畫讓其從ActionBar後面慢慢滑出來!
具體程式碼實現如下:
content_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main" tools:context=".MainActivity">
<!--黑色背景遮罩層,平時隱藏 -->
<View
android:id="@+id/gray_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:background="#66000000"/>
</RelativeLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private final static String TAG="MainActivity";
private PopupWindow mPopupWindow;
private Toolbar toolbar;
private View mGrayLayout;
private boolean isPopWindowShowing=false;
int fromYDelta;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
mGrayLayout=findViewById(R.id.gray_layout);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
//對黑色半透明背景做監聽,點選時開始退出動畫並將popupwindow dismiss掉
mGrayLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(isPopWindowShowing){
mPopupWindow.getContentView().startAnimation(AnimationUtil.createOutAnimation(MainActivity.this, fromYDelta));
mPopupWindow.getContentView().postDelayed(new Runnable() {
@Override
public void run() {
mPopupWindow.dismiss();
}
},AnimationUtil.ANIMATION_OUT_TIME);
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
if(isPopWindowShowing){
mPopupWindow.getContentView().startAnimation(AnimationUtil.createOutAnimation(MainActivity.this, fromYDelta));
mPopupWindow.getContentView().postDelayed(new Runnable() {
@Override
public void run() {
mPopupWindow.dismiss();
}
},AnimationUtil.ANIMATION_OUT_TIME);
}else{
showPopupWindow();
}
// return true;
}
return super.onOptionsItemSelected(item);
}
private void showPopupWindow(){
final View contentView= LayoutInflater.from(this).inflate(R.layout.selectlist,null);
TextView t1= (TextView) contentView.findViewById(R.id.text1);
mPopupWindow=new PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
mPopupWindow.setBackgroundDrawable(new BitmapDrawable());
//將這兩個屬性設定為false,使點選popupwindow外面其他地方不會消失
mPopupWindow.setOutsideTouchable(false);
mPopupWindow.setFocusable(false);
mGrayLayout.setVisibility(View.VISIBLE);
//獲取popupwindow高度確定動畫開始位置
int contentHeight=ViewUtils.getViewMeasuredHeight(contentView);
Log.i(TAG,"contentview height="+contentHeight);
mPopupWindow.showAsDropDown(toolbar, 0, 0);
fromYDelta=-contentHeight-50;
Log.i(TAG,"fromYDelta="+fromYDelta);
mPopupWindow.getContentView().startAnimation(AnimationUtil.createInAnimation(this, fromYDelta));
mPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
isPopWindowShowing=false;
mGrayLayout.setVisibility(View.GONE);
}
});
t1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Snackbar.make(findViewById(R.id.gray_layout), "click 1", Snackbar.LENGTH_SHORT)
.setAction("Action", null).show();
}
});
isPopWindowShowing=true;
}
}
AnimationUtil.java
public class AnimationUtil {
//動畫持續時間
public final static int ANIMATION_IN_TIME=500;
public final static int ANIMATION_OUT_TIME=500;
public static Animation createInAnimation(Context context,int fromYDelta){
AnimationSet set=new AnimationSet(context,null);
set.setFillAfter(true);
TranslateAnimation animation=new TranslateAnimation(0,0,fromYDelta,0);
animation.setDuration(ANIMATION_IN_TIME);
set.addAnimation(animation);
AlphaAnimation alphaAnimation=new AlphaAnimation(0,1);
alphaAnimation.setDuration(ANIMATION_IN_TIME);
set.addAnimation(alphaAnimation);
return set;
}
public static Animation createOutAnimation(Context context,int toYDelta){
AnimationSet set=new AnimationSet(context,null);
set.setFillAfter(true);
TranslateAnimation animation=new TranslateAnimation(0,0,0,toYDelta);
animation.setDuration(ANIMATION_OUT_TIME);
set.addAnimation(animation);
AlphaAnimation alphaAnimation=new AlphaAnimation(1,0);
alphaAnimation.setDuration(ANIMATION_OUT_TIME);
set.addAnimation(alphaAnimation);
return set;
}
}
selectlist.xml
<?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="wrap_content"
android:background="#ffffff"
android:orientation="vertical">
<TextView
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/select_1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/select_2"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/select_3"/>
</LinearLayout>
ViewUtils.java
public class ViewUtils {
/**
* 獲取控制元件的高度
*/
public static int getViewMeasuredHeight(View view) {
calculateViewMeasure(view);
return view.getMeasuredHeight();
}
/**
* 獲取控制元件的寬度
*/
public static int getViewMeasuredWidth(View view) {
calculateViewMeasure(view);
return view.getMeasuredWidth();
}
/**
* 測量控制元件的尺寸
*/
private static void calculateViewMeasure(View view) {
int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(w, h);
}
}
實現效果如下: