Last active
January 25, 2019 04:23
-
-
Save fiskurgit/2344ac8b8a0a6cd97ff8d0c5d445090b to your computer and use it in GitHub Desktop.
Material Design 2 BottomSheetDialog that doesn't draw over the bottom navigation bar.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package online.fisk.kroki.views; | |
import android.app.Activity; | |
import android.app.Dialog; | |
import android.content.DialogInterface; | |
import android.graphics.Color; | |
import android.graphics.Point; | |
import android.graphics.drawable.ColorDrawable; | |
import android.graphics.drawable.GradientDrawable; | |
import android.os.Build; | |
import android.support.annotation.NonNull; | |
import android.support.design.widget.BottomSheetBehavior; | |
import android.support.design.widget.CoordinatorLayout; | |
import android.util.DisplayMetrics; | |
import android.view.Display; | |
import android.view.Gravity; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.view.Window; | |
import android.view.WindowManager; | |
import timber.log.Timber; | |
/* | |
FiskBottomSheetDialog dialog = new FiskBottomSheetDialog(activity, R.layout.some_layout, R.style.AppTheme); | |
View view = dialog.getContentView(); | |
*/ | |
public class FiskBottomsheetDialog { | |
private final Dialog dialog; | |
private View contentView; | |
private boolean cancelable = true; | |
private CoordinatorLayout coordinatorLayout; | |
private Dialog.OnDismissListener onDismissListener = null; | |
private BottomSheetBehavior bottomSheetBehavior; | |
public FiskBottomsheetDialog(Activity context, int layout, int theme) { | |
dialog = new Dialog(context, theme); | |
Window window = dialog.getWindow(); | |
if (window != null) { | |
window.setDimAmount(0); | |
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); | |
window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); | |
} | |
contentView = context.getLayoutInflater().inflate(layout, null); | |
//Curved top corners: | |
GradientDrawable curvedBackground = new GradientDrawable(); | |
curvedBackground.setColor(Color.WHITE); | |
float cornerRadius = 8 * ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT); | |
curvedBackground.setCornerRadii(new float[]{cornerRadius, cornerRadius, cornerRadius, cornerRadius, 0, 0, 0, 0}); | |
contentView.setBackground(curvedBackground); | |
//Full screen coordinator to hold the bottomsheet | |
coordinatorLayout = new CoordinatorLayout(context); | |
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); | |
layoutParams.gravity = Gravity.CENTER; | |
coordinatorLayout.setLayoutParams(layoutParams); | |
coordinatorLayout.setBackgroundColor(Color.parseColor("#00000000")); | |
bottomSheetBehavior = new BottomSheetBehavior(); | |
bottomSheetBehavior.setSkipCollapsed(true); | |
bottomSheetBehavior.setHideable(true); | |
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); | |
CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams(CoordinatorLayout.LayoutParams.MATCH_PARENT, CoordinatorLayout.LayoutParams.WRAP_CONTENT); | |
params.setBehavior(bottomSheetBehavior); | |
contentView.setLayoutParams(params); | |
coordinatorLayout.addView(contentView); | |
//Any click on the dimmed coordinator in the background should dismiss the dialog (unless setCanceleable(false); has been called): | |
coordinatorLayout.setOnClickListener(_view -> { | |
if (cancelable) BottomSheetBehavior.from(contentView).setState(BottomSheetBehavior.STATE_HIDDEN); | |
}); | |
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { | |
@Override | |
public void onStateChanged(@NonNull View bottomSheet, int newState) { | |
switch (newState) { | |
case BottomSheetBehavior.STATE_HIDDEN: | |
dialog.dismiss(); | |
if (onDismissListener != null) onDismissListener.onDismiss(dialog); | |
break; | |
} | |
} | |
//slideOffset is float in range 0 to 1 - remapped to 0 to 153 (0x99000000) | |
@Override | |
public void onSlide(@NonNull View bottomSheet, float slideOffset) { | |
int alpha = (int) map(slideOffset, 0f, 1f, 0f, 153f); | |
int overlayColor = Color.argb(alpha, Color.red(Color.BLACK), Color.green(Color.BLACK), Color.blue(Color.BLACK)); | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && window != null) { | |
window.setStatusBarColor(overlayColor); | |
} | |
coordinatorLayout.setBackgroundColor(overlayColor); | |
} | |
}); | |
dialog.setContentView(coordinatorLayout); | |
//Without this the bottom sheet doesn't animate, despite the default state being hidden | |
BottomSheetBehavior.from(contentView).setState(BottomSheetBehavior.STATE_HIDDEN); | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) dialog.create(); | |
} | |
public void show() { | |
dialog.show(); | |
contentView.post(() -> BottomSheetBehavior.from(contentView).setState(BottomSheetBehavior.STATE_EXPANDED)); | |
} | |
public void dismiss() { | |
BottomSheetBehavior.from(contentView).setState(BottomSheetBehavior.STATE_HIDDEN); | |
} | |
public void setOnShowListener(DialogInterface.OnShowListener onShowListener) { | |
dialog.setOnShowListener(onShowListener); | |
} | |
public void setCancelable(boolean cancelable) { | |
this.cancelable = cancelable; | |
dialog.setCancelable(cancelable); | |
} | |
public View getContentView() { | |
return contentView; | |
} | |
public CoordinatorLayout getCoordinatorLayout() { | |
return coordinatorLayout; | |
} | |
public void setOnDismissListener(Dialog.OnDismissListener onDismissListener) { | |
this.onDismissListener = onDismissListener; | |
} | |
private float map(float value, float start1, float stop1, float start2, float stop2) { | |
return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1)); | |
} | |
public Dialog getDialog() { | |
return dialog; | |
} | |
public void setMaxWidth(float dp){ | |
int maxWidth = Math.round(contentView.getContext().getResources().getDisplayMetrics().density * dp); | |
Display display = dialog.getWindow().getWindowManager().getDefaultDisplay(); | |
Point size = new Point(); | |
display.getSize(size); | |
if(size.x > maxWidth){ | |
contentView.getLayoutParams().width = maxWidth; | |
((CoordinatorLayout.LayoutParams)contentView.getLayoutParams()).gravity = Gravity.CENTER_HORIZONTAL; | |
} | |
} | |
public void setMaxWidth(int dimenRes){ | |
float dp = contentView.getContext().getResources().getDimension(dimenRes); | |
setMaxWidth(dp); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
how to expand this bottom sheet?