How to set Max Height for RecyclerView? - android

How to set Max Height of RecyclerView?
I have a RecyclerView as follows:
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/recycler_goods">
</android.support.v7.widget.RecyclerView>
When the items of recyclerview are too many, the recyclerview will be too high.
Can I set the max height of the recyclerview ?
when the recyclerview grow to the max height,The recyclerview will not grow up and the items of recyclerview can be scrolled.

Create a subclass of RecyclerView and override onMeasure method.
public class MyRecyclerView extends RecyclerView {
#Override
protected void onMeasure(int widthSpec, int heightSpec) {
height = MeasureSpec.makeMeasureSpec(Utils.dpsToPixels(the_height_you_want), MeasureSpec.AT_MOST);
super.onMeasure(widthSpec, height);
}
}

You can use ConstraintLayout to wrap RecyclerView and others, set their constraint and set minHeight for view belows RecyclerView

try this:
xml code
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Title"
android:textSize="21sp"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="30dp"> //increases your recycleview height
</android.support.v7.widget.RecyclerView>
</LinearLayout>
</FrameLayout>
java code
if your item on wrap content
ViewGroup.LayoutParams params=recycler_view.getLayoutParams();
params.height= RecyclerView.LayoutParams.WRAP_CONTENT;
recycler_view.setLayoutParams(params);
and
<dimen name="view_height">250dp</dimen>
float height= getResources().getDimension(R.dimen.view_height); //get height
ViewGroup.LayoutParams params_new=recycler_view.getLayoutParams();
params_new.height=height;
recycler_view.setLayoutParams(params_new);

Simplest solution: You can put RecyclerView with android:layout_height"match_parent" in a parent layout (RelativeLayout, LinearLayout,...) with specific height.

Related

How to center ImageView in GridLayout?

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" />

Android RecyclerView and GridLayoutManager layout

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

Percentage of a layout inside RecyclerView visible on Screen

Is there a way from which I can know what percentage of my layout inside a recyclerView is visible on the Screen.
The layout inflated inside RecyclerView has params of
android:layout_width="match_parent"
android:layout_height="match_parent"
Edit added layout file
Layout file - custom_card.xml
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignBottom="#id/imageView"
android:layout_alignTop="#id/imageView"
android:scaleType="fitCenter"
android:src="#drawable/image_view_screen" />
</RelativeLayout>
Activity Layout File.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ProgressBar
android:visibility="gone"
android:layout_width="56dp"
android:layout_height="56dp"
android:id="#+id/progress_bar"
android:layout_centerInParent="true"/>
</RelativeLayout>
I am using a Vertical LinearLayoutManager
After much Try I figured it out. If it helps anyone.
Since my layout height was match_parent it was easier for me. But this method will work for everyone with some calculations.
int firstItemPos=mLayoutManager.findFirstVisibleItemPosition();
View firstItemView=mLayoutManager.findViewByPosition(firstItemPos);
int lastItemPos=mLayoutManager.findLastVisibleItemPosition();
View lastItemView=mLayoutManager.findViewByPosition(lastItemPos);
Now all items between firstItemPos and lastItemPos is visible 100%.
For firstItemView-
Math.abs(firstItemView.getY()) / firstItemView.getHeight()
Similarly for lastItemView-
Math.abs(lastItemView.getY()) / lastItemView.getHeight()
use this;
in your adapter;
private final Rect mCurrentViewRect = new Rect();
... your inits...
in your onBindViewHolder;
View firstItemView = linearLayoutManager.findViewByPosition(position);
int pos= getVisibilityPercents(position);
use these metods;
public int getVisibilityPercents(View currentView) {
int percents = 100;
currentView.getLocalVisibleRect(mCurrentViewRect);
int height = currentView.getHeight();
if (viewIsPartiallyHiddenTop()) {
percents = (height - mCurrentViewRect.top) * 100 / height;
} else if (viewIsPartiallyHiddenBottom(height)) {
percents = mCurrentViewRect.bottom * 100 / height;
}
return percents;
}
private boolean viewIsPartiallyHiddenBottom(int height) {
return mCurrentViewRect.bottom > 0 && mCurrentViewRect.bottom < height;
}
private boolean viewIsPartiallyHiddenTop() {
return mCurrentViewRect.top > 0;
}
btw, dont remember get your recyclerView and linearLayoutManager to your adapter in constructor.
For more => https://github.com/danylovolokh/VideoPlayerManager

How to set weight for width and height?

I need to create view dynamical with width and height which are the percent of parent size.So I need to add weight for width and height for one view.
Is it possible?
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:weightSum="4"
android:orientation="horizontal">
<ImageView
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_weight="1"
android:gravity="center"
android:id="#+id/imgtype"
android:scaleType="fitCenter"/>
<TextView
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_weight="3"
android:id="#+id/txtsubject"
android:textStyle="bold"
android:textSize="#dimen/lat_sub_text_size"
android:textColor="#android:color/black"/>
<LinearLayout/>
here you will be able to divide the major portion of parent linearlayout's width to the textview and remaining minor part for imageview this is for aligning horizontally the same can be done for vertical as well.Weightsum property of parent decides number of parts it will contain.
For example, I have the below layout:
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/ll_forImage"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="#+id/ll_forList"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
</LinearLayout>
Now, I will set width and height for each View depend on Screen width and Screen Height.
int screenWidth = dpToPx(getResources().getConfiguration().screenWidthDp);
int screenHeight = dpToPx(getResources().getConfiguration().screenHeightDp);
int ratioW = ....;//
int ratioH = ....;//
setLayoutSize(ll_forImage, screenWidth/ratioW , screenHeight/ratioH );
setLayoutSize(ll_forList, screenWidth/ratioW , screenHeight - screenHeight/ratioH );
// You can use setTranslation to translate View to expected position.
with:
private int dpToPx(int dp) {
return (int) (dp * getResources().getDisplayMetrics().density + 0.5f);
}
private static void setLayoutSize(View view, int width, int height) {
ViewGroup.LayoutParams params = view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
}
Adding layout_weight is a good approach while using LinearLayout.
Remember, layout_weight works only in case of LinearLayout and cannot be used with RelativeLayout.

ImageView with no source does not honor layout, adding source does not repair layout

My base layout is a ListView of LinearLayouts, and each item in the grid is the FrameLayout below. I am downloading an image to the ImageView. Prior to the image being loaded, there is no content and the layout is shrunk to the height of the small ProgressBar (first problem), when I expect it to be 240dp or 120dp. After the image is placed in the view, the layout does not adjust (second problem) and the height remains the shrunken dimension of a small ProgressBar.
loading image code:
#Override
public View getView(View convertView) {
// ...
// set up holder
// ...
new GetPhotoTask().execute(holder.my_tile_image, holder.my_loading, my_media_url);
holder.my_tile_image.setVisibility(View.INVISIBLE);
holder.my_loading.setVisibility(View.VISIBLE);
holder.my_tile_label.setText(activityObject1.track.name);
// ...
}
private final class GetPhotoTask extends AsyncTask<Object, Void, Drawable> {
ImageView iv;
ProgressBar pb;
#Override
protected Drawable doInBackground(Object... params) {
iv = (ImageView) params[0];
pb = (ProgressBar) params[1];
return new BitmapDrawable(getResources(), loadAsset(params[2]).media_url, true));
}
#Override
protected void onPostExecute(Drawable result) {
super.onPostExecute(result);
pb.setVisibility(View.GONE);
iv.setImageDrawable(result);
iv.setVisibility(View.VISIBLE);
}
}
the main xml:
<ListView
android:id="#+id/my_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="2dp" />
the xml for each row:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/my_row_type_3"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="240dp"
android:weightSum="3" >
<include layout="#layout/my_tile_layout"
android:id="#+id/my_tile_1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" />
<LinearLayout
android:id="#+id/my_row_type_2"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:weightSum="2" >
<include layout="#layout/my_tile_layout"
android:id="#+id/my_tile_2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<include layout="#layout/my_tile_layout"
android:id="#+id/my_tile_3"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
the xml for row content:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/my_tile_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="2dp" >
<ImageView
android:id="#+id/my_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:contentDescription="#string/foo" />
<ProgressBar
android:id="#+id/my_loading"
style="?android:attr/progressBarStyleSmall"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" />
<TextView
android:id="#+id/my_tile_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/my_title"
android:layout_gravity="left|bottom" />
</FrameLayout>
Why does the initial layout shrink to the height of progress bar even though I've hard coded 240dp for each row? Why does setting a bitmap in the ImageView content not cause it to resize at that point either? The first question most important, as I believe it will nullify the second. Thanks in advance.
SOLUTION
To get the structure I want, I use RelativeLayout for the tiles (for layering ability), and for each row I am overriding the LinearLayout to enforce the sizing I want set for each row. As there is a potential for each tile's content to be larger or smaller than the view, this is screwing up my ability to rely on either centerCrop or fitCenter. So in my custom layout, I set the height to be proportional to the width of each row, and the mode of the MeasureSpec to be EXACTLY.
public final class MyRow3 extends LinearLayout {
// ...
#Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, makeMeasureSpec(getSize(widthMeasureSpec) * 2 / 3, MeasureSpec.EXACTLY));
}
I'm not sure why it isn't honouring it but why not do something like this instead:
Set an absolute height in your ImageView to guarantee some space.
<ImageView
android:layout_height="###dp"
/>
Then change the layout back to an auto adjusted state just before the image is loaded:
iv.setLayoutParams( new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT ) );
To get the structure I want, I use RelativeLayout for the tiles (for layering ability), and for each row I am overriding the LinearLayout to enforce the sizing I want set for each row. As there is a potential for each tile's content to be larger or smaller than the view, this is screwing up my ability to rely on either centerCrop or fitCenter. So in my custom layout, I set the height to be proportional to the width of each row, and the mode of the MeasureSpec to be EXACTLY.
public final class MyRow3 extends LinearLayout {
// ...
#Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, makeMeasureSpec(getSize(widthMeasureSpec) * 2 / 3, MeasureSpec.EXACTLY));
}

Categories

Resources