I'm trying to get a fullscreen CollapsingToolbar
but when I set match_parent
to the height of AppBarLayout
I'm not able to scroll the ImageView
which is inside CollapsingToolbarLayout
. I have to leave some space so that I can touch the "white" of the activity (in AppBarLayout I added android:layout-marginBottom:"16dp" ) and only then, after I touched it, I can scroll the ImageView otherwise I can't.
This happens everytime I run the app and touch the layout for the first time. So I have to touch the white first and then scroll the image.
Could you help me?
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="@+id/drawer">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="16dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginStart="48dp"
app:expandedTitleMarginEnd="64dp">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:fitsSystemWindows="true"
app:layout_collapseMode="parallax"
android:contentDescription="@null"
android:src="@drawable/background" />
<android.support.v7.widget.Toolbar
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_collapseMode="pin"
app:theme="@style/ToolbarTheme"
android:id="@+id/toolbar"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
</FrameLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
<com.myapplication.ScrimInsetsFrameLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="304dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:insetForeground="#4000"
android:clickable="true"
android:background="#ffffff">
...
</com.myapplication.ScrimInsetsFrameLayout>
</android.support.v4.widget.DrawerLayout>
EDIT @PPartisan I've done what you said but here's what I got:
This isn't a nice solution, but it does work on my test device. It kick starts the scrolling process by explicitly assigning a touch listener to the AppBar that triggers a nested scroll.
First, create a custom class that extends NestedScrollView
and add the following method so it look something like this:
public class CustomNestedScrollView extends NestedScrollView {
private int y;
public CustomNestedScrollView(Context context) {
super(context);
}
public CustomNestedScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean dispatchHandlerScroll(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
y = (int) e.getY();
startNestedScroll(2);
break;
case MotionEvent.ACTION_MOVE:
int dY = y - ((int)e.getY());
dispatchNestedPreScroll(0, dY, null, null);
dispatchNestedScroll(0, 0, 0, dY, null);
break;
case MotionEvent.ACTION_UP:
stopNestedScroll();
break;
}
return true;
}
}
Then, inside your Activity
class, assign a TouchListener
to your AppBarLayout
:
appBarLayout.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return customNestedScrollView.dispatchHandlerScroll(event);
}
});
and remove it when the AppBar collapses fully for the first time:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (Math.abs(appBarLayout.getY()) == appBarLayout.getTotalScrollRange()) {
appBarLayout.setOnTouchListener(null);
}
return super.dispatchTouchEvent(ev);
}
Edit
Take the following steps to get it up and running:
Replace the NestedScrollView
in your xml
(android.support.v4.widget.NestedScrollView
) with the CustomNestedScrollView
(which will take the form of com.something.somethingelse.CustomNestedScrollView
, depending on where it is in your project).
Assign it to a variable in your Activity
onCreate()
(i.e. CustomScrollView customScrollView = (CustomScrollView) findViewById(R.id.custom_scroll_view_id);
)
Set up the TouchListener
on your appBarLayout
as you have done in your edit. Now when you call dispatchHandlerScroll()
, it will be on your customNestedScrollView
instance.
dispatchTouchEvent()
is a method you override in your Activity
class, so it should be outside the TouchListener
So, for example:
public class MainActivity extends AppCompatActivity {
private AppBarLayout appBarLayout;
private CustomNestedScrollView customNestedScrollView;
//...
@Override
protected void onCreate(Bundle savedInstanceState) {
//...
customNestedScrollView = (CustomNestedScrollView) findViewById(R.id.scroll);
appBarLayout = (AppBarLayout) findViewById(R.id.app_bar_layout);
appBarLayout.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return customNestedScrollView.dispatchHandlerScroll(event);
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (Math.abs(appBarLayout.getY()) == appBarLayout.getTotalScrollRange()) {
appBarLayout.setOnTouchListener(null);
}
return super.dispatchTouchEvent(ev);
}
}
Hope that's cleared things up.