How to remove spacing between rows in RecyclerView using GridLayoutManager - android

I am trying to have a full screen grid with a RecyclerView with a GridLayoutManager but for some reason a horizontal space is added between the rows and at the top and bottom of my RecyclerView. I can't get rid of it. I searched for solutions and tried an ItemDecorator by setting the dimensions to 0 explicitly but that didn't work. Nothing else worked.
The image.
The code for my ItemDecorator is pretty standard, included.
private class RecyclerViewItemDecorator extends RecyclerView.ItemDecoration {
private int spaceInPixels;
public RecyclerViewItemDecorator(int spaceInPixels) {
this.spaceInPixels = spaceInPixels;
}
#Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
outRect.left = spaceInPixels;
outRect.right = spaceInPixels;
outRect.bottom = spaceInPixels;
if (parent.getChildLayoutPosition(view) == 0) {
outRect.top = spaceInPixels;
} else {
outRect.top = 0;
}
}
}
These are the layout files I use.
/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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="com.example.korah.moviesapp.MainActivity">
<fragment
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/main_fragment"
android:name="com.example.korah.moviesapp.MainActivityFragment"
tools:layout="#layout/activity_main_fragment"
>
</fragment>
</RelativeLayout>
/layout/activity_main_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/movies_recycler"
xmlns:android="http://schemas.android.com/apk/res/android">
</android.support.v7.widget.RecyclerView>
/layout/activity_movies_grid.xml
<?xml version="1.0" encoding="utf-8"?>
<ImageView
android:id="#+id/imageView"
android:src="#drawable/interst"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android" />

Should be because of the scaling of Image rather than anything else. So try setting scaleType of ImageView as fitXY.
<ImageView
android:id="#+id/imageView"
android:src="#drawable/interst"
android:layout_width="wrap_content"
android:scaleType="fitXY"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android" />

Related

android recyclerView horizontal and vertical spacing

Hi all I am very new to android and I am having a problem with recyclerview. I am trying to add space between image views in a recyclerview but I am not successful.
What I want
What is happening
Below are my implementations
ItemOffsetDecoration.java
public class ItemOffsetDecoration extends RecyclerView.ItemDecoration {
private int itemOffset;
public ItemOffsetDecoration(int itemOffset) {
itemOffset = itemOffset;
}
public ItemOffsetDecoration(#NonNull Context context, #DimenRes int itemOffsetId) {
this(context.getResources().getDimensionPixelSize(itemOffsetId));
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(itemOffset, itemOffset, itemOffset, itemOffset);
}
}
shopping.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
android:background="#drawable/shopping_bg"
tools:context=".activities.HomepageActivity$PlaceholderFragment">
<android.support.v7.widget.RecyclerView
android:id="#+id/shoppingRV"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="#dimen/grid_horizontal_spacing"/>
</RelativeLayout>
Shopping.java
public class Shopping extends Fragment implements InstaPukkeiRecyclerViewAdapter.ItemClickListener {
InstaPukkeiRecyclerViewAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.tab_shopping, container, false);
processRV(rootView);
return rootView;
}
private void processRV(View layout) {
RecyclerView recyclerView = (RecyclerView) layout.findViewById(R.id.shoppingRV);
int noOfColumns = 3;
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), noOfColumns));
adapter = new InstaPukkeiRecyclerViewAdapter(getContext(), LogoIds.SHOPPING_SITE_LOGOS);
adapter.setClickListener(this);
recyclerView.setAdapter(adapter);
recyclerView.addItemDecoration(new ItemOffsetDecoration(getContext(), R.dimen.grid_horizontal_spacing));
}
}
Please help me here. Thanks in advance.
EDIT
item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/logoImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:adjustViewBounds="true" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:marginLeft="18dp"
android:marginRight="18dp"
android:id="#+id/logoImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:adjustViewBounds="true" />
</LinearLayout>
Change your item layout with this one in your item's XML. You make the parent(LinearLayout) height match parent that's why you are getting vertical full screen space
Use wrap_content in RecyclerView and also in row layout.And also add margins
<android.support.v7.widget.RecyclerView
android:id="#+id/shoppingRV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:padding="#dimen/grid_horizontal_spacing"/>
hmmm you can add margin to your image view or use dimen to set height and width something like this
android:layout_width="#dimen/dp_130"
android:layout_height="#dimen/dp_120"
or
<ImageView
android:id="#+id/logoImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:layout_margin="#dimen/dp_15"
android:adjustViewBounds="true" />
Inside your Recycleview set layout height to wrap_content

Horizontal RecyclerView with items that have dynamic height

So I need a horizontal RecyclerView. However, the items in them have dynamic heights based on what's returned from the backend.
The RecyclerView and its items have the height of "wrap_content"
The problem is if the first visible items in the RecyclerView are small, then when the user scrolls to the larger items, they appear cut off.
Ideally, we want the RecyclerView to be large enough to hold the largest item in the group (but only the largest existing item... not the hypothetically largest item). The RecyclerView dynamically changing its height is also acceptable.
I wrote an example app to illustrate the problem. In this app, we have a horizontal list. The first 33 items should show 1 line of text, while the next should show 3 lines of text, and the last 34 should show 2 lines. However, they all show 1 line, because the height of the RecyclerView doesn't change.
I've tried calling requestLayout() on the RecyclerView (and on the TextView) from onBindViewHolder(), but it doesn't seem to do anything.
MainActivity:
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdapter = createAdapter();
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
mRecyclerView.setAdapter(mAdapter);
}
private RecyclerView.Adapter<ViewHolder> createAdapter() {
RecyclerView.Adapter adapter = new RecyclerView.Adapter<ViewHolder>() {
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (position < 33) {
holder.mText.setText("1 line");
} else if (position > 66) {
holder.mText.setText("2 lines\n2 lines");
} else {
holder.mText.setText("3 lines\n3 lines\n3 lines");
}
}
#Override
public int getItemCount() {
return 100;
}
};
return adapter;
}
private static class ViewHolder extends RecyclerView.ViewHolder {
TextView mText;
public ViewHolder(View itemView) {
super(itemView);
mText = (TextView) itemView.findViewById(R.id.text);
}
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#888888">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hi"
android:textSize="30sp" />
</LinearLayout>
Change your recyclerView height & width from wrap_content to match_parent or you can also give fixed height to your recyclerView like android:layout_height="150dp"
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#888888" />
</RelativeLayout>
or You can try
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="#888888" />
</RelativeLayout>
Change your item.xml layout content with the below code.
It will solve your issue.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="160dp"
android:layout_height="match_parent"
android:background="#888888">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hi"
android:textSize="30sp" />
</LinearLayout>
You can solve this issue using the FlexboxLayoutManager Google library by defining the FlexDirection to FlexDirection.ROW and FlexWrap to FlexWrap.NOWRAP and also in your BaseViewHolder constructor set for each item the FlexShrink to 0.0f to be able to scroll horizontally. More details of how to achieve this can be found here: Horizontal RecyclerView with dynamic item’s Height
MainActivity:
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdapter = createAdapter();
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
mRecyclerView.setAdapter(mAdapter);
}
private RecyclerView.Adapter<ViewHolder> createAdapter() {
RecyclerView.Adapter adapter = new RecyclerView.Adapter<ViewHolder>() {
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (position < 33) {
holder.mText.setText("1 line");
} else if (position > 66) {
holder.mText.setText("2 lines\n2 lines");
} else {
holder.mText.setText("3 lines\n3 lines\n3 lines");
}
}
#Override
public int getItemCount() {
return 100;
}
};
return adapter;
}
private static class ViewHolder extends RecyclerView.ViewHolder {
TextView mText;
public ViewHolder(View itemView) {
super(itemView);
mText = (TextView) itemView.findViewById(R.id.text);
}
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#888888">
<TextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hi"
android:textSize="30sp" />
</LinearLayout>
To make RecyclerView Horizontal you need to use android:layout_centerHorizontal="true". Also, everything more are the same as vertical.
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/RecyclerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="#id/toolbar"/>
Try to add your textView android:singleLine="false" it changes when there are multiple lines
Just call itemAdapter.notifyDataSetChanged();

RecyclerView in SwipeRefreshLayout not "wrap_content"

I have a RecyclerView as the only child of SwipeRefreshLayout, I want the RecyclerView wrap_content. When I set both of them "wrap_content", it doesn't work. The RecyclerView with fewer items also match_parent. When i delete SwipeRefreshLayout, the RecyclerView will wrap_content. Can anyone help me? My English is poor, Maybe you cann't understand. Anyone can help me? Thank you very much.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container_v"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#00ffff">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff00ff">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
Finally, I work out it. From this Answer
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container_v"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#00ffff">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff00ff"/>
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
The key is to use Layout wrap RecyclerView. Beacause of SwipeRefreshLayout use MeasureSpec.EXACTLY mode measure mTarget size when onMeasure():
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mTarget == null) {
ensureTarget();
}
if (mTarget == null) {
return;
}
mTarget.measure(MeasureSpec.makeMeasureSpec(
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));
......
}
And mTarget is the first child view of SwipeRefreshLayout. So this will cause the mTarget always match parent.
private void ensureTarget() {
// Don't bother getting the parent height if the parent hasn't been laid
// out yet.
if (mTarget == null) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (!child.equals(mCircleView)) {
mTarget = child;
break;
}
}
}
}
FrameLayout is used because it is more lightweight.
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingBottom="10dp"
tools:itemCount="2"
tools:listitem="#layout/item_msg_detail_text_style" />
</FrameLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

Scrollable CardView with RecyclerView inside

I would like to implement a screen where I have a Card view containing a RecyclerView.
The CardView should of the same height of the content of the recycler view, this means that if the RecyclerView has few item, I should see the bottom corners and the bottom shadow of the card but if the RecyclerView has many items, the Card view should "scroll" with the RecyclerView to have the bottom corners and shadow of the cardview at the bottom of the RecylerView.
Here what it should look like when the RecyclerView is at top :
When the user begins to scroll, the top corners disappear with the RecyclerView scrolling :
And finally, when the user reaches the bottom of the RecyclerView, the bottom corners and the shadow of the CardView appears :
From now, I managed to have a working implementation by putting the RecyclerView inside the CardView and the CardView inside a NestedScrollView but this breaks the fling gesture...
<android.support.design.widget.CoordinatorLayout
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:clipChildren="false"
android:id="#+id/containerLayout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
tools:ignore="MissingPrefix">
<android.support.v4.widget.NestedScrollView
android:clipToPadding="false"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:paddingBottom="16dp"
android:paddingLeft="85dp"
android:paddingRight="85dp"
android:paddingTop="16dp">
<android.support.v7.widget.CardView
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:cardBackgroundColor="?android:attr/windowBackground">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_height="wrap_content"
android:layout_width="match_parent"/>
</android.support.v7.widget.CardView>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
Do you have any hints or idea on how I could implement such design ? I guess that CoordinatorLayout could help me but I couldn't find anything ...
Thank you
Picking up Oknesif's idea of a manipulated adapter, I made an adapter with three layouts (topitem, middleitem, bottomitem) with two XML drawable shapes for topitem and bottomitem. Thus, I was able to completely get rid of the NestedScrollView and the CardView.
This is what it looks like:
And here is the code. First, MainActivity:
public class MainActivity extends AppCompatActivity {
final static int LIST_SIZE = 100;
final static int TOP = 0;
final static int BOTTOM = LIST_SIZE;
final static int MIDDLE = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
final ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < LIST_SIZE; i++) {
list.add(i);
}
class Viewholder extends RecyclerView.ViewHolder {
TextView textView;
Viewholder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.textView);
}
}
RecyclerView recyclerView = findViewById(R.id.recyclerView);
final RecyclerView.Adapter<Viewholder> adapter = new RecyclerView.Adapter<Viewholder>() {
LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
#Override
public Viewholder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case TOP:
return new Viewholder(inflater.inflate(R.layout.topitem, parent, false));
case BOTTOM:
return new Viewholder(inflater.inflate(R.layout.bottomitem, parent, false));
case MIDDLE:
default:
return new Viewholder(inflater.inflate(R.layout.middleitem, parent, false));
}
}
#Override
public void onBindViewHolder(Viewholder holder, int position) {
holder.textView.setText(String.valueOf(list.get(position)));
if (position != 0 && position != LIST_SIZE - 1) {
int color = position % 2 == 0 ? android.R.color.holo_orange_dark : android.R.color.holo_orange_light;
holder.itemView.setBackgroundColor(getResources().getColor(color));
}
}
#Override
public int getItemCount() {
return LIST_SIZE;
}
#Override
public int getItemViewType(int position) {
int itemViewType;
switch (position) {
case 0:
itemViewType = TOP;
break;
case LIST_SIZE - 1:
itemViewType = BOTTOM;
break;
default:
itemViewType = MIDDLE;
}
return itemViewType;
}
};
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
}
}
res/layout/activity.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/containerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingLeft="25dp"
android:paddingRight="25dp" />
</android.support.design.widget.CoordinatorLayout>
res/layout/topitem.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/topbackground"
android:layout_marginTop="50dp"
android:textAlignment="center"
android:textColor="#android:color/white"
android:textSize="24sp"
android:textStyle="bold" />
res/layout/middleitem.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textColor="#android:color/white"
android:textSize="24sp"
android:textStyle="bold" />
res/layout/bottomitem.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/bottombackground"
android:layout_marginBottom="50dp"
android:textAlignment="center"
android:textColor="#android:color/white"
android:textSize="24sp"
android:textStyle="bold" />
res/drawable/topbackground.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:topLeftRadius="5dp"
android:topRightRadius="5dp" />
<solid android:color="#android:color/holo_orange_dark" />
</shape>
res/drawable/bottombackground.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp" />
<solid android:color="#android:color/holo_orange_light" />
</shape>
EDIT:
Adding this line to the bottom XML item layouts:
android:elevation="12dp"
and changing the background to white, gives the following result:
it's just a simple line of code
recycler.setNestedScrollingEnabled(false);
and don't forget to make cardview height to wrap_content
I have a suggestion based on the Constraintlayout which I have used before.
You can create two Guideline to set the starting and ending position of the CardView during the scrolling process. Let me illustrate the XML for the start position of the view
<android.support.constraint.ConstraintLayout
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:clipChildren="false"
android:id="#+id/containerLayout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
tools:ignore="MissingPrefix">
<android.support.constraint.Guideline
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/guideline"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.1"/>
<android.support.constraint.Guideline
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/guideline2"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.9"/>
<android.support.v7.widget.CardView
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:cardBackgroundColor="?android:attr/windowBackground"
app:layout_constraintTop_toTopOf="#+id/guideline">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_height="wrap_content"
android:layout_width="match_parent" />
</android.support.v7.widget.CardView>
here I am assuming that you want to leave roughly 10% of screen space empty on top. If you want less or more, please adjust.
Once the user starts scrolling you can adjust the top constraint of the Cardview to the top of the parent and once he reaches the bottom of the list you can adjust the bottom constraint of the Cardview to the guideline2 which will leave 10% of screen space below.
This should achieve the desired effect without much performance issues since you are doing away with the Scrollview.
Please let me know if you need me to elaborate any part of my answer in more detail.

How can we scroll parent layout while scrolling recyclerview android

Please help me with the following situation.
I am developing an application where in one page I have a Linearlayout with a background image and RecyclerView with list of names.What I need is when i scroll up the RecyclerView I need the LinearLayout above also to move up so that the list in the recyclerView does not go under the LinearLayout above and when I scroll down the RecyclerView I need the LinearLayout above to scroll down so that we could see the image fully.
What i have done already is I used the setOnScrollListener of recyclerview and in the onScrolled() function I am getting the scrolling down and scrolling up event.But now i am stuck how to proceed further.
Below is the layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<include layout="#layout/toolbar"
android:id="#+id/toolbar" />
<android.support.v7.widget.CardView
android:id="#+id/cardview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/toolbar"
android:layout_margin="8dp"
card_view:cardBackgroundColor="#android:color/white"
card_view:cardCornerRadius="8dp">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/scrollview"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="5"
android:orientation="vertical">
<LinearLayout
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:background="#drawable/hydeparkmap"
android:layout_weight="3" ></LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:scrollbars="vertical" />
</LinearLayout>
</ScrollView>
</android.support.v7.widget.CardView>
</RelativeLayout>
Here is the code, i used in corresponding java class:
#InjectView(R.id.scrollview)
ScrollView scrollview;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shoplist);
ButterKnife.inject(this);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setTitle("ShopList");
scrollview.setVerticalScrollBarEnabled(true);
lm=new LinearLayoutManager(ShopListActivity.this);
recyclerView.setLayoutManager(lm);
firstVisibleInListview = lm.findFirstVisibleItemPosition();
adapter = new RecyclerViewAdapter(ShopListActivity.this, getData());
recyclerView.setAdapter(adapter);
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(ShopListActivity.this, new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Intent intent1 = new Intent(ShopListActivity.this, ShopProductListActivity.class);
intent1.putExtra("position", String.valueOf(position));
intent1.putExtra("shopname", it.get(position).getTitle());
intent1.putExtra("shopimage", String.valueOf(it.get(position).getImgIcon()));
intent1.putExtra("subcategory", subcategory);
startActivity(intent1);
}
})
);
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int currentFirstVisible = lm.findFirstVisibleItemPosition();
if(currentFirstVisible > firstVisibleInListview){
Toast.makeText(getBaseContext(),"Scrolled up ",Toast.LENGTH_SHORT).show();
scrollview.fullScroll(ScrollView.FOCUS_UP);
}
else
Toast.makeText(getBaseContext(),"Scrolled down ",Toast.LENGTH_SHORT).show();
firstVisibleInListview = currentFirstVisible;
}
});
}
so if I understand your question completely, you some View that should scroll with
RcyclerView.
if so in this situation you should delete your ScrollView cause RecyclerView have that within itself. what I write here is step by step guide to put a header( not sticky) in top of your RecyclerView so they would scroll together:
1- first you need to create a layout containing your header in my case i had an image for header so it looked like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#mipmap/winter"/>
</LinearLayout>
let's call this header_layout
2- you need to implement another method of RecyclerAdapter called getItemViewType it's output would be in as second parameter onCreateViewHolder(ViewGroup parent,int viewType) here you inflate the layout for each kind of view you need( for me these two look like this) :
#Override
public int getItemViewType(int position){
if(position == 0){
return 0;
} else {
return 1;
}
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView;
if(viewType==1){
itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.report_row_layout, parent, false);
} else {
itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.report_header_layout, parent, false);
}
return new MyViewHolder(itemView);
}
note that my first position (header) differs and other are the same you could have multiple views for multiple positions.
3- you should change your onBindViewHolder if needed in my case I needed to make it do nothing for my first position
4- remove your ScrollView and implement the layouts in positions and your main layout should look like this:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<include layout="#layout/toolbar"
android:id="#+id/toolbar" />
<android.support.v7.widget.CardView
android:id="#+id/cardview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/toolbar"
android:layout_margin="8dp"
card_view:cardBackgroundColor="#android:color/white"
card_view:cardCornerRadius="8dp">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v7.widget.CardView>
</RelativeLayout>
I don't know what your CardView is doing but delete it if you think it's not needed. if you need you can make your header a LinearLayout or anything else.
hope this helps.

Categories

Resources