I have Recyclerview inside the nestedscrollview and I want to scroll the nestedscrollview to the buttom display loading and load more list to recyclerview.
Here is my xml.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="kh.com.iknow.endless.MainActivity">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Filter"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Sort"/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:scrollbars="vertical" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
you can do it in two ways :
1- adding header to recyclerview
2- using setOnScrollChangeListener method of NestedScrolview
I prefer the second way :
NestedScrollView nestedSV = (NestedScrollView) findViewById(R.id.nested_sync_scrollview);
if (nestedSV != null) {
nestedSV.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
#Override
public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
String TAG = "nested_sync";
if (scrollY > oldScrollY) {
Log.i(TAG, "Scroll DOWN");
}
if (scrollY < oldScrollY) {
Log.i(TAG, "Scroll UP");
}
if (scrollY == 0) {
Log.i(TAG, "TOP SCROLL");
}
if (scrollY == (v.getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight())) {
Log.i(TAG, "BOTTOM SCROLL");
if (!isRecyclerViewWaitingtoLaadData) //check for scroll down
{
if (!loadedAllItems) {
showUnSentData();
}
}
}
}
});
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/off_white_bg"
android:orientation="vertical">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="2dp"
android:fitsSystemWindows="true">
<android.support.v4.widget.NestedScrollView
android:id="#+id/nestedScrollViewId"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusableInTouchMode="true"
android:orientation="vertical"
app:layout_scrollFlags="scroll|enterAlways">
<LinearLayout
android:id="#+id/permiumLAyout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/divider"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:focusableInTouchMode="true"
android:gravity="center"
android:orientation="vertical"
android:visibility="visible">
<!-- List view -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/btn_br_color"
android:padding="3dp">
<TextView
android:id="#+id/primiumGameNameText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="fill"
android:layout_marginLeft="15dp"
android:gravity="center"
android:maxLines="4"
android:text="Primium Games"
android:textAppearance="#style/TextAppearance.AppCompat.Body1"
android:textColor="#color/row_text_color"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view_primiumGameList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:isScrollContainer="false"
android:nestedScrollingEnabled="false"
android:paddingBottom="3dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingTop="3dp" />
</LinearLayout>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</FrameLayout>
</LinearLayout>
I Noted one issue putting my RecyclerView inside the NestedScrollView. I realized that scrolling the content of my RecyclerView slacked.Getting issue in scrolling. And one main issue load more data getting issue for load data inside NestedScrollView.
Solution: use load more event like this
mRecAdapter = new RecyclerAdapter(recylerView,
primiumgameDetailsArrayList, getActivity(), cost);
recylerView.setAdapter(mRecAdapter);
//set load more listener for the RecyclerView adapter
mRecAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore () {
**mRecyclerView.setNestedScrollingEnabled(false);**
if (reqCountStatus.equalsIgnoreCase("true")) {
primiumgameDetailsArrayList.add(null);
mRecAdapter.notifyItemInserted(primiumgameDetailsArrayList.size() - 1);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
primiumgameDetailsArrayList.remove(primiumgameDetailsArrayList.size() - 1);
mRecAdapter.notifyItemRemoved(primiumgameDetailsArrayList.size());
int index = primiumgameDetailsArrayList.size();
primiumGameloadData(mRecyclerView, index);
}
}, 5000);
} else {
mRecyclerView.setNestedScrollingEnabled(false);
Toast.makeText(getActivity().getApplicationContext(),
"Loading data completed", Toast.LENGTH_SHORT).show();
}
}
});
Note:I had to disable the scroll functionality of my RecyclerView with this method mRecyclerView.setNestedScrollingEnabled(false); and enable when load more request for data mRecyclerView.setNestedScrollingEnabled(true)
Related
I have a RecyclerView where in each item i can add X child items, when a parent item is added my RecyclerView scrolls to bottom but the issue is that when lot of child items are added to the last element it's not scrolling to last child (obviously as i'm doing scrollToPosition of last RecyclerView item).
So how should i perform the scrolling in the way that it scrolls to even last child not only the parent item?
Here a gif of how it looks like.
XML
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:stackFromEnd="true"
android:paddingBottom="45dp"
tools:listitem="#layout/comanda_list" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fabInvia"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:backgroundTint="#00C853"
app:layout_anchor="#+id/bottomSheet"
app:borderWidth="0dp"
app:layout_anchorGravity="top|center"
app:srcCompat="#drawable/ic_baseline_send"
android:contentDescription="#string/verifica_gp" />
<include layout="#layout/bottom_sheet_pterm" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Code where i add a child item in my Adapter
public void addChild(int position, Varianti variante) {
comandeList.get(position).setVariant(variante);
notifyItemChanged(position);
}
onBindViewHolder where the child items are rendered
#Override
public void onBindViewHolder(#NonNull final ExampleViewHolder holder, final int position) {
final Comanda item = comandeList.get(position);
...
List<Varianti> variants = item.getVarianti();
if (variants != null && variants.size() > 0) {
for (Varianti v : variants) {
View vView = mInflater.inflate(R.layout.varianti_layout, holder.variantsContainer, false);
TextView nameTV = vView.findViewById(R.id.variant_name);
if (v.getState().equals("K") || v.getState().equals("KK")) {
nameTV.setTypeface(null, Typeface.BOLD);
}
if (!item.getState().equals("S")) {
nameTV.setTextColor(Color.parseColor("#FFFFFF"));
}
nameTV.setText(v.getDescrizione());
nameTV.setBackground(v.getDrawable());
holder.variantsContainer.addView(vView);
}
}
...
}
In activity after adding new item / child item
adapterComanda.addVariante(position, variante);
recyclerComanda.scrollToPosition(adapterComanda.getItemCount() - 1);
BottomSheet
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/bottomSheet"
android:background="#FFFFFF"
android:layout_width="match_parent"
android:layout_height="450dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
app:behavior_hideable="false"
android:elevation="5dp"
app:behavior_peekHeight="60dp"
android:orientation="vertical">
... (different LinearLayouts)
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:gravity="bottom"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerViewTasti"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="50dp"
android:paddingTop="3dp"
android:paddingBottom="3dp"
tools:listitem="#layout/tasto_list"
app:spanCount="4"
android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" />
</LinearLayout>
</LinearLayout>
The issue with your code is it is Scrolling to the bottom, but the recycler view is going below the <include layout="#layout/bottom_sheet_pterm" />
Try setting a layout_anchor
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="45dp"
app:layout_anchor="#+id/fabInvia"
app:stackFromEnd="true" />
Or use a constraintlayout which constraints bottom to top of fabInvia.
I'm trying to use a Bottom Sheet with a ListView inside it, but I'm facing two problem, 1st. the ListView doesn't occupy all the space from the Bottom Sheet, the match-parent isn't working, 2nd. scrolling through the list view doesn't really work, if I try to scroll down it only scrolls a little instead of a normal scroll and if I scroll up, the Bottom Sheet closes instead of scrolling the list first.
Gif of the problem
Here's the XML:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.abili.agriexport2.MapsActivity" />
<android.support.v4.widget.NestedScrollView
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="350dp"
android:background="?android:attr/windowBackground"
android:clipToPadding="true"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimary"
android:orientation="horizontal">
<TextView
android:id="#+id/textView11"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="16dp"
android:text="Direções"
android:textColor="#color/colorWhite"
android:textSize="24sp" />
<ImageButton
android:id="#+id/closeBottomSheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="5"
android:background="#null"
app:srcCompat="#drawable/mr_ic_close_dark" />
</LinearLayout>
<ListView
android:id="#+id/listaDirecoes"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
Appreciate any help :)
try to add
android:fillViewport="true"
to your NestedScrollView
For the other problem, I used this way once:
yourLV.setOnScrollListener(new ListView.OnScrollListener() {
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
#Override
public void onScrollStateChanged(AbsListView arg0, int arg1) {
if (listIsAtTop(yourLV)) {
yourLV.setOnTouchListener(null);
} else {
yourLV.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// Disallow the touch request for parent scroll on touch of child view
v.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
}
}
});
And
public static boolean listIsAtTop(ListView listView) {
if(listView.getChildCount() == 0) return true;
return listView.getChildAt(0).getTop() == 0;
}
I have this simple layout:
<RelativeLayout 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.support.design.widget.CoordinatorLayout
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ActionBarThemeOverlay">
<include layout="#layout/include_toolbar_actionbar"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/theme_primary"
android:padding="#dimen/keyline_1">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/bg_search_view"
android:focusable="true"
android:focusableInTouchMode="true">
<com.xxxx.ui.widget.CustomSearchView
android:id="#+id/search_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:withBackButton="true" />
</FrameLayout>
</FrameLayout>
</android.support.design.widget.AppBarLayout>
<RelativeLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"/>
<LinearLayout
android:id="#+id/methods_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="#dimen/keyline_5">
<com.xxx.ui.widget.ButtonSearchBy
android:id="#+id/search_by_categories"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:title="#string/search_by_categories"
app:icon="#drawable/ic_by_categories"
app:iconFillColor="#color/grey"
android:visibility="gone"/>
<com.xxx.ui.widget.ButtonSearchBy
android:id="#+id/search_by_recents"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:title="#string/search_by_recents"
app:icon="#drawable/ic_by_recents"
app:iconFillColor="#color/grey"
android:visibility="gone"/>
</LinearLayout>
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
In my Activity, I added this code to disable user scroll on directly CoordinatorLayout:
if (mAppBarLayout.getLayoutParams() != null) {
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
AppBarLayout.Behavior appBarLayoutBehaviour = new AppBarLayout.Behavior();
appBarLayoutBehaviour.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
#Override
public boolean canDrag(#NonNull AppBarLayout appBarLayout) {
return false;
}
});
layoutParams.setBehavior(appBarLayoutBehaviour);
}
This code works correctly, BUT in the "fragment_container" (FrameLayout), I add a RecyclerView, and if the user scrolls into this list then the Coordinator scrolls too...
I want collapse or expand automatically my CoordinatorLayout, and not to have a link with the RecyclerView scrolling.
I tried this too, but it doesn't work properly:
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (mFragmentContainer.getVisibility() == View.VISIBLE &&
event.getAction() == MotionEvent.ACTION_MOVE) {
Rect fragContainerRect = new Rect();
mFragmentContainer.getHitRect(fragContainerRect);
if (fragContainerRect.contains((int) event.getX(), (int) event.getY())) {
LogUtils.LOGD("XXXX", "move");
mFragmentContainer.dispatchTouchEvent(event);
return true;
}
}
return super.dispatchTouchEvent(event);
}
So how can I do to disable the CoordinatorLayout scrolling when the list scrolls?
Thank you very much guys!
This is what I want to achieve :
I wanted to use AbsoluteLayout but it is deprecated.
So I made a RelativeLayout beneath the blue view in the image above, and then put everything inside a ScrollView, but the hidden view is still 'on' the blue view, and not below it. Also, the screen scrolls, but the hidden part is just cut , and instead I see the my app's default background..
Any ideas?
EDIT :
my current try :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:fillViewport="true"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/imageView" />
<LinearLayout
android:id="#+id/centerHolder"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical" >
.....
.....
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="1000dp"
android:layout_below="#id/main_holder"
android:background="#color/black_color">
</RelativeLayout>
</RelativeLayout>
</ScrollView>
I am taking this from a project of mine which displays a RecyclerView where you can add data if you click on a row - because the click "opens" the bottom sheet.
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/rl_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.fragment.BlockFragment">
<include
android:id="#+id/ll_header"
layout="#layout/layout_header_names" />
<include
android:id="#+id/divider_header"
layout="#layout/layout_divider_horizontal"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="#+id/ll_header" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_block"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/divider_footer"
android:layout_below="#+id/divider_header" />
<include
android:id="#+id/divider_footer"
layout="#layout/layout_divider_horizontal"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#767676"
android:layout_above="#+id/ll_footer" />
<include
android:id="#+id/ll_footer"
layout="#layout/layout_footer_score"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
<!-- Here comes my bottom sheet.
It is wrapped inside a FrameLayout, because an include cannot
have a behaviour. The included layout is every layout you
can imagine - mine is a RelativeLayout with two EditTexts
for example. The layout_behaviour is the second important line. -->
<FrameLayout
android:id="#+id/container_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#e3e3e3"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<include layout="#layout/layout_bottom_sheet"/>
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
For the behaviour itself, you'll need to get the FrameLayout (the View with the app:layout_behavior="android.support.design.widget.BottomSheetBehavior").
private BottomSheetBehavior bottomSheetBehavior;
bottomSheetBehavior = BottomSheetBehavior.from((FrameLayout)findViewById(R.id.container_bottom_sheet);
//for the sheet to "peek":
bottomSheetBehavior.setPeekHeight(200);
//now you can set the states:
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
It is also possible to set a BottomSheetCallback() in which you can get all the state changes and also the slideOffset!
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
switch (newState) {
case BottomSheetBehavior.STATE_DRAGGING:
case BottomSheetBehavior.STATE_EXPANDED:
break;
case BottomSheetBehavior.STATE_COLLAPSED:
default:
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
}
});
I think you should just use LinearLayout to wrap the ImageView and other layouts.
Edited the answer based on comments.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:fillViewport="true"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/centerHolder"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical" >
.....
.....
</LinearLayout>
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/imageView"
android:layout_alignParentTop="true" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="1000dp"
android:layout_below="#+id/centerHolder"
android:background="#color/black_color">
</RelativeLayout>
</RelativeLayout>
</ScrollView>
Just replace your ScrollView with NestedScrollView
Example:
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
I realized you need something like this, just tested it out , just copy two files and see how it works.
import android.animation.ObjectAnimator;
import android.content.Context;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ScrollView;
public class MainActivity extends AppCompatActivity {
LinearLayout movableLL;
boolean mDragLockGained;
float initialTouchPoint;
// int cutoffElevation;
boolean inAnimation;
ScrollView scrollView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scrollView = (ScrollView) findViewById(R.id.scrollView);
movableLL = (LinearLayout) findViewById(R.id.mobileLL);
movableLL.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (inAnimation) return true;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDragLockGained = true;
initialTouchPoint = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
performTranslation(event);
initialTouchPoint = event.getRawY();
break;
case MotionEvent.ACTION_UP:
mDragLockGained = false;
performSettlingAnimation();
break;
}
return true;
}
});
}
private void performTranslation(MotionEvent event) {
float newDelta = event.getRawY() - initialTouchPoint;
float currentY = movableLL.getTranslationY();
if (currentY + newDelta > 0) {
movableLL.setTranslationY(currentY + newDelta);
if (scrollView.getTranslationY() + newDelta < 0){
}
scrollView.setTranslationY(scrollView.getTranslationY() + newDelta);
} else {
movableLL.setTranslationY(currentY);
scrollView.setTranslationY(scrollView.getTranslationY());
}
}
final int SETTLE_ANIMATION_DURATION = 300;
private void performSettlingAnimation() {
ObjectAnimator animLl = ObjectAnimator.ofFloat(movableLL, "translationY",
movableLL.getTranslationY(), convertDpToPixels(this, 150));
inAnimation = true;
animLl.setDuration(SETTLE_ANIMATION_DURATION);
animLl.start();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
inAnimation = false;
}
}, SETTLE_ANIMATION_DURATION);//use animationListener here as a best practice and toggle values in
//on animation start and cancel/finish
ObjectAnimator animSv = ObjectAnimator.ofFloat(scrollView, "translationY", scrollView.getTranslationY()
, 0);
animSv.setDuration(SETTLE_ANIMATION_DURATION);
animSv.start();
}
public static int convertDpToPixels(Context context, int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()
);
}
}
and the xml......
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:gravity="center"
android:text="Hello There" />
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:gravity="center"
android:text="Hello Again" />
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:gravity="center"
android:text="WhatsUp" />
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:gravity="center"
android:text="See ya" />
</LinearLayout>
</ScrollView>
<LinearLayout
android:id="#+id/mobileLL"
android:layout_width="match_parent"
android:layout_height="300dp"
android:translationY="150dp"
android:layout_gravity="bottom"
android:background="#android:color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#99ff0000" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#990000ff" />
</LinearLayout>
Please let me know if I missed something.
For this purposes the best way is to use BottomSheet from Design Support Library from my point of view.
<?xml version="1.0" encoding="utf-8"?><android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="1000dp"
android:background="#android:color/white">
<!-- other layout -->
</RelativeLayout>
</RelativeLayout>
</ScrollView>
<FrameLayout
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:behavior_peekHeight="120dp"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<View
android:layout_width="match_parent"
android:layout_height="240dp"
android:background="#android:color/darker_gray" />
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
It also possible to combine it with your own a CoordinatorLayout Behavior to change scroll position for your scroll view, if needed.
Okay so I have a Tab view going inside of which I have a webview, a listview and a few other pages. I want to be able to do a SwipeRefreshLayout to refresh each item. I have this working on each page. But, when I scroll down in a webview I can't scroll back up. It triggers the refresh and rebuilds it. I'd like to be able to scroll up in my webview.
Layout stuff
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="20px"
android:layout_weight="1"
android:nestedScrollingEnabled="true">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Splash$PlaceholderFragment">
<TextView
android:id="#+id/section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<WebView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/webView"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:overScrollMode="ifContentScrolls"
android:nestedScrollingEnabled="false"/>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/progressBar"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/listView"
android:layout_centerVertical="false"
android:layout_centerHorizontal="true"
android:visibility="visible" />
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
The SwipeRefreshLayout is being used inside the fragment for my tabbed layout.
swipeLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipe_container);
swipeLayout.setColorScheme(android.R.color.holo_blue_bright,
android.R.color.holo_green_light,
android.R.color.holo_orange_light,
android.R.color.holo_red_light);
swipeLayout.setOnRefreshListener( new SwipeRefreshLayout.OnRefreshListener() {
#Override public void onRefresh() {
if(getArguments().getInt(ARG_SECTION_NUMBER) == 4 ) {
stringArrayList.clear();
new updatetheQueue().execute(ctx);
}
else {
swipeLayout.setRefreshing(false);
}
}});
You can use an OnScrollChangedListener to disable SwipeRefreshLayout when the WebView is not scrolled to the top.
// Only enable swipe to refresh if the `WebView` is scrolled to the top.
webView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
if (webView.getScrollY() == 0) {
swipeRefreshLayout.setEnabled(true);
} else {
swipeRefreshLayout.setEnabled(false);
}
}
});
Getting this working was very challenging. However there is a fairly simple modification that can be made to the layout XML to work around this. It means I can't update the webviews on swipe but thats okay.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Splash$PlaceholderFragment">
<TextView
android:id="#+id/section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<WebView
android:id="#+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:overScrollMode="ifContentScrolls" />
<ProgressBar
android:id="#+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Splash$PlaceholderFragment">
<ListView
android:id="#+id/listView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="false"
android:visibility="visible" />
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
you can make a class extend SwipeRefreshLayout and Override canChildScrollUp to sit scro
#Override
public boolean canChildScrollUp() {
// TODO Auto-generated method stub
return true; // if you want it to scroll up
// check if child Get To Top
//return false // if you want it to execute swipe down to refresh listener
}
If you are using the ViewPager and the tabs are Fragments, you can fix your WebViewFragment with this snippet:
private ViewTreeObserver.OnScrollChangedListener mOnScrollChangedListener;
#Override
public void onStart() {
super.onStart();
swipeLayout.getViewTreeObserver().addOnScrollChangedListener(mOnScrollChangedListener =
new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
if (mWebView.getScrollY() == 0)
swipeLayout.setEnabled(true);
else
swipeLayout.setEnabled(false);
}
});
}
#Override
public void onStop() {
swipeLayout.getViewTreeObserver().removeOnScrollChangedListener(mOnScrollChangedListener);
super.onStop();
}
More info in Android - SwipeRefreshLayout with empty textview.
this is how i solve the problem, hope it will help :
mWebView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
if(mWebView.getScrollY() == 0){
mSwipeRefreshLayout.setEnabled(true);
}else{
mSwipeRefreshLayout.setEnabled(false);
}
}
});
In kotlin:
webView.viewTreeObserver.addOnScrollChangedListener {
binding.swipeRefreshLayout.isEnabled = webView.scrollY == 0
}