引用
??現(xiàn)如今很多軟件都有個人中心,而個人中心往往都用來設(shè)置個人信息奋姿,一般的個人中心包括:用戶頭像,用戶名素标,以及其他的業(yè)務(wù)邏輯需要的集合称诗。今天我們就來封裝彈出窗口PopupWindow,點擊更換頭像就是很經(jīng)典的例子头遭。
介紹
??PopupWindow用來做彈出框并不是獨一份寓免,一般系統(tǒng)使用的是另一種,我們很多軟件的消息通知其實都是用AlertDialog计维,但PopupWindow好就好在它足夠靈活袜香,可以適應(yīng)很多自定義的彈出框環(huán)境。
本期效果
區(qū)別
(1)AlertDialog不能指定顯示的位置享潜,只能默認(rèn)顯示在屏幕最中間困鸥。而
PopupWindow是可以指定顯示位置的,隨便哪個位置都可以,更加靈活疾就。
(2)AlertDialog是非阻塞線程式對話框:AlertDialog彈出時澜术,后臺還可以做事情;而PopupWindow是阻塞線程式對話框:PopupWindow彈出時猬腰,程序會等待鸟废,在PopupWindow退出前,程序一直等待姑荷,只有當(dāng)我們調(diào)用了dismiss方法的后盒延,PopupWindow退出,程序才會向下執(zhí)行鼠冕。
這兩種區(qū)別的表現(xiàn)是:
??AlertDialog彈出時添寺,背景是黑色的,但是當(dāng)我們點擊背景懈费,AlertDialog會消失计露,證明程序不僅響應(yīng)AlertDialog的操作,還響應(yīng)其他操作憎乙,其他程序沒有被阻塞票罐,這說明了AlertDialog是非阻塞式對話框;PopupWindow彈出時泞边,背景沒有什么變化该押,但是當(dāng)我們點擊背景的時候,程序沒有響應(yīng)阵谚,只允許我們操作PopupWindow蚕礼,其他操作被阻塞。
(3)PopupWindow的位置按照有無偏移分椭蹄,可以分為偏移和無偏移兩種闻牡;按照參照物的不同净赴,可以分為相對于某個控件(Anchor錨)和相對于父控件绳矩。
用法
第一步:布局文件
(1)主布局:activity_case22.xml
說明:我簡單添加了一個居中的按鈕點擊事件來處理彈出popupwindow。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/case22_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".show.Case22"
tools:ignore="MissingConstraints">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:titleTextColor="@color/white"
android:background="@color/green"
app:title="PopupWindow使用" />
<Button
android:id="@+id/show_popupWindow"
android:layout_width="match_parent"
android:textAllCaps="false"
android:layout_height="wrap_content"
android:text="彈出PopupWindow"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
(2)子布局:popup_select_layout.xml
說明:這里是比較常用的彈出框玖翅,拍照+相冊+取消翼馆,View用作分割線。
<androidx.constraintlayout.widget.ConstraintLayout 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="match_parent"
android:layout_height="match_parent"
tools:ignore="MissingConstraints">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
app:layout_constraintBottom_toBottomOf="parent">
<Button
android:id="@+id/take_photo"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/button_round_style"
android:gravity="center"
android:text="拍照"
android:textColor="@color/black"
android:textSize="20sp" />
<View
android:id="@+id/divide1"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/black"
app:layout_constraintTop_toBottomOf="@id/take_photo" />
<Button
android:id="@+id/picture"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/button_round_style"
android:gravity="center"
android:text="相冊"
android:textColor="@color/black"
android:textSize="20sp"
app:layout_constraintTop_toBottomOf="@id/divide1" />
<View
android:id="@+id/divide2"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/black"
app:layout_constraintTop_toBottomOf="@id/picture" />
<Button
android:id="@+id/cancel"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/button_round_style"
android:gravity="center"
android:text="取消"
android:textColor="@color/black"
android:textSize="20sp"
app:layout_constraintTop_toBottomOf="@id/divide2" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
第二步:創(chuàng)建TestPopupWindow類
繼承自PopupWindow類金度。
/**
* @data on 2020/9/14 9:18 AM
* @auther ArmStrong
* @describe
*/
public class TestPopupWindow extends PopupWindow {
TestDataListener mTestDataListener;
int type = 0;
public TestPopupWindow(Context context) {
super(context);
View contentView = LayoutInflater.from(context).inflate(R.layout.popup_select_layout, null);
//封裝成CommonPopupWindow類
setContentView(contentView);
setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
setFocusable(true);
setBackgroundDrawable(new BitmapDrawable());
setOutsideTouchable(true);
setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
}
});
//初始化控件
TextView takePhoto = (TextView)contentView.findViewById(R.id.take_photo);
TextView picture = (TextView)contentView.findViewById(R.id.picture);
TextView cancel = (TextView)contentView.findViewById(R.id.cancel);
takePhoto.setOnClickListener((View)->{
Log.i("TestPopupWindow: ","拍照");
type = 0;
if(mTestDataListener != null){
mTestDataListener.getTestData(type);
}
dismiss();
});
picture.setOnClickListener((View)->{
Log.i("TestPopupWindow: ","相冊");
type = 1;
if(mTestDataListener != null){
mTestDataListener.getTestData(type);
}
dismiss();
});
cancel.setOnClickListener((View)->{
Log.i("TestPopupWindow: ","取消");
type = 2;
if(mTestDataListener != null){
mTestDataListener.getTestData(type);
}
dismiss();
});
}
//回調(diào)事件接口
public interface TestDataListener {
void getTestData(int type);
}
public void setTestClickaListener(TestDataListener testDataListener) {
mTestDataListener = testDataListener;
}
}
第三步:在Activity中使用
public class Case22 extends AppCompatActivity {
TestPopupWindow popupWindow;
Button btnShowPopupWindow;
@SuppressLint("ResourceType")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_case22);
ConstraintLayout case22Layout = findViewById(R.id.case22_layout); //主布局設(shè)置彈出窗口定位使用
btnShowPopupWindow = findViewById(R.id.show_popupWindow);
showPopupWindow(case22Layout);
}
//展示彈出窗口
private void showPopupWindow(View parent){
btnShowPopupWindow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
popupWindow = new TestPopupWindow(getApplicationContext());
popupWindow.showAtLocation(parent, Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 0);//在activity的底部展示应媚。
// popupWindow.showAsDropDown(binding.showPopupWindow); //在某個控件下方彈出Popupwindow
popupWindow.setTestClickaListener(new TestPopupWindow.TestDataListener() {
@Override
public void getTestData(int type) {
Log.d("test: ", String.valueOf(type)); //測試
switch (type){
case 0: //拍照
Toast.makeText(getBaseContext(),"拍照",Toast.LENGTH_SHORT).show();
break;
case 1: //相冊
Toast.makeText(getBaseContext(),"相冊",Toast.LENGTH_SHORT).show();
break;
case 2: //取消
Toast.makeText(getBaseContext(),"取消",Toast.LENGTH_SHORT).show();
break;
}
}
});
}
});
}
}
大功告成!
解析
第一:封裝的思想
??我們都知道Java語言的三個特點:封裝繼承和多態(tài)猜极。但我們一直以來在定義PopupWindow時中姜,都是在new其對象的時候在activity中調(diào)用其實例化對象的set方法來設(shè)置popupWindow的屬性,從而實現(xiàn)我們的業(yè)務(wù),但這種封裝并不徹底丢胚。
??為了體現(xiàn)徹底的封裝思想翩瓜,我們在這里自定義了TestPopupWindow類并繼承自PopupWindow,在其類中構(gòu)造方法里設(shè)置携龟,每當(dāng)在activity中new一個對象兔跌,這些屬性就會被設(shè)置,一個封裝峡蟋,實現(xiàn)多處的代碼復(fù)用坟桅,同時有效地簡化了Activity的代碼。
第二:定義其彈出位置
??PopupWindow可以靈活地定義其顯示的位置蕊蝗,一種方式是絕對定位:采用showAtLocation()方法仅乓,它有四個參數(shù),分別是View蓬戚,Gravity方灾,x,y碌更,父布局+位置+偏移量裕偿。本例中我們讓其位于父布局的底部并且水平居中Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL。
??另一中方式是相對定位:采用showAsDropDown()方法痛单,它用來定義顯示PopupWindow在某個控件之下彈出嘿棘。
效果圖
千夜零一:“之前總是看各種博客學(xué)習(xí)東西,現(xiàn)在我想用博客記錄下我的學(xué)習(xí)腳步旭绒,好東西也需要分享鸟妙,索取和給予是相互的。以后會盡量日更的挥吵!目標(biāo)完成1001篇博客哈哈重父。”
??如果覺得對你有所幫助忽匈,請不要吝嗇你的點贊房午,有問題也可以在下方評論區(qū)留言哦,關(guān)注我一起學(xué)習(xí)吧~