How to resize RecyclerView when Material BottomSheet is Expanded? - java

I have a layout where i have a bottom sheet which could be expanded, then from that bottomsheet i can click some items which then will be added to my RecyclerView, the issue is that when the bottomsheet is expanded i'm unable to see the last added items as the recyclerView goes behind the bottomSheet.
So i would do something like the bottomSheet pushes to top the recyclerView (or that the recyclerView is resized)
The issue is that i was trying to do the resize in onSlide but it doesn't work as expected...
Here is my Layout:
<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:layout_marginTop="2dp"
app:layout_anchorGravity="top"
android:layout_marginBottom="60dp"
app:layout_anchor="#+id/bottomSheet"
android:padding="2dp"
android:scrollbars="vertical"
tools:listitem="#layout/recyclerview_pterm" />
<include layout="#layout/bottom_sheet_pterm" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
And my BottomSheetBehavior callback:
bottomSheet.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_EXPANDED) {
mRecyclerViewTOP.scrollToPosition(dummyDataItems.size() - 1);
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
int padding = bottomSheet.getHeight();
ViewGroup.LayoutParams params= mRecyclerViewTOP.getLayoutParams();
params.height = params.height - padding;
mRecyclerViewTOP.setLayoutParams(params);
}
});
So how could i make the recyclerView shows ever the last inserted item even when bottomSheet is expanded?

Related

How to add horizontal scroll on vertical recyclerview?

So i have a recyclerview like this :
as you can see, the screen width is not enough for displaying all the text nicely, so i need to add horizontal scroll so user can scroll horizontally and vertically at the same time, how do i do this?
Use HorizontalScrollView with LinearLayout as child. Set it's Orientation to horizontal and add your dynamic views to it.
<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent">
<LinearLayout
android:id="#+id/ll_main"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="match_parent">
// Add your dynamic views to this layout.
</LinearLayout>
</HorizontalScrollView>
You can use this in your row layout :
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
//Your layout item here
</HorizontalScrollView>
You can add android:scrollHorizontally="true" in your TextView
If there are more than one view in your list item, you can use HorizontalScrollView
Put vertical RecyclerView inside HorizontalScrollView like below.
<HorizontalScrollView
android:fillViewport="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/tasks_recycler_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"/>
</HorizontalScrollView>
Also the root element of the item view for the RecyclerView has to have width wrap_content not match_parent, by setting it's width to wrap_content it allows it to expand the width of its parent which in this case would be the RecyclerView.
Now in the item view either give wrap_content or fixed widths to the inner views which in your case are the views to display "No", "Wonum", "Item num", "Quantity" and "UOM". By giving inner views fixed or wrap_content option they will expand automatically or according to the given width hence expanding their parent.
Try this
val linearLayoutManager = LinearLayoutManager(this)
linearLayoutManager.orientation = LinearLayoutManager.HORIZONTAL
selected_recycler_view.layoutManager = linearLayoutManager
adapter = TAdapter(this, existing.selectedArrayList)
Use this layout manager to allow horizontal scrolling of long items in a vertical LinearLayoutManager.
import android.content.Context;
import android.view.View;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class FullScrollLayoutManager extends LinearLayoutManager {
private int offset;
private int maxOffset;
public FullScrollLayoutManager(Context context) {
super(context);
}
#Override
public void onLayoutCompleted(RecyclerView.State state) {
super.onLayoutCompleted(state);
int n = getChildCount();
offset = 0;
maxOffset = 0;
int ownWidth = getWidth();
for(int i=0; i<n; ++i) {
View view = getChildAt(i);
int x = view.getRight();
if(x>ownWidth) maxOffset = Math.max(maxOffset,x-ownWidth);
}
}
#Override
public boolean canScrollHorizontally() {
return true;
}
#Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
if(dx<0) {
if(-dx>offset) dx = -offset;
}
else
if(dx>0) {
if(dx+offset>maxOffset) dx = maxOffset-offset;
}
offsetChildrenHorizontal(-dx);
offset += dx;
return dx;
}
}

How to make toolbar visible again which is previous hidden using layout_scrollFlags, when swipe to different viewpager page [duplicate]

This question already has answers here:
Show toolbar when view pager is swiped. [CoordinatorLayout]
(2 answers)
Closed 5 years ago.
Currently, I have the following page with ViewPager
When the page in INFO tab is scrolled, toolbar will be hidden. This behavior is implemented via CoordinatorLayout, AppBarLayout and app:layout_scrollFlags
<?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: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="wrap_content"
app:elevation="0dp"
android:elevation="0dp"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" >
<android.support.v7.widget.Toolbar
app:layout_scrollFlags="scroll|enterAlways|snap"
android:id="#+id/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="#android:color/transparent"
app:elevation="0dp"
android:elevation="0dp"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="?attr/detailedStockTabIndicatorColor" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
So, this is how it looks like after scrolling.
After Scroll, Toolbar is hidden
Since this is a ViewPager, if I swipe to FINANCIAL tab, it will look like the following.
Followed by Swipe
Since, the page in FINANCIAL tab is not scroll-able, we hope not to hide the Toolbar.
I was wondering, how to make toolbar visible again which is previous hidden using layout_scrollFlags, when swipe to different ViewPager page?
you can do it like this :
final AppBarLayout appBarLayout = view.findViewById(R.id.app_bar_layout);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if (position == 1)
appBarLayout.setExpanded(true, true);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
so when viewPager is in unscrollable page it expands and toolbar appears
#Marzieh Heidari answer is the correct answer for this question, but I share my different approach that I use in my project to solve this problem.
In the fragment which have short content, I still keep NestedScrollView at root. Then I still able to scroll up/down to collapse and expand toolbar
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:isScrollContainer="false"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This fragment have short content"
android:textSize="100sp"
/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
Hope it help
Maybe the application life cycle events can help you here, by catching the load of the new screen and set the toolbar at that point programmaticly to show?
You need to expand toolbar in when user swipe to second tab and make toolbar unscrollable
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if(position == 1) {
appbar.setExpanded(true, true);
AppBarLayout.LayoutParams params =
(AppBarLayout.LayoutParams) toolbar.getLayoutParams();
params.setScrollFlags(0); // clear flags
toolbar.setLayoutParams(params);
} else {
AppBarLayout.LayoutParams params =
(AppBarLayout.LayoutParams) toolbar.getLayoutParams();
params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL
| AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
toolbar.setLayoutParams(params);
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
You asked duplicate question. your question's answer available here
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
expandToolbar();
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
public void expandToolbar(){
AppBarLayout appBarLayout = (AppBarLayout)findViewById(R.id.app_bar_layout);
appBarLayout.setExpanded(true, true);
}

Android: Click outside of a listview in a listfragment

I have a listview which occupies all the space of the layout IN THEORY, but actually it occupies only half of the layout because it has got only 5 elements and it doesn't cover all the screen. I'd like to know when I touch OUTSIDE of the listview. I tried to create a clicklistener method for the layout of the listfragment which contains the list, but it is never used because IN THEORY the listview occupies all the layout, so the click isn't found. It is the same for the layout of the activity more or less. In that case the click is found only on the edges, so I can't find a method to solve my problem.
Here is the fragment layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#android:id/list" />
Here is the activity layout:
<RelativeLayout
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"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="com.example.utente.actionbar.MainActivity">
<Button
android:text="MULTI"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="26dp"
android:id="#+id/button" />
<Button
android:text="SINGOLO"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/button"
android:layout_alignLeft="#+id/button"
android:layout_alignStart="#+id/button"
android:layout_marginBottom="25dp"
android:id="#+id/button2" />
IN THEORY the listview occupies all the layout
Not a theory, that is exactly what happens; by using android:layout_height="match_parent" the View will always take the full screen height.
listView.setOnClickListener would work if you want to see if you clicked anywhere in the ListView, but you typically would instead want listView.setOnItemClickListener to see if you have clicked on any single item, and not the entire list.
Refer: difference between onClickListener and onItemClickListener
If you really want to shrink the ListView, then android:layout_height="wrap_content" is an option, but I'm not sure that works without content actually being loaded into that View since the content wrapping is applied at inflation-time, which since it has no adapter set, can't be done.
If you are needing to detect a listener literally "outside the ListView", then you need to set some type of click / touch listener on the rootView of that Fragment.
public View onCreateView(...) {
rootView = inflater.inflate(...);
listView = ...;
listView.setOnTouchListner(...
#Override
public boolean onTouch(View v, MotionEvent event) {
return false; // Says that click was not handled here.
}
});
rootView.setOnTouchListner(...
// TODO: Check if click landed outside the ListView
#Override
public boolean onTouch(View v, MotionEvent event) {
if (v.getId() != android.R.id.listView) { // Not the list
if (event.getAction() == MotionEvent.ACTION_UP) {
// Up action more reliable than "down"
return true;
}
}
}
);
return rootView;
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content" <!-- Or specific height -->
android:id="#android:id/list" />
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/clickView" />
</LinearLayout>
In Fragmet
public View onCreateView(...) {
rootView = inflater.inflate(...);
View clickView = rootView.findViewById(...);
clickView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Do something here
}
});
return rootView;
}
I guess this solves your problem.

Adding progressbar at the end of recyclerview

In my app, I send a volley request which fetches list items one-by-one, not all at once. I want to implement a progressbar at the end of the recyclerview when the data is being fetched. The class 'updateAdapter' updates the adapter and I was thinking of making the progress bar visible in the recyclerview scroll listener. But I have no idea how to do this in my code.
updateAdapter.java
//THIS CLASS UPDATES THE RECYCLER VIEW
public class updateAdapter{
private FetchWpApi fetch;
private int totalItemCount;
private int prevLastvisible=0;
private int fpage=1;
private Context context;
private RecyclerView recyclerView;
private ArrayList<sItem> list= new ArrayList<>();
private LinearLayoutManager manager;
private ProgressBar progressBar;
//CONSTRUCTOR FOR updateAdapter
public updateAdapter(RecyclerView recyclerView, final Context context, String url, LinearLayoutManager manager){
this.context=context;
this.recyclerView=recyclerView;
fetch=new FetchWpApi(url,context);
this.manager=manager;
}
public void fetchAndPut()
{
if(recyclerView.getAdapter()==null) {
fetch.fetchApiData(fpage, new FetchWpApi.Callback() {
#Override
public void onSuccess(sItem sitem) {
list.add(sitem);
if (list.size() == 1 || recyclerView.getAdapter() == null) {
ItemAdapter adapter = new ItemAdapter(context, list);
recyclerView.setAdapter(adapter);
} else if (list.size() > 1 && recyclerView.getAdapter() != null) {
recyclerView.getAdapter().notifyDataSetChanged();
recyclerView.getAdapter().notifyItemRangeChanged(0, recyclerView.getAdapter().getItemCount());
}
}
#Override
public void onFail(String msg) {
Toast.makeText(context, "FAILED PRIMARY LOAD", Toast.LENGTH_LONG).show();
}
});
}
recyclerView.addOnItemTouchListener(
//Not important
);
//SCROLL LISTENER ATTACHED TO THE RECYCLER VIEW
//SHOW PROGRESS BAR HERE?
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
{
#Override
public void onScrolled(final RecyclerView recyclerView, int dx, int dy)
{
if(dy > 0) //check for scroll down
{
totalItemCount = manager.getItemCount();
int lastVisibleItemPosition = ((LinearLayoutManager) manager).findLastVisibleItemPosition();
if( (lastVisibleItemPosition+1)==totalItemCount && totalItemCount%10==0 && lastVisibleItemPosition>prevLastvisible)
{
//SET VISIBILITY OF THE PROGRESS BAR IN THE LAST CARD ITEM TO VISIBLE ??
fpage++;
//loading = false;
Log.v("...", "Last Item !");
//Do pagination.. i.e. fetch new data
prevLastvisible=lastVisibleItemPosition;
fetch.fetchApiData(fpage,new FetchWpApi.Callback(){
#Override
public void onSuccess(sItem sitem){
list.add(sitem);
recyclerView.getAdapter().notifyDataSetChanged();
recyclerView.getAdapter().notifyItemRangeChanged(0, recyclerView.getAdapter().getItemCount());
}
#Override
public void onFail(String msg){
Toast.makeText(context,"FAILED ONLOAD",Toast.LENGTH_LONG).show();
}
});
}
}
}
});
}
}
The progressbar which I want to display is in this cardview:
finalcard.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/cvItem"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<!--<LinearLayout-->
<!--android:id="#+id/linearlayout"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_margin="10dp"-->
<!-->-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="#+id/tvTitle"
android:textColor="#000"
android:text="Sample text Sampletext sample text sample text sample text"
android:layout_alignParentStart="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toStartOf="#+id/ivMainImage"
android:layout_marginTop="15dp"
android:paddingStart="16dp"
android:paddingEnd="2dp"
android:maxLines="4"
android:textSize="20sp"
android:layout_gravity="start"
/>
<TextView
android:id="#+id/dateText"
android:text="DATE"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="0dp"
android:layout_gravity="start"
android:layout_below="#id/tvTitle"
android:ellipsize="marquee"/>
<ImageView
android:id="#+id/ivMainImage"
android:layout_width="140dp"
android:layout_height="130dp"
android:layout_gravity="end"
android:layout_alignParentEnd="true"
android:layout_margin="15dp"
android:src="#android:drawable/btn_star"
android:scaleType="centerCrop"
/>
<View
android:id="#+id/view"
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="#0C000000"
android:layout_below="#id/ivMainImage"
/>
<ProgressBar
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/progressBar2"
android:layout_below="#id/view"
android:visibility="gone"
/>
</RelativeLayout>
Fix your progress bar below your recycler view instead of card view.
Set visible progress bar when call web service, and set visibility Gone after complete service call
//Progress bar setVisibility - Visible
progressbar.setVisibility(View.VISIBLE);
fetch.fetchApiData(fpage, new FetchWpApi.Callback() {
#Override
public void onSuccess(sItem sitem) {
progressbar.setVisibility(View.GONE);
list.add(sitem);
recyclerView.getAdapter().notifyDataSetChanged();
recyclerView.getAdapter().notifyItemRangeChanged(0, recyclerView.getAdapter().getItemCount());
}
#Override
public void onFail(String msg) {
progressbar.setVisibility(View.GONE);
Toast.makeText(context, "FAILED ONLOAD", Toast.LENGTH_LONG).show();
}
});
I think you can follow this link to add header or footer Recyclerview offically. And you add footer as progressbar to load more data, and remove footer when you finish loading data.
There are 2 ways:
1. Put the progress bar in the bottom of the screen and when you are bottom of the RecyclerView by int last = layoutManager.findLastVisibleItemPosition(); it just display and when you get the response then hide it;
2. In your adapter:
add a dummy row to the last position of your list.
check in adapter when the position is last then show the progress bar:
if(position == list.size - 1) {
// create a layout which only have progress bar
View row = LayoutInflater.from(viewGroup.getContext()).inflate(
R.layout.progressbar, viewGroup, false);
} else {
View row = LayoutInflater.from(viewGroup.getContext()).inflate(
R.layout.layout_list, viewGroup, false);
}

TabWidget wrapped in HorizontalScrollView doesn't scroll with ViewPager

I'm having to use TabHost in place of ActionBarTabs and to make them scroll-able I've wrapped my TabWidget in a HorizontalScrollView, but the HorizontalScrollView doesn't scroll itself in accordance with ViewPager. I've tried using scrollTo and fullScroll in a couple of different ways, but it doesn't change anything. What do I need to do to get this working correctly?
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<HorizontalScrollView
android:id="#id/horizontalScrollView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fillViewport="true"
android:scrollbars="#null" >
<TabWidget
android:id="#android:id/tabs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" />
</HorizontalScrollView>
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0" />
<android.support.v4.view.ViewPager
android:id="#id/viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
#Override
public void onTabChanged(String tabId) {
int position = mTabHost.getCurrentTab();
mViewPager.setCurrentItem(position);
mHorizontalScrollView.scrollTo(position, 0);
}
#Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
mHorizontalScrollView.scrollTo(position, 0);
}
The horizontal scroll view will change when you call .refreshDrawableState() after calling the .scrollTo(x,y) method.
Another thing to watch out for is that .scrollTo(x,y) scrolls such that x is positioned on the left side of the screen. You may need to do some math with the coordinates of your tabs and the width of the horizontal scroll view to position things correctly. You can't call .scrollTo(position,0) and have it work the way you'd like (unless your tabs are 1 pixel wide).
ViewPager has the brains for the scrolling behavior.
I would remove the HorizontalScrollView from your layout. The rest looks fine.
I would then examine this Google provided code example, which I based a ViewPager interface like you want to accomplish on: http://developer.android.com/resources/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsPager.html
You'll notice that the corresponding methods that you declared above don't have anything to do with scrolling, other than to set which page to scroll to. ViewPager handles the smooth scrolling internally.
#Override
public void onTabChanged(String tabId) {
int position = mTabHost.getCurrentTab();
mViewPager.setCurrentItem(position);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}

Categories

Resources