Hộp thư đến không sử dụng Snackbar tiêu chuẩn và cũng không sử dụng cửa sổ lớp phủ, nó sử dụng chế độ xem tùy chỉnh. Tôi đã giải mã APK để xác minh cách chúng đạt được hiệu ứng này và tôi đã cố gắng tái tạo một ví dụ tối thiểu.
Trước hết tạo ra một mới bố trí custom_snackbar.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#323232"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<TextView
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="Marked done"
android:textColor="@android:color/white"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:gravity="center_vertical"
android:minWidth="48dp"
android:text="undo"
android:textAllCaps="true"
android:textColor="#a1c2fa"/>
</LinearLayout>
Sau đó, tạo ra những phương pháp để hiển thị và bỏ qua những tùy chỉnh Snackbar:
private View customSnackbar;
private void showCustomSnackbar(final Context context) {
customSnackbar = LayoutInflater.from(context).inflate(R.layout.custom_snackbar, null, false);
customSnackbar.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//action implementation
}
});
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.format = PixelFormat.TRANSLUCENT;
lp.gravity = Gravity.BOTTOM;
lp.flags = WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
customSnackbar.setLayoutParams(lp);
WindowManager windowManager = (WindowManager) context.getSystemService(WINDOW_SERVICE);
if (windowManager != null) {
windowManager.addView(customSnackbar, customSnackbar.getLayoutParams());
Point m = new Point();
windowManager.getDefaultDisplay().getSize(m);
int childMeasureSpecWidth = ViewGroup.getChildMeasureSpec(View.MeasureSpec.makeMeasureSpec(m.x, View.MeasureSpec.EXACTLY), 0, lp.width);
int childMeasureSpecHeight = ViewGroup.getChildMeasureSpec(View.MeasureSpec.makeMeasureSpec(m.y, View.MeasureSpec.EXACTLY), 0, lp.height);
customSnackbar.measure(childMeasureSpecWidth, childMeasureSpecHeight);
customSnackbar.setTranslationY(customSnackbar.getMeasuredHeight());
customSnackbar.animate()
.setDuration(300)
.translationX(0.0f)
.translationY(0.0f);
}
}
private void dismissCustomSnackbar(final Context context) {
customSnackbar.animate()
.setDuration(300)
.translationX(0.0f)
.translationY(customSnackbar.getMeasuredHeight())
.withEndAction(new Runnable() {
@Override
public void run() {
WindowManager windowManager = (WindowManager) context.getSystemService(WINDOW_SERVICE);
if (windowManager != null) {
windowManager.removeView(customSnackbar);
}
}
});
}
Đây là kết quả thu được:
Nguồn
2018-02-04 23:07:06
Tôi đã thử đặt độ cao của chế độ xem của thanh snack, theo mặc định là 6, với số lượng lớn, nhưng điều này không giúp ích gì. Tôi đã thử độ cao lên tới 5000! – Erik
Tôi cho rằng họ phải sử dụng cửa sổ lớp phủ (ví dụ: 'TYPE_SYSTEM_OVERLAY' trước 8.0,' TYPE_APPLICATION_OVERLAY' trên 8.0+). Tôi không sử dụng Hộp thư đến của Google nên tôi không thể kiểm tra kịch bản này. Tuy nhiên, nếu Inbox không có hành vi này trên 8.0+, nhưng từ 7.1 trở lên, thì rất có thể là lớp phủ, vì [lớp phủ không thể che phủ IME trên 8.0+] (https://developer.android.com /about/versions/oreo/android-8.0-changes.html#cwt). – CommonsWare
'độ cao' chỉ ảnh hưởng đến bố cục ứng dụng của bạn. Tôi nghĩ rằng có thể có một số thủ thuật với việc tạo ra Snakebar với bối cảnh khác nhau. – sakiM