Reputation: 554
I have list of groceries in the scaffold and when one of the items are selected, I have to open a modal sheet containing a webView. However, whatever I do, I can not prevent modal sheet to consume all the gestures itself.
What I meant is, I can not scroll inside the webview in the modal sheet even though I disable the gestures of the modal sheet. Any possible way to implement this?
I have already tried nested scroll connections but couldn't be able to proceed as I am still trying to understand the concept. Any help is appreciated.
Upvotes: 1
Views: 3957
Reputation: 2884
This solution work on me
Custom webView:
class ObservableWebView : WebView {
var onScrollChangedCallback: OnScrollChangeListener? = null
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle)
override fun onScrollChanged(currentHorizontalScroll: Int, currentVerticalScroll: Int, oldHorizontalScroll: Int, oldcurrentVerticalScroll: Int) {
super.onScrollChanged(currentHorizontalScroll, currentVerticalScroll, oldHorizontalScroll, oldcurrentVerticalScroll)
onScrollChangedCallback?.onScrollChanged(
currentHorizontalScroll,
currentVerticalScroll,
oldHorizontalScroll,
oldcurrentVerticalScroll
)
}
interface OnScrollChangeListener {
fun onScrollChanged(
currentHorizontalScroll: Int,
currentVerticalScroll: Int,
oldHorizontalScroll: Int,
oldcurrentVerticalScroll: Int
)
}
}
Bottomsheet:
class BottomSheetWebView(context: Context) : FrameLayout(context) {
private val mBottomSheetDialog: BottomSheetDialog = BottomSheetDialog(context)
private var mCurrentWebViewScrollY = 0
init {
inflateLayout(context)
setupBottomSheetBehaviour()
setupWebView()
}
private fun inflateLayout(context: Context) {
inflate(context, R.layout.bottom_sheet_webview, this)
mBottomSheetDialog.setContentView(this)
mBottomSheetDialog.window?.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
?.setBackgroundResource(android.R.color.transparent);
}
private fun setupBottomSheetBehaviour() {
(parent as? View)?.let { view ->
BottomSheetBehavior.from(view).let { behaviour ->
behaviour.addBottomSheetCallback(object :
BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == BottomSheetBehavior.STATE_DRAGGING && mCurrentWebViewScrollY > 0) {
// this is where we check if webview can scroll up or not and based on that we let BottomSheet close on scroll down
behaviour.setState(BottomSheetBehavior.STATE_EXPANDED);
} else if (newState == BottomSheetBehavior.STATE_HIDDEN) {
close()
}
}
})
}
}
}
private fun setupWebView() {
webView.onScrollChangedCallback = object : ObservableWebView.OnScrollChangeListener {
override fun onScrollChanged(currentHorizontalScroll: Int, currentVerticalScroll: Int,
oldHorizontalScroll: Int, oldcurrentVerticalScroll: Int) {
mCurrentWebViewScrollY = currentVerticalScroll
}
}
}
fun showWithUrl(url: String) {
webView.loadUrl(url)
mBottomSheetDialog.show()
}
fun close() {
mBottomSheetDialog.dismiss()
}
}
You can find detailed explanation in here: https://medium.com/@nishantpardamwar/using-webview-with-bottomsheetdialog-f38e45cc95a5
Upvotes: 1
Reputation: 554
I finally did it. First I have copied the solution for nested scroll in webView in accompanist page. Even-though the solution did not merged, it has a crucial point to be addded.
I have copied the solution of bentrengrove to my code below the link https://github.com/google/accompanist/issues/1260 with fix https://github.com/google/accompanist/pull/1270 and after that modified the base WebView code such as:
var webView by remember { mutableStateOf<WebView?>(null) }
val scrollState = rememberScrollState() --> ADDED THIS LINE
.
.
.
AndroidView(
factory = { context ->
val web = WebView(context).apply {
onCreated(this)
layoutParams = LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
)
webChromeClient = chromeClient
webViewClient = client
webView = this
}
// In order to dispatch nested scrolling correctly, WebView needs to
// be wrapped in a NestedScrollView. This is important for things like
// SwipeToRefresh and TopAppBar behaviours.
NestedScrollView(context).apply {
addView(web)
}
},
modifier = modifier
.clipToBounds()
.verticalScroll(scrollState) --> ADDED THIS LINE
And now, the scroll in webView both collapses the topBar and scrolls inside of the modal sheet. I can improve the answer if anyone needs.
EDIT: I also forgot to mention that I have changed BottomSheetScaffold to BackdropScaffold.
Upvotes: 2
Reputation: 1238
you can try to create the bottom sheet as bottomsheetdialogfragment here is the working example ,you can set the state for the bottom sheet as collpsed, expended, half expended according to your requirement.
public class WebViewDialog extends BottomSheetDialogFragment implements View.OnClickListener {
public UserSessions mUserSessions;
BottomSheetBehavior bottomSheetBehavior;
WebviewLayoutBinding binding;
String title;
String url;
public WebViewDialog(String url, String title) {
this.title = title;
this.url = url;
}
public WebViewDialog() {
}
BottomSheetDialog bottomSheet;
View mView = null;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
bottomSheet = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);
View view = View.inflate(getActivity(), R.layout.webview_layout, null);
mView = view;
binding = DataBindingUtil.bind(view);
bottomSheet.setContentView(view);
bottomSheet.setCancelable(false);
bottomSheet.setCanceledOnTouchOutside(false);
bottomSheetBehavior = BottomSheetBehavior.from((View) (view.getParent()));
bottomSheetBehavior.setPeekHeight(BottomSheetBehavior.PEEK_HEIGHT_AUTO);
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View view, int i) {
if (BottomSheetBehavior.STATE_EXPANDED == i) {
}
if (BottomSheetBehavior.STATE_COLLAPSED == i) {
}
if (BottomSheetBehavior.STATE_HIDDEN == i) {
dismiss();
}
}
@Override
public void onSlide(@NonNull View view, float v) {
}
});
mUserSessions = new UserSessions(getActivity());
binding.imgCLose.setOnClickListener(this);
if (url != null && !url.isEmpty()) {
BBProgress.showProgressDialog(getActivity());
binding.mWebView.setWebViewClient(new MyBrowserClient());
binding.mWebView.getSettings().setJavaScriptEnabled(true);
binding.mWebView.loadUrl(url);
}
return bottomSheet;
}
@Override
public void onDismiss(@NonNull DialogInterface dialog) {
super.onDismiss(dialog);
}
@Override
public void onStart() {
super.onStart();
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
int mStep = 0;
public void onBackClick() {
dismiss();
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (v.getId() == R.id.imgCLose) {
onBackClick();
}
}
public boolean lg;
public class MyBrowserClient extends WebViewClient {
public MyBrowserClient() {
}
public boolean shouldOverrideUrlLoading(WebView view, String url) {
NetworkInfo nf = ((ConnectivityManager) getActivity().getSystemService(CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
if (nf == null || !nf.isConnected()) {
CommonMethods.errorToast(getActivity(), getActivity().getString(R.string.error_internet));
return true;
} else if (url.startsWith("http:") || url.startsWith("https:")) {
view.getSettings().setBuiltInZoomControls(false);
view.loadUrl(url);
return true;
} else {
view.getSettings().setBuiltInZoomControls(false);
view.loadData(url, "text/html", "UTF-8");
return true;
}
}
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
if (!lg) {
boolean unused = lg = true;
return;
}
}
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
BBProgress.hideProgressDialog(getActivity());
}
}
}
And thew xml file for the layout is webview_layout.xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/app_bg"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorAccent">
<RelativeLayout
android:id="@+id/rlTopHeader"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:background="@color/white"
android:padding="@dimen/_10dp">
<ImageView
android:id="@+id/imgCLose"
android:layout_width="@dimen/_44dp"
android:layout_height="@dimen/_44dp"
android:layout_centerVertical="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/_5dp"
android:src="@drawable/ic_back"
app:tint="@color/black" />
<TextView
android:id="@+id/txtTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="@dimen/_10dp"
android:layout_toEndOf="@+id/imgCLose"
android:text="@string/app_name_inside"
android:textColor="@color/black"
android:textSize="@dimen/_18dp" />
</RelativeLayout>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/appBarLayout"
android:background="@color/white"
android:minHeight="@dimen/_250dp"
android:orientation="vertical">
<WebView
android:id="@+id/mWebView"
android:nestedScrollingEnabled="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"></WebView>
</LinearLayout>
</RelativeLayout>
I hope this example will help and solve your problem as per I am using the same and working fine for me.
Upvotes: 1