Skip to content

Instantly share code, notes, and snippets.

@IRMobydick
Created April 3, 2020 11:45
Show Gist options
  • Save IRMobydick/0e3fe4fc4bd90963cbc1d04e5f9b010d to your computer and use it in GitHub Desktop.
Save IRMobydick/0e3fe4fc4bd90963cbc1d04e5f9b010d to your computer and use it in GitHub Desktop.
Custom Android AppBarLayout$ScrollingViewBehavior: Prevent Toolbar from scrolling when RecyclerView doesn't have enough items to scroll.
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Alireza Eskandarpour Shoferi
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<io.github.meness.testapplication.NotTouchableCoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false">
<android.support.design.widget.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|enterAlways"
app:title="@string/app_name"
app:titleTextColor="@android:color/white">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never">
</android.support.v7.widget.RecyclerView>
</io.github.meness.testapplication.NotTouchableCoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Alireza Eskandarpour Shoferi
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Large"/>
</LinearLayout>
/*
* Copyright 2016 Alireza Eskandarpour Shoferi
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import com.mikepenz.fastadapter.adapters.FastItemAdapter;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// init
LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
FastItemAdapter<SampleItem> adapter = new FastItemAdapter<>();
RecyclerView rv = (RecyclerView) findViewById(R.id.rv);
// set behavior to RecyclerView
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) rv.getLayoutParams();
params.setBehavior(new ShouldScrolledBehavior(layoutManager, adapter));
rv.setLayoutParams(params);
rv.setLayoutManager(layoutManager);
rv.setHasFixedSize(true);
rv.setAdapter(adapter);
for (int i = 1; i < 100; i++) {
adapter.add(new SampleItem().setNumber(i));
}
}
}
/*
* Copyright 2016 Alireza Eskandarpour Shoferi
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* touching on CoordinatorLayout has disabled to only be scrolled while RecyclerView is scrolling
*/
public class NotTouchableCoordinatorLayout extends CoordinatorLayout {
public NotTouchableCoordinatorLayout(Context context) {
super(context);
}
public NotTouchableCoordinatorLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NotTouchableCoordinatorLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
}
/*
* Copyright 2016 Alireza Eskandarpour Shoferi
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import com.mikepenz.fastadapter.items.AbstractItem;
import java.util.List;
public class SampleItem extends AbstractItem<SampleItem, SampleItem.ViewHolder> {
public int number;
public SampleItem setNumber(int number) {
this.number = number;
return this;
}
@Override
public int getType() {
return 0;
}
@Override
public int getLayoutRes() {
return R.layout.layout_sample_item;
}
@Override
public void bindView(ViewHolder holder, List payloads) {
super.bindView(holder, payloads);
holder.name.setText("Hello World " + number);
}
protected static class ViewHolder extends RecyclerView.ViewHolder {
protected TextView name;
public ViewHolder(View view) {
super(view);
this.name = (TextView) view.findViewById(R.id.name);
}
}
}
/*
* Copyright 2016 Alireza Eskandarpour Shoferi
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.view.MotionEvent;
import android.view.View;
import com.mikepenz.fastadapter.adapters.FastItemAdapter;
/**
* scroll when adapter's items are not completely visible. in other words,
* toolbar is always visible till adapter's items are enough to be scrolled.
*/
public class ShouldScrolledBehavior extends AppBarLayout.ScrollingViewBehavior {
private LinearLayoutManager mLayoutManager;
private FastItemAdapter<SampleItem> mAdapter;
public ShouldScrolledBehavior(LinearLayoutManager layoutManager, FastItemAdapter<SampleItem> adapter) {
super();
this.mLayoutManager = layoutManager;
this.mAdapter = adapter;
}
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent ev) {
return !shouldScrolled();
}
public boolean shouldScrolled() {
// adapter has more items that not shown yet
if (mLayoutManager.findLastCompletelyVisibleItemPosition() != mAdapter.getAdapterItemCount() - 1) {
return true;
}
// last completely visible item is the last item in adapter but it may be occurred in 2 ways:
// 1) all items are shown
// 2) scrolled to the last item (implemented following)
else if (mLayoutManager.findLastCompletelyVisibleItemPosition() == mAdapter.getAdapterItemCount() - 1 && mLayoutManager.findFirstCompletelyVisibleItemPosition() != 0) {
return true;
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment