I'm trying to make my RecyclerView prettier, so I added a CardView. However, I don't see any changes when I ran the app, the UI looks like as if there's no CardView at all - there is not separation between the items. Can you please suggest what's wrong with my code here?
This is my list_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/card_view"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="4dp"
card_view:cardElevation="6dp">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.AppCompatTextView
android:id="#+id/link_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:padding="1dp"
android:layout_marginBottom="10dp"
android:layout_marginStart="10dp"
android:text="#string/title_place_holder"/>
<LinearLayout
android:layout_below="#id/link_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<android.support.v7.widget.AppCompatImageView
android:id="#+id/link_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_gravity="center"
app:srcCompat="#drawable/ic_launcher_background"/>
<android.support.v7.widget.AppCompatTextView
android:id="#+id/link_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="15sp"
android:padding="1dp"
android:text="#string/summary_place_holder"/>
</LinearLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>
This is how I initialize my RecylerView:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView)findViewById(R.id.recyclerView);
mAdapter = new PostsAdapter(mPostList);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mAdapter);
preparePostData();
}
This can be achieved with a 1 line change in xml applied to the CardView element applying a margin.
android:layout_margin"#dimen/default_margin"
With your code:
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/card_view"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="4dp"
card_view:cardElevation="6dp"
android:layout_margin"#dimen/default_margin">
And in the dimens resources file
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<dimen name="default_margin">10dp</dimen>
</resources>
I have made changes in your code, please try below code
in place on
card_view:cardCornerRadius="4dp"
card_view:cardElevation="6dp"
I've changed to below
app:cardCornerRadius="4dp"
app:cardElevation="6dp"
app:cardUseCompatPadding="true"
Just replace below layout code
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com /apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:cardCornerRadius="4dp"
app:cardElevation="6dp"
app:cardUseCompatPadding="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatTextView
android:id="#+id/link_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:padding="1dp"
android:layout_marginBottom="10dp"
android:layout_marginStart="10dp"
android:text="#string/title_place_holder"/>
<LinearLayout
android:layout_below="#id/link_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<android.support.v7.widget.AppCompatImageView
android:id="#+id/link_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_gravity="center"
app:srcCompat="#drawable/ic_launcher_background"/>
<android.support.v7.widget.AppCompatTextView
android:id="#+id/link_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="15sp"
android:padding="1dp"
android:text="#string/summary_place_holder"/>
</LinearLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>
You need item decoration in RecyclerView with equal spacing around item!
Note : make sure yourRecyclerView background is different that item background
EqualSpacingItemDecoration.java
import android.graphics.Canvas;
import android.graphics.Rect;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class EqualSpacingItemDecoration extends RecyclerView.ItemDecoration {
private final int top;
private final int left;
private final int bottom;
private final int right;
private int displayMode;
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
public static final int GRID = 2;
public EqualSpacingItemDecoration(int top, int left, int bottom, int right) {
this(top, left, bottom, right, -1);
}
public EqualSpacingItemDecoration(int top, int left, int bottom, int right, int displayMode) {
this.top = top;
this.left = left;
this.bottom = bottom;
this.right = right;
this.displayMode = displayMode;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildViewHolder(view).getAdapterPosition();
int itemCount = state.getItemCount();
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
setSpacingForDirection(outRect, layoutManager, position, itemCount);
}
private void setSpacingForDirection(Rect outRect,
RecyclerView.LayoutManager layoutManager,
int position,
int itemCount) {
// Resolve display mode automatically
if (displayMode == -1) {
displayMode = resolveDisplayMode(layoutManager);
}
switch (displayMode) {
case HORIZONTAL:
outRect.left = left;
outRect.right = position == itemCount - 1 ? right : 0;
outRect.top = top;
outRect.bottom = bottom;
break;
case VERTICAL:
outRect.left = left;
outRect.right = right;
outRect.top = top;
outRect.bottom = position == itemCount - 1 ? bottom : 0;
break;
case GRID:
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
int cols = gridLayoutManager.getSpanCount();
int rows = itemCount / cols;
outRect.left = left;
outRect.right = position % cols == cols - 1 ? right : 0;
outRect.top = top;
outRect.bottom = position / cols == rows - 1 ? bottom : 0;
}
break;
}
}
private int resolveDisplayMode(RecyclerView.LayoutManager layoutManager) {
if (layoutManager instanceof GridLayoutManager) return GRID;
if (layoutManager.canScrollHorizontally()) return HORIZONTAL;
return VERTICAL;
}
#Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
}
}
Use like :
...
mRecyclerView..addItemDecoration(new EqualSpacingItemDecoration(12,12,12,12,1))
...
Just simply use app:cardUseCompatPadding="true" in CardView tag.
Try this in your manifest application tag.
android:hardwareAccelerated="true"
Related
I am trying to implement behaviour which is shown below (on pictures), so I need to stretch all content below AppBarLayout. I've already achieved it somehow by implementing custom CoordinatorLayout Behaviour but that solution have some issues with views recycling inside RecyclerView and overall performance. Is there easier solution to achieve what i want?
public class TestBehaviour48Margin extends CoordinatorLayout.Behavior {
public TestBehaviour48Margin() {
}
public TestBehaviour48Margin(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean layoutDependsOn(#NonNull CoordinatorLayout parent, #NonNull View child, #NonNull View dependency) {
return dependency instanceof AppBarLayout;
}
#Override
public boolean onDependentViewChanged(#NonNull CoordinatorLayout parent, #NonNull View child, #NonNull View dependency) {
AppBarLayout appBarLayout = (AppBarLayout) dependency;
val toolbar = appBarLayout.findViewById(R.id.toolbar);
int range = appBarLayout.getTotalScrollRange();
int totalHeight = parent.getHeight();
int appBarHeight = appBarLayout.getHeight();
int toolbarHeight = toolbar.getHeight();
int initialHeight = totalHeight - appBarHeight;
int finalHeight = totalHeight - toolbarHeight;
int differenceHeight = finalHeight - initialHeight;
float factor = -appBarLayout.getY() / range;
val layoutParams = child.getLayoutParams();
int lastHeight = layoutParams.height;
layoutParams.height = (int) (initialHeight + (differenceHeight * factor)) + LayoutUtils.dpToPx(parent.getContext(), 48);
if(lastHeight != layoutParams.height){
child.setLayoutParams(layoutParams);
}
return true;
}
}
<CoordinatorLayout ... (some content)
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="48dp"
android:layout_gravity="bottom"
app:layout_behavior=".custom_views.TestBehaviour48Margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/custom_pink"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:nestedScrollingEnabled="false"
android:id="#+id/rv_strength_items"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#color/grey_B" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#color/custom_blue_light" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_gravity="bottom"
android:background="#color/custom_green"
bind:layout_anchor="#id/scroll"
bind:layout_anchorGravity="bottom" />
</LinearLayout>
</FrameLayout>
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorSurfaceNight"
android:visibility="#{viewmodel.views.mainLayoutVisibility}"
app:elevation="0dp"
app:layout_behavior=".fragments.training.main_training.view_fold.BlockableAppBarLayoutBehaviour">
... rest of code
How do i get perfect aligning between the gridView items, i have added the gridview using java and it's base adapter is set in which i added the image and textview.
Xml Code:
<android.support.v7.widget.CardView
android:layout_width="180dp"
android:layout_height="200dp"
android:layout_margin="5dp"
android:orientation="vertical"
app:cardCornerRadius="5dp"
app:cardElevation="5dp">
<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:layout_weight="1"
android:orientation="vertical">
<ImageView
android:id="#+id/ImageWomenItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:scaleType="fitXY"
android:src="#drawable/womenone" />
</LinearLayout>
<TextView
android:id="#+id/itemName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Red Top"
android:textColor="#8e8d8d"
android:textSize="15dp" />
</LinearLayout>
</android.support.v7.widget.CardView>
This is Activity code in which i declared the recylerview and set it's adapter
Java code:
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerViewClothes);
recyclerView.setHasFixedSize(true);
mLayoutManager = new GridLayoutManager(getActivity(), 2);
recyclerView.setLayoutManager(mLayoutManager);
mAdapter = new GridAdapter();
recyclerView.setAdapter(mAdapter);
Use Space Decoration Class For That
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpacesItemDecoration(int space) {
this.space = space;
}
#Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
outRect.left = space;
outRect.right = space;
outRect.bottom = space;
// Add top margin only for the first item to avoid double space between items
if (parent.getChildLayoutPosition(view) == 0) {
outRect.top = space;
} else {
outRect.top = 0;
}
}
}
Your Activity Where You Set Your Adapter
int spacing = getResources().getDimensionPixelSize(R.dimen.spacing);
recyclerview.addItemDecoration(new SpacesItemDecoration(spacing));
Specify in dimen.xml
<dimen name="spacing">5px</dimen>
Xml Code:
<android.support.v7.widget.CardView
android:layout_width="175dp"
android:layout_height="200dp"
android:orientation="vertical"
app:cardCornerRadius="5dp"
app:cardElevation="5dp">
<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:layout_weight="1"
android:orientation="vertical">
<ImageView
android:id="#+id/ImageWomenItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:scaleType="fitXY"
android:src="#drawable/womenone" />
</LinearLayout>
<TextView
android:id="#+id/itemName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Red Top"
android:textColor="#8e8d8d"
android:textSize="15dp" />
</LinearLayout>
</android.support.v7.widget.CardView>
Try this,
recyclerView = (RecyclerView) findViewById(R.id.recyclerView );
recyclerView .setLayoutManager(new GridLayoutManager(getActivity(), 2));
int spanCount = 2;
int spacing_left = 10;
int spacing_top=15;
recyclerView.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing_left, spacing_top));
GridSpacingItemDecoration:
/* set spacing for grid view */
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
final private int spanCount, spacing, spacing_top;
final private boolean includeEdge;
public GridSpacingItemDecoration(int spanCount, int spacing_left, int spacing_top) {
this.spanCount = spanCount;
this.spacing = spacing_left;
this.includeEdge = true;
this.spacing_top = spacing_top;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item phases_position
int column = position % spanCount; // item column
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount;
outRect.right = (column + 1) * spacing / spanCount;
if (position < spanCount) { // top edge
outRect.top = spacing_top;
}
outRect.bottom = spacing_top; // item bottom
} else {
outRect.left = column * spacing / spanCount;
outRect.right = spacing - (column + 1) * spacing / spanCount;
if (position >= spanCount) {
outRect.top = spacing_top; // item top
}
}
}
}
Add padding to your root layout of adapter xml.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="8dp">
<android.support.v7.widget.CardView
app:cardCornerRadius="5dp"
app:cardElevation="5dp"
android:layout_width="180dp"
android:layout_height="200dp"
android:layout_margin="5dp"
android:orientation="vertical">.......
</android.support.v7.widget.CardView>
</LinearLayout>
I need to add a divider between two NavigationViews in my app. (navigation_drawer_top and navigation_drawer_bottom).
I have tried this. But this added divider to top of the view. not at end of the first NavigationView(navigation_drawer_top).
<View android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"/>
Here is my code
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/navigation_drawer_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start">
<android.support.design.widget.NavigationView
android:id="#+id/navigation_drawer_top"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="top"
android:background="#color/menuColor"
android:paddingLeft="50dp"
app:headerLayout="#layout/nav_header_main"
app:itemTextAppearance="#style/NavigationDrawerStyle"
app:itemTextColor="#color/menuTextColour"
app:menu="#menu/menu_navigation_drawer_top"
/>
<android.support.design.widget.NavigationView
android:id="#+id/navigation_drawer_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/menuColor"
android:layout_gravity="bottom"
android:paddingLeft="50dp"
app:itemTextAppearance="#style/NavigationDrawerStyle"
app:itemTextColor="#color/menuTextColour"
app:menu="#menu/menu_navigation_drawer_bottom" />
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
try this
<View
android:layout_below="#+id/id_of_item_below_which_you_want_it"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"/>
It's quite simple to do. All you need to do is make a group and put unique id to the groups. The unique id is what plays the real trick in adding a divider to your menu.
Here is a quick example for you,
<group android:id="#+id/group1" android:checkableBehavior="single" >
<item
android:id="#+id/item_1"
android:checked="true"
android:icon="#drawable/ic_1"
android:title="#string/title_1" />
</group>
<group android:id="#+id/group2" android:checkableBehavior="single" >
<item
android:id="#+id/item_2"
android:icon="#drawable/ic_2"
android:title="#string/title_2" />
</group>
This will surely add dividers to your menus.
EDIT
As you are adding menus programmatically, you should try to get access to each NavigationMenuView and add a decorator to them.
NavigationView navigationView = (NavigationView) findViewById(R.id.navigation);
NavigationMenuView navMenuView = (NavigationMenuView) navigationView.getChildAt(0);
navMenuView.addItemDecoration(new DividerItemDecoration(appContext,DividerItemDecoration.VERTICAL_LIST))
And here is the DividerItemDecoration class for you,
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
#Override
public void onDraw(Canvas c, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
#Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
Hi I have a simple CardView where I want to show a divider between each Cardview. The issue is, my View that I use as a divider never gets shown on the last CardView in my RecyclerView. Here is my attempt:
<?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"
xmlns:fresco="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="100dp"
card_view:cardElevation="0dp"
android:id="#+id/cv_news_feed">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
...Content...
</RelativeLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/material_color_grey_300" />
</android.support.v7.widget.CardView>
The divider shows up for every CardView except for the last for whatever reason and I'm not sure why this is occurring. Any help would be appreciated, thanks!
EDIT: Image posted:
Remove following view from your item
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/material_color_grey_300" />
and try to use ItemDecoration as follows
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
Utility.ItemDecorationConst);
recyclerView.addItemDecoration(5);
DividerItemDecoration.java
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public DividerItemDecoration(int space) {
this.space = space;
}
#Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
outRect.left = space;
outRect.right = space;
outRect.top = space;
outRect.bottom = space;
}
}
CardView is an extension of FrameLayout which means that your divider is not in the bottom of your CardView but in the top.
Place your divider in your LinearLayout instead.
Add layout_gravity attribute to the View:
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="bottom"
android:background="#color/material_color_grey_300" />
You can try to this code , hope this can help you
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:fresco="http://schemas.android.com/tools"
android:id="#+id/cv_news_feed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="100dp"
card_view:cardElevation="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
...Content...
</RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="#+id/cv_news_feed"
android:layout_marginTop="5dp"
android:background="#android:color/holo_red_dark" />
</RelativeLayout>
Create a class DividerItemDecoration:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* Created by Lincoln on 30/10/15.
*/
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
Then set the item decoration using addItemDecoration() method before setting the adapter.
recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
// set the adapter
recyclerView.setAdapter(mAdapter);
N.B. Remove the view that you are using in cardview layout to show the divider.
Try to put your divider into LinearLayout,i.e.:
You should use like this
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
...Content...
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/material_color_grey_300" />
</LinearLayout>
Because CardView extends FrameLayout so your devider will be behind LinearLayout content.
I'm trying to center all my items horizontally for each row in RecyclerView
I tried many things: RelativeLayout as a parent, then use layout_centerInParent, use the basic android:layout_gravity="center", try to add some space element,using weights and .... in
item_row.xml
but I didn't succeed :(
What i have
What i want
In activity
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
item_row.xml
<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/cardView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
card_view:cardCornerRadius="2dp"
card_view:cardElevation="4dp"
card_view:cardUseCompatPadding="true">
<!-- Recycler View Item Row -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="#+id/imgThumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:background="#android:color/black" />
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="item name"
android:id="#+id/txtName"
android:layout_margin="5dp"
android:singleLine="false"
android:lines="2"
android:gravity="center" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="#+id/txtCategory"
android:textStyle="italic"
android:textColor="#496fa9"
android:text="subtitle"
android:layout_weight="1"
android:gravity="center_vertical"
android:paddingLeft="10dp"
android:layout_gravity="center" />
<ImageButton
android:id="#+id/imageButton"
android:layout_width="48dp"
android:layout_height="wrap_content"
android:background="#android:color/black"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:padding="8dp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
i googled a lot and found this answer but actually i don't know how to create a LinearLayout for each row of items!
is that the best solution?
any other idea?
you can use a SpanSizeLookup to make views/items with different widths for your grid view. So with that you can do some cleverness with empty views to adjust accordingly. Might be more complicate or simpler depending on how variable your layout actually is.
reference: https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.SpanSizeLookup.html
for this specific case you show on your drawing you would do something like:
GridLayoutManager lm = new GridLayoutManager(context, 6);
lm.setSpanSizeLookup(new MySizeLookup());
public static class MySizeLookup extends SpanSizeLookup {
public int getSpanSize(int position) {
if(position >= 0 && position <= 2) {
return 2;
} else if (position == 3 || position == 6) {
return 1;
} else {
return 2;
}
}
}
and with that you'll have to make on your adapter, the position 3 and 6 to be an empty/invisible element. Something like new View(context); just to occupy that extra space
Use the gridLayoutManager = new GridLayoutManager(context,6) and override setSpanSizeLookup.
Example:
int totalSize=list.size();
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
int span;
span = totalSize % 3;
if (totalSize < 3) {
return 6;
} else if (span == 0 || (position <= ((totalSize - 1) - span))) {
return 2;
} else if (span == 1) {
return 6;
} else {
return 3;
}
}
});
This will work if you want to display 3 items in a row and remaining in the center of the grid.
Change the grid layout manager span counts accordingly your requirement.
GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 6);
final int totalSize = customList.size();
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
int extra;
extra = totalSize % 3;
if(extra == 0)
return 2;
if (totalSize - (position + 1) < extra) {
return (int) 6 / extra;
}
return 2;
}
});
recycler.setLayoutManager(layoutManager);
GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 6);
final int totalSize = customList.size();
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
int rows = Math.round((totalSize / 3f) + 0.4f);
int itemInRow = Math.round(((position + 1) / 3f) + 0.4f);
if (rows == 1 || rows == itemInRow) {
int span = totalSize % 3;
if (span == 0) {
return 2;
}
return 6 / span;
}
return 2;
}
});