帝都幾日降溫,終于被撂倒了。but 只要一息尚存就得不斷進步!于是,寫出 《PopupWindow 使用詳解》的第二篇 筆記,先奉上 第一篇鏈接: 《PopupWindow 使用詳解(一) 中文API 文檔 贈送 ListPopupWindow 中文 API》 。下面給大家展示一下制作的效果gif。
下面進行一個樣式一個樣式的肢解哈,對了,所有效果筆者都沒有制作載入動畫和退出動畫。有需要的小伙伴可以通過 這個方法 public void setAnimationStyle(int animationStyle)
進行設置,也是很簡單、很常用的。
效果一、圖片選取功能(帶陰影)
1、布局設置
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/ll_pic"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/shape_pic_select"android:gravity="bottom"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginStart="5dp"android:layout_marginEnd="5dp"android:orientation="vertical"><Buttonandroid:id="@+id/btn_pic_photo"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="1dp"android:background="#ffffff"android:text="相 冊"android:textColor="#3c3c3c"android:textSize="16sp" /><Buttonandroid:id="@+id/btn_pic_camera"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="1dp"android:background="#ffffff"android:text="拍 照"android:textColor="#3c3c3c"android:textSize="16sp" /><Buttonandroid:id="@+id/btn_pic_cancel"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="1dp"android:background="#ffffff"android:text="取 消"android:textColor="#3c3c3c"android:textSize="16sp" /></LinearLayout>
</LinearLayout>
2、Java 邏輯代碼
/*** 照片選擇器*/@SuppressLint("InflateParams")private void showPicSelect() {view = LayoutInflater.from(this).inflate(R.layout.item_pic_select, null, false);LinearLayout llPop = view.findViewById(R.id.ll_pic);Button btnCamera = view.findViewById(R.id.btn_pic_camera);Button btnPhoto = view.findViewById(R.id.btn_pic_photo);Button btnCancel = view.findViewById(R.id.btn_pic_cancel);btnCamera.setOnClickListener(this);btnPhoto.setOnClickListener(this);btnCancel.setOnClickListener(this);llPop.setOnClickListener(this);myPop = new PopupWindow(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);myPop.setBackgroundDrawable(new ColorDrawable());myPop.showAtLocation(rlMain, Gravity.BOTTOM, 0, 0);}@Overridepublic void onBackPressed() {if (myPop.isShowing()) {myPop.dismiss();} else {super.onBackPressed();}}
3、實現思路
之前筆者看了看網上百度來的答案,實現陰影效果的思路大概是,當 PopupWindow 彈出時將 Activity 設置為半透明,但是這種思路的弊端是 Activity 透明了,你懂得,你可以在 A Activity 界面直接看到了 桌面或者是 B Activity 界面的東西,很蛋疼。
筆者的思路是:為 PopupWindow 設置一個半透明的背景色,然后監聽這不背景 layout 的點擊事件,和物理鍵的返回事件。否則會出現點擊無效果的現象。具體邏輯如上。
二、仿qq和微信的長按置頂刪除功能
1、布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:id="@+id/ll_qq"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:background="@drawable/shape_qq"android:orientation="horizontal"tools:ignore="UselessParent"><TextViewandroid:id="@+id/tv_delete"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="10dp"android:text="刪除"android:textColor="#ffffff"android:textSize="16sp" /><Viewandroid:layout_width="2dp"android:layout_height="match_parent"android:layout_marginTop="5dp"android:layout_marginBottom="5dp"android:background="#666666" /><TextViewandroid:id="@+id/tv_be_top"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="10dp"android:text="置頂"android:textColor="#ffffff"android:textSize="16sp" /></LinearLayout><ImageViewandroid:id="@+id/iv_three"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/ll_qq"android:layout_centerHorizontal="true"android:background="@null"android:layout_marginTop="-5dp"android:contentDescription="@string/app_name"android:src="@mipmap/ic_three" />
</RelativeLayout>
2、Java 邏輯
/*** 仿qq 產生水滴按鈕*/@SuppressLint("InflateParams")private void showQq() {view = LayoutInflater.from(this).inflate(R.layout.item_qq, null, false);TextView tvTop = view.findViewById(R.id.tv_be_top);TextView tvDelete = view.findViewById(R.id.tv_delete);tvDelete.setOnClickListener(this);tvTop.setOnClickListener(this);myPop = new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);myPop.setBackgroundDrawable(new ColorDrawable());myPop.setOutsideTouchable(true);myPop.getContentView().measure(0, 0);myPop.showAsDropDown(cvMain, (cvMain.getWidth() - myPop.getContentView().getMeasuredWidth()) / 2,-(cvMain.getHeight() + myPop.getContentView().getMeasuredHeight()));}
3、實現思路
這個其實沒什么好說的,但是需要注意的兩點是:(1)、ui 一定要有的或者是自己會個ps 也行,仔細看筆者布局,有一個地方,設置 margin 屬性居然用了 負值 否則無法保證 下面的shape 背景與三角標進行無縫銜接;(2)、注意這個方法一定要設置即便是不設置值 public void setBackgroundDrawable(Drawable background)
否則會導致 public void setOutsideTouchable(boolean touchable)
這個方法不起作用,即出現點擊 PopupWindow 外部區域無法隱藏 PopupWindow 的尷尬局面
三、實現懸浮圖片輪播
1、布局代碼
<!--布局 1-->
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="#00000000"app:cardCornerRadius="10dp"><android.support.v4.view.ViewPagerandroid:id="@+id/vp_pop"android:layout_width="200dp"android:layout_height="300dp"android:background="#48BAFF" /></android.support.v7.widget.CardView><!--布局 2-->
<?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:gravity="center"android:orientation="vertical"><ImageViewandroid:layout_width="200dp"android:layout_height="300dp"android:contentDescription="@string/app_name"android:src="@mipmap/pic_1" />
</LinearLayout>
2、Java 邏輯代碼
/*** 輪播效果*/@SuppressLint("InflateParams")private void showPager() {views = new ArrayList<>();view = LayoutInflater.from(this).inflate(R.layout.item_pager, null, false);ViewPager vpPop = view.findViewById(R.id.vp_pop);picView01 = LayoutInflater.from(this).inflate(R.layout.item_pop_vp_01, null, false);picView02 = LayoutInflater.from(this).inflate(R.layout.item_pop_vp_02, null, false);picView03 = LayoutInflater.from(this).inflate(R.layout.item_pop_vp_03, null, false);picView04 = LayoutInflater.from(this).inflate(R.layout.item_pop_vp_04, null, false);views.add(picView01);views.add(picView02);views.add(picView03);views.add(picView04);vpPop.setAdapter(new MyPopAdapter());myPop = new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);myPop.setOutsideTouchable(true);//懸浮效果myPop.setElevation(5);myPop.setBackgroundDrawable(new ColorDrawable(0x00ffffff));myPop.showAtLocation(rlMain, Gravity.CENTER, 0, 0);}/*** 配置 adapter*/class MyPopAdapter extends PagerAdapter {@Overridepublic int getCount() {return views.size();}@Overridepublic boolean isViewFromObject(@NonNull View view, @NonNull Object o) {return view == o;}@NonNull@Overridepublic Object instantiateItem(@NonNull ViewGroup container, int position) {container.addView(views.get(position));return views.get(position);}@Overridepublic void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {container.removeView(views.get(position));}}@Overrideprotected void onDestroy() {super.onDestroy();if (views != null) {views.remove(picView01);views.remove(picView02);views.remove(picView03);views.remove(picView04);}if (myPop.isShowing()) {myPop.dismiss();}}
3、實現思路及注意事項
首先,加載圖片需要進行相關處理,比如說用過Picasso 或者是 Glide 等框架,當然了也可將進行自己壓縮;
其次,由于為了突出美觀,筆者用了一個 CardView 可以設置圓角,但是 CardView 的陰影屬性失效了,為了凸顯層次感可以設置 PopupWindow 的這個方法 public void setElevation(float elevation)
該方法可以是你感覺出一種懸浮的效果;
最后,沒用的 view 需要進行清理,否則會留在內存哦。
四、向下彈出水滴效果
1、布局源碼
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignBottom="@+id/iv_beauty"android:layout_toEndOf="@+id/iv_beauty"android:src="@mipmap/ic_right" /><ImageViewandroid:id="@+id/iv_beauty"android:layout_width="150dp"android:layout_height="200dp"android:background="#669"android:src="@mipmap/pic_5" />
</RelativeLayout>
2、Java 邏輯
/*** 向下彈出*/@SuppressLint("InflateParams")private void showDown() {view = LayoutInflater.from(this).inflate(R.layout.item_anywhere, null, false);myPop = new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);myPop.setBackgroundDrawable(new ColorDrawable());myPop.setOutsideTouchable(true);myPop.getContentView().measure(0, 0);myPop.showAsDropDown(btnPopDown, -((myPop.getContentView().getMeasuredWidth() - btnPopDown.getWidth()) / 2), 0);}
3、注意事項
這個沒什么可說的了,和 上面 小標題二 相同 ,具體查看上方即可。
五、實現屏幕右側向左彈出
1、布局代碼
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignBottom="@+id/iv_beauty"android:layout_toEndOf="@+id/iv_beauty"android:src="@mipmap/ic_right" /><ImageViewandroid:id="@+id/iv_beauty"android:layout_width="150dp"android:layout_height="200dp"android:background="#669"android:src="@mipmap/pic_5" />
</RelativeLayout>
2、Java 邏輯代碼
/*** 向左彈出*/@SuppressLint("InflateParams")private void showStart() {view = LayoutInflater.from(this).inflate(R.layout.item_pop_start, null, false);myPop = new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);myPop.setBackgroundDrawable(new ColorDrawable());myPop.setOutsideTouchable(true);myPop.getContentView().measure(0, 0);myPop.showAsDropDown(fabStart, -(myPop.getContentView().getMeasuredWidth()), -(fabStart.getHeight() / 2 + myPop.getContentView().getMeasuredHeight()));}
3、注意事項
這里比較復雜的 就是 PopupWindow 的錨點位置 為 其寄生的 控件的 左下角,而 Popwindow 的起始點為 左上角,但是 PopupWindow 默認不超出界面。這就導致了 PopupWindow 明明在 控件則左側,但是卻無法到達自己的想要位置。
所以 對于該現象,我們只能 在計算偏移量的時候 需要向左 移動 (控件長度+PopupWindow的長度 +其他長度)
六、實現需要獲取焦點的控件使用
1、布局代碼
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="#00000000"app:cardCornerRadius="10dp"><RelativeLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="#00000000"android:padding="10dp"><TextViewandroid:id="@+id/tv_name_p"android:layout_width="wrap_content"android:layout_height="40dp"android:gravity="center_vertical"android:text="賬戶:"android:textSize="16sp" /><EditTextandroid:layout_width="200dp"android:layout_height="40dp"android:layout_toEndOf="@+id/tv_name_p"android:background="@null"android:gravity="center_vertical"android:inputType="number"android:paddingStart="10dp"android:paddingEnd="10dp"android:singleLine="true"android:textSize="16sp"tools:text="123" /><TextViewandroid:id="@+id/tv_password_p"android:layout_width="wrap_content"android:layout_height="40dp"android:layout_below="@+id/tv_name_p"android:gravity="center_vertical"android:text="密碼:"android:textSize="16sp" /><EditTextandroid:layout_width="200dp"android:layout_height="40dp"android:layout_below="@+id/tv_name_p"android:layout_toEndOf="@+id/tv_password_p"android:background="@null"android:gravity="center_vertical"android:inputType="numberPassword"android:paddingStart="10dp"android:paddingEnd="10dp"android:singleLine="true"android:textSize="16sp"tools:text="123" /></RelativeLayout>
</android.support.v7.widget.CardView>
2、邏輯代碼
/*** 向右彈出 輸入框*/@SuppressLint("InflateParams")private void showEnd() {view = LayoutInflater.from(this).inflate(R.layout.item_end_input, null, false);myPop = new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);myPop.setBackgroundDrawable(new ColorDrawable(0x00ffffff));myPop.setElevation(10);myPop.setOutsideTouchable(true);myPop.setFocusable(true);myPop.getContentView().measure(0, 0);myPop.showAsDropDown(fadEnd, (int) (fadEnd.getWidth() * 1.3), -((fadEnd.getHeight() + myPop.getContentView().getMeasuredHeight()) / 2));}
3、注意事項
這里一定要 設置該方法 public void setFocusable(boolean focusable)
否則 在切換EditText 的時候只是光標進行了移動,但是 無法召喚軟鍵盤。
七、總結
1、筆者認為,上面的大概可以滿足比較簡單的開發需求了,筆者很菜,這些已經足可以滿足筆者了目前;
2、關于偏移量這個會涉及導到一些小小的計算和一點點邏輯想法,所以不要只是做 cv 戰士,作為文雅的程序員,我們還是需要有點自己的想法的哈;
3、代碼上傳 github 地址為:PopupWindow
4、希望可以幫到你,批評和建議,望各位大佬留言,小生在這里謝過了。