I have a full screen grid layout with 8 rows of 7 ImageView.
I need all the rows centered without spaces between them (now I have as result the image I uploaded). The space must be only on the top and on the bottom. I already tried to find a solution on the Internet but I haven't found one.
XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<GridLayout
android:id="#+id/gameGrid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:rowCount="8"
android:columnCount="7"
>
<!-- ROW 1-1 -->
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:id="#+id/cellR1-1"
android:layout_rowWeight="1"
android:layout_columnWeight="1"
app:srcCompat="#drawable/dl"
/>
<!-- ROW 1-2 -->
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:id="#+id/cellR1-2"
android:layout_rowWeight="1"
android:layout_columnWeight="1"
app:srcCompat="#drawable/dl"
/>
<!-- ROW ... -->
</GridLayout>
</RelativeLayout>
I tried as solution to set all the ImageViews height same as the width but my code didn't worked:
void setGrid(){
//setting the cell height as the cell widht
int imagWidth = cell[0][0].getLayoutParams().width;
for(int r=0;r<rowCount;r++)
for(int c=0;c<columnCount;c++) {
cell[r][c].getLayoutParams().height = imagWidth;
cell[r][c].requestLayout();
}
}
Image:
It might be helpful to you, use the RecyclerView instead of GridLayout
RecyclerView.LayoutManager recyclerViewLayoutManager = new GridLayoutManager(getApplicationContext(), 7); // 7 means how many column you want you can change according to your requirement.
recyclerView.setLayoutManager(recyclerViewLayoutManager);
Try using RecyclerView with GridLayoutManager like below:
GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 7);
YourAdapter adapter = new YourAdapter();
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
int spacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16,
Objects.requireNonNull(getContext()).getResources().getDisplayMetrics());
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
#Override
public void getItemOffsets(#NotNull Rect outRect, #NotNull View view, #NotNull RecyclerView parent, #NotNull RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) == Objects.requireNonNull(parent.getAdapter()).getItemCount() - 1) {
outRect.bottom = spacing;
}
if (parent.getChildAdapterPosition(view) == 0) {
outRect.top = spacing;
}
}
});
Other solution is:
Instead of adding padding to both the top and bottom items, You can just add the padding to the top and bottom of your RecyclerView and set the clipToPadding attribute to false.
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingTop="8dp"
android:paddingBottom="8dp" />
Related
I'm trying to add Right and Left margins to my RecyclerView on the first and last item with Item Decorations.
The right and left margins are being successfully added to the first and last, however the ones in the middle have margins on the bottom and I have NO IDEA where they are coming from.
ItemDecoration:
public class MapItemDecoration extends RecyclerView.ItemDecoration {
private final int spacing;
public MapItemDecoration(int spacing) {
this.spacing = spacing;
}
#Override
public void getItemOffsets(Rect outRect, #NonNull View view,
#NonNull RecyclerView parent,
#NonNull RecyclerView.State state
) {
final int position = parent.getChildLayoutPosition(view);
final int itemCount = state.getItemCount();
if (position == 0) {
//Adds margins on first item on the right side
outRect.set(0, 0, spacing, 0);
} else if (itemCount > 0 && position == itemCount - 1) {
//Adds margins to the last item on the left side
outRect.set(spacing, 0, 0, 0);
} else {
//Margins between first and last item on both right and left side.
outRect.set(spacing, 0, spacing, 0);
}
}
}
ViewHolder:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content">
<ImageView
android:id="#+id/image"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
adapter = new MapAdapter(listLocations, this);
int spacing = SpacingUtils.convertIntToDP(this, 32);
recyclerView.addItemDecoration(new MapItemDecoration(spacing));
recyclerView.setLayoutManager(new LinearLayoutManager(
this, LinearLayoutManager.HORIZONTAL, false
));
recyclerView.setAdapter(adapter);
Does anyone know what I'm doing incorrectly? Why are margins being added to the bottom of my viewholders even though I have the value set as 0 inside my ItemDecorations?
Edit
:____________________________________________________
I tried setting a specified dp width on the ImageView inside the Viewholder
New ViewHolder:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/image"
android:layout_width="150dp"
android:layout_height="150dp"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
This seems to remove the bottom margins. But I need the ImageView to be using the attributes
<ImageView
android:id="#+id/image"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,1:1"
so my viewholder is scaled accordingly to the screensize. Is there another solution without setting the imageview as a specified width? Or maybe there is a way I could do it with percentage in the parent constraint layout.
This fixed the margins from appearing on the bottom:
Removing the attributes
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,1:1"
on my ImageView and setting it as
android:layout_width="match_parent"
android:layout_height="match_parent"
And since I still wanted a square ImageView and a viewholder that was sized based on the screensize, I programmatically sized it inside my onCreateViewHolder
Thanks to this answer by Ben P. https://stackoverflow.com/a/51202132/11110509
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.viewholder_map, parent, false);
ViewGroup.LayoutParams layoutParams = itemView.getLayoutParams();
int width = (int) (parent.getWidth() * 0.4);
layoutParams.width = width;
layoutParams.height = width;
itemView.setLayoutParams(layoutParams);
return new ViewHolder(itemView);
}
And the ViewHolder:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<ImageView
android:id="#+id/iv_location"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
This way I still get the square imageview, and also scaled viewholder size based on the device.
Hallo i have some problem in gridviiew inside recyclerview, there is some spaces above grid item 2. like this pic. that spaces changes dinamicaly if i reload content inside recyclerview.
normal recyclerview
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView2"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
item cardview
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:clickable="true"
android:clipChildren="true"
card_view:cardPreventCornerOverlap="false"
card_view:cardUseCompatPadding="false"
android:foreground="?attr/selectableItemBackground"
android:orientation="vertical">
found weird solution by add 2 dummy content and remove it (item 1 and 2) in recycler adapter onBindViewHolder solved my problem.
if (position == 1 || position == 0) {
// holder;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
0,
0
);
int margin = dpToPx(0);
params.setMargins(margin, margin, margin, margin);
holder.cardview2.setLayoutParams(params);
holder.cardview2.setVisibility(View.GONE);
} else {
so whats is the problem?
Want to add Spacing between the cards of CardView without using cardUseCompatPadding, How can i achieve that ?
Set Padding on rows so that all the items set spacing between each items
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#FFF"
android:padding="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
// here your views
</LinearLayout>
or, Use like this by java to saperate items
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setItemAnimator(new DefaultItemAnimator());
int spacingInPixels = getResources().getDimensionPixelSize(R.dimen.spacing);
recyclerView.addItemDecoration(new SpacesItemDecoration(spacingInPixels));
Class
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;
}
}
}
If you are using data binding, you may prefer to inspect <Space /> component in your list item for horizontal RecyclerView spacing
like below;
<data>
<variable
name="data"
type="com.foo.Entity" />
<variable
name="position"
type="int" />
<import type="android.view.View" />
</data>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="45dp"
android:gravity="center"
android:orientation="horizontal">
<Space
android:layout_width="6dp"
android:layout_height="6dp"
android:visibility="#{position == 0 ? View.GONE : View.VISIBLE}" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="#drawable/gray_border">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_margin="8dp"
android:background="#color/white"
android:gravity="center"
android:lineSpacingExtra="4sp"
android:maxLines="1"
android:singleLine="true"
android:text="#{data.text}"
android:textColor="#6b778d"
android:textSize="12sp"
android:textStyle="normal"
tools:text="Foo" />
</RelativeLayout>
</LinearLayout>
And you will see;
I'm trying to implement a RecyclerView with a GridLayoutManager in my Android application. The CardView elements within the RecyclerView are displaying vertically as if they were in a LinearLayout. How can I coerce them to fill the grid from left to right, one row at a time?
Here is my RecyclerView layout code:
<android.support.v7.widget.RecyclerView
android:id="#+id/RECYCLER_VIEW"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/item_offset" />
Here is my CardView layout 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"
card_view:cardUseCompatPadding="true"
android:layout_width="120dp"
android:layout_height="120dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_alignParentBottom="true"
android:textAlignment="center"
android:textSize="18dp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
Here is the code to set up the RecyclerView in the activity's onCreate method (CustomAdapter extends RecyclerView.Adapter):
// set up adapter
adapter = new CustomAdapter(getApplicationContext(), ApplicationState.getGridElements());
view.setAdapter(adapter);
// grid layout manager with 2 columns
GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
view.setLayoutManager(layoutManager);
// custom decoration for equal spacing
ItemOffsetDecoration itemDecoration = new ItemOffsetDecoration(getApplicationContext(), R.dimen.item_offset);
view.addItemDecoration(itemDecoration);
view.setHasFixedSize(true);
GridLayoutManager (Context context,
int spanCount,
int orientation,
boolean reverseLayout)
Set reverseLayout as true
I need to center elements in each row so they will be like in this mockup.
I've been searching if there is any layout that works that way without look.
items are centered in their rows.
This is how it looks now in my code.
Make recyclerview width to wrap_content and its container's layout_gravity to center_horizontal
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycrer_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingLeft="16dp"
android:paddingRight="16dp" />
</LinearLayout>
Take LinearLayout in your RecyclerView's item row layout then give android:layout_gravity="center" to LinearLayout.
For each row of images you have to take different LinearLayout.
Here is example code:
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal">
<ImageView
android:id="#+id/image1"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:src="#drawable/image1" />
<ImageView
android:id="#+id/image2"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:src="#drawable/image2" />
<ImageView
android:id="#+id/image3"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:src="#drawable/image3" />
</LinearLayout>
Achieved with:
recyclerView.adapter = MyAdapter()
val layoutManager = FlexboxLayoutManager(context).apply {
justifyContent = JustifyContent.CENTER
alignItems = AlignItems.CENTER
flexDirection = FlexDirection.ROW
flexWrap = FlexWrap.WRAP
}
recyclerView.layoutManager = layoutManager
You need to add FlexboxLayout to your gradle:
implementation 'com.google.android.flexbox:flexbox:3.0.0'
I am assuming that you are using a LinearLayoutManager with a RecyclerView for a ListView-style effect. In that case, use a horizontal LinearLayout for each row, with android:gravity="center" to center its contents.
Use FlexboxLayout from com.google.android:flexbox library. Note the flexwrap and justifyContent property values. Then, set layout_wrapBefore = true on the view that you want to wrap the line of items before.
<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:flexWrap="wrap"
app:justifyContent="center">
<View ... />
<View app:layout_wrapBefore="true" ... />
<View ... />
</com.google.android.flexbox.FlexboxLayout>
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.
you can use the new layoutManager from google FlexLayoutManager
it will gives you a lot of control and flexibility over the recyclerView items
you can add some layouts dynamically, for example:
adapter object can be a horizontal LinearLayout
1- create a LinearLayout in java code and customize it (gravity,...)
2- add some icons to linearLayout
3- add linearLayout to your adapter
4- repeat 1,2,3
// : declare new horizontal linearLayout
ImageView myIcons[nomOfIcons];
// : add all icons to myIcons
for(int i=1; i<=nomOfIcons; i++){
linearLayout.addView(myIcons[i - 1]);
if(i%numOfIconsInOneHorizontalLinearLayout==0) {
results.add(linearLayout); // add linearLayout to adapter dataSet
// : declare new horizontal linearLayout
}
}
if(n%numOfIconsInOneHorizontalLinearLayout!=0) // add last linearLayout if not added in the loop
results.add(linearLayout);
mAdapter.notifyDataSetChanged(); // update adapter
Currently, I think we need to write our own custom view for it because Android has not supported this feature as we expected yet.
It is the Sample I made in case someone needs it:
https://github.com/mttdat/utils
(Try the CenterGridActivity.kt by adjusting Manifest file to start this activity as default)
Trust me, this gonna work.
In your main xml file where you've put the recycler view, copy my code.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="#dimen/_50sdp"
android:gravity="center">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="#dimen/_50sdp"/>
</LinearLayout>