I am trying to achieve following structure (image below). As you can see there are two sections with RecyclerViews and CardViews in it. These two sections are divided by two TextViews with Buttons.
Each section should match screen width (minus indent between cards). Each CardView has square ImageView in it. So the height of CardView itself depend on screen width: card_height = screen_width - indent_between_cards + space_for_card_text. To achieve this behaviour I use simple SquareImageView, which looks like this:
public class SquaredImageView extends ImageView {
public SquaredImageView(Context context) {
super(context);
}
public SquaredImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquaredImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
setMeasuredDimension(width, width);
}
}
The CardView layout looks like this:
<CardView
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:background="#color/snow"
android:clickable="true"
android:orientation="vertical">
<!-- Image -->
<com.test.views.SquaredImageView
android:id="#+id/card_image"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Content -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="32dp"
android:orientation="horizontal">
<!-- Title -->
<TextView
android:id="#+id/card_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:singleLine="true"
android:textColor="#color/stone_dark"
android:textSize="14sp" />
<!-- Button -->
<ImageView
android:id="#+id/card_menu"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:clickable="true"
android:scaleType="center"
android:src="#drawable/ic_menu" />
</LinearLayout>
</CardView>
It means, that RecyclerView's adapter don't know the dimensions of CardView in advance.
As you probably know, RecyclerView has no system, which can measure its child-views, to make wrap its content correctly.
But unpredictable SquareImageView + fullscreen RecyclerView works fine in most of cases except the one described in this question.
So what's the problem? You should use your own LayoutManager or WrappableLayoutManager by #se-solovyev to solve your problem.
The problem is in unpredictable SquareImageView. When LayoutManager tries to measure its child, it gets nothing. It means that RecyclerView displayed in fullscreen (as if height and width are set to match_parent).
So the question is: how to make RecyclerView with unpredictable SquareImageViews wrap its content correctly?
Related
I'm trying to create a GridLayout with images. The grid has 3 columns.
I have a few problems though:
The ImageViews are going off the screen, as shown in the image below. The GridLayout isn't properly setting the width of the ImageViews to fit.
There is no space/margin between the ImageViews, even though I have set the horizontalSpacing and verticalSpacing properties for the GridLayout.
Here is my current code. What should I change to fix my two problems?
<GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="3"
android:horizontalSpacing="10dp"
android:verticalSpacing="10dp"
android:stretchMode="columnWidth">
<ImageView
android:layout_width="130dp"
android:layout_height="130dp"
android:background="#color/Color_DarkRed" />
<ImageView
android:layout_width="130dp"
android:layout_height="130dp"
android:background="#color/Color_DarkRed" />
<ImageView
android:layout_width="130dp"
android:layout_height="130dp"
android:background="#color/Color_DarkRed" />
<ImageView
android:layout_width="130dp"
android:layout_height="130dp"
android:background="#color/Color_DarkRed" />
<ImageView
android:layout_width="130dp"
android:layout_height="130dp"
android:background="#color/Color_DarkRed" />
<ImageView
android:layout_width="130dp"
android:layout_height="130dp"
android:background="#color/Color_DarkRed" />
</GridLayout>
Update
Following this answer, I tried using the following layout:
<GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="3">
<com.my.package.view.SquareImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/Color_DarkRed" />
<com.my.package.view.SquareImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/Color_DarkRed" />
<com.my.package.view.SquareImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/Color_DarkRed" />
</GridLayout>
But it comes out looking like the image below. Each ImageView takes up the entire width of the screen:
http://i.imgur.com/p8AXcKN.png
You should reduce the layout_width="130dp" because your screen isn't guaranteed to be 390dp
Change the images or you can also use Square Image View for proper sizing of your Grid Items.
Create a separate class for defining the size dynamically for your ImageView that should inherit ImageView class as shown below:
public class SquareImageView extends ImageView {
public SquareImageView(Context context) {
super(context);
}
public SquareImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
int width = getMeasuredWidth();
setMeasuredDimension(width, width);
}
}
The setMeasuredDimension(width, width); will automatically set your height as the width.
In xml file use this class as a view in place of ImageView as shown below:
<com.packagepath.SquareImageView
android:id="#+id/Imageview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
This is how it looks:
I've added an image to my layout. Because the image was a big small, and ended up in the middle of my screen, not filling the entire width of the screen, i had to stretch it out. With that, the letters obviously stretch out as well, which makes it look bad. I know that this might be unfixable. Every image needs to be stretched out, so the colors are fine, but the letters are always a bit hazy after that.
If this has no solutions at all, just tell me so I know that. If you think you know how to fix this, please help.
Don't think it's relevant, but this is the code that i added the image with:
<LinearLayout 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:orientation="vertical"
tools:context="com.example.rodekruis.MainActivity">
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="#drawable/rkz_logo4"
android:layout_marginBottom="30dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:scaleType="fitXY"
/>
Try to remove the attributes android: scaleType = "fitXY" and replace the android: layout_width = "fill_parent" on android: layout_width = "wrap_content"
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/rkz_logo4"
android:layout_marginBottom="30dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
/>
Create MyImageView.class
public class MyImageView extends ImageView {
public final static int WIDTH_IMAGE = 640;
public final static int HEIGHT_IMAGE = 200;
public MyImageView(Context context) {
super(context);
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = width * HEIGHT_IMAGE / WIDTH_IMAGE;
setMeasuredDimension(width, height);
}
}
in xml
<?xml version="1.0" encoding="utf-8"?>
<your.package.MyImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/image_banner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/rkz_logo4"
android:layout_marginBottom="30dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"/>
I have a ListView with an ImageView and TextView, I want to set the width of the image as 2/3 of the screen.
How do I create a custom ImageView to do this? This is what I've tried so far.
Custom View
public class CustomImageListView extends ImageView {
public CustomImageListView(Context context) {
super(context);
}
public CustomImageListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomImageListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Snap
// to
int width = MainActivity.width;
int height = MainActivity.height;
int w = width *2/5;
int h = w *4/6;
setMeasuredDimension(w, h);
// setMeasuredDimension(ChoseImage.width, ChoseImage.height); // Snap to
// //
// width
}
}
The custom View XML
<tuannt.tinmoi.custom.CustomImageListView
android:id="#+id/ivAvater"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/nomage" />
You can define a horizontal linear layout with WeightSum = 3 and inside it put another layout with with layout_weight = 1, the remaining portion will be of weight = 2, so you can put your imageView there. Refer below:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/fullscreen"
style="#style/translucent"
android:orientation="horizontal"
android:weightSum="3">
<RelativeLayout
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_gravity="right"
android:gravity="center"
android:background="#88000000"
android:id="#+id/sidebar"
android:layout_weight="1" >
</RelativeLayout>
<!-- other views, with a total layout_weight of 2 -->
</LinearLayout>
You don't need to create a Custom View to achieve this. You can make use of the layout_weight attribute.
This would be your layout for every item in the ListView.
item_in_listview.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
The layout_weight attribute is explained in this question.
In a nutshell, layout_weight specifies how much of the extra space in
the layout to be allocated to the View.
I currently have this code working. What I'm doing is downloading an image using Picasso and loading it into an imageView, which is inside a RecyclerView item.
Recycler Item 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_item"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardPreventCornerOverlap="false"
app:cardElevation="4dp"
app:cardCornerRadius="4dp"
app:cardUseCompatPadding="true">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Loading View -->
<com.wang.avi.AVLoadingIndicatorView
android:id="#+id/avloadingitem"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:visibility="gone"
app:indicator="BallClipRotate"
app:indicator_color="#color/colorAccent"/>
<!-- Imagen -->
<com.wallakoala.wallakoala.Views.ProductImageView
android:id="#+id/grid_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:riv_corner_radius_bottom_left="4dp"
app:riv_corner_radius_bottom_right="4dp"
app:riv_corner_radius_top_left="4dp"
app:riv_corner_radius_top_right="4dp"/>
<!-- Pie de foto -->
<RelativeLayout
android:id="#+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:alpha="0.75">
<!-- Info extra -->
<include android:id="#+id/extraInfo"
layout="#layout/product_footer_extra"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible"/>
<!-- Info principal -->
<include android:id="#+id/mainFooter"
layout="#layout/product_footer"
android:layout_height="#dimen/footer_height"
android:layout_width="match_parent"
android:layout_below="#id/extraInfo"/>
</RelativeLayout>
</FrameLayout>
</android.support.v7.widget.CardView>
This is my custom ImageView.
public class ProductImageView extends RoundedImageView
{
public ProductImageView(Context context)
{
super(context);
}
public ProductImageView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public ProductImageView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), (int)(getMeasuredWidth() * 1.32f));
}
}
I know the aspect ratio of the images, so I can do this in onMeasure method to tell Android the height I want:
setMeasuredDimension(getMeasuredWidth(), (int)(getMeasuredWidth() * 1.32f));
So now it works perfectly with images with that aspect ratio,however, I want to get rid of this, as I want to download images with different aspect ratios. So, how can I tell Android to fit the width and adjust the height of the imageView maintaining the aspect ratio?
Thanks in advance,
Think you should add the adjustViewBounds attribute to your image tag
<ImageView
android:id="#+id/thumbview"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_gravity="center"
android:adjustViewBounds="true"/>
You ImageView in xml should have height wrap_content, like this..
<ImageView
android:id="#+id/grid_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"/>
then, you should use post() method with picasso lib to load image from server.
imageView.post(new Runnable() {
#Override
public void run() {
Picasso.with(mActivity).load(path).resize(imageView.getWidth(), 0).into(imageView);
}
}); break;
There is a lib called ''Glide''. You can do this simply loading the image into a imageview and call .centercrop
ex: Glide.with(yourFragment)
.load(yourUrl)
.centerCrop()
.into(yourView);
Font> https://github.com/bumptech/glide/wiki/Transformations
What you're looking is: .fit().centerCrop() or .fit().centerInside()
Picasso
.with(context)
.load(imageUrl)
.fit()
.centerCrop()
// or .centerInside()
.into(myImageView)
fit: wait until the size of the ImageView can be measured, and resize the image to fit the ImageView
centerInside: The image will be displayed completely, but might not
fill the entire ImageView (Mantains aspect ratio)
centerCrop: scales the image so that it fills, cropping the extra
currently I am developing a settings menu in a scrollview. The basic structure looks like the following:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="#+id/scrollview_settings"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="#dimen/paddingSmall">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/transparent_white_settings"
android:paddingTop="#dimen/paddingMedium"
android:paddingBottom="#dimen/paddingMedium">
<ImageView
android:id="#+id/logo"
android:layout_width="68dp"
android:layout_height="wrap_content"
android:src="#drawable/newspaper_logo_color"
android:layout_alignParentRight="true"
android:layout_margin="#dimen/paddingBig"
android:adjustViewBounds="true"/>
</RelativeLayout>
<!-- Layout News Uebersicht -->
<include layout="#layout/separator_line_grey"/>
<de.basecom.noznewsapp.views.FontTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="true"
android:textColor="#color/buttonHoverBackground"
android:textSize="#dimen/sliding_image_kicker_font_size"
android:paddingLeft="#dimen/paddingLarge"
android:paddingTop="#dimen/paddingMedium"
android:paddingBottom="#dimen/paddingMedium"
android:text="#string/news_overview"
android:textScaleX="#dimen/letter_spacing"
android:textStyle="bold"
android:gravity="center_vertical"
android:background="#color/settings_header_color"
android:layout_gravity="center_vertical"/>
<include layout="#layout/separator_line_grey"/>
<!-- News-Overview Issues -->
<LinearLayout
android:id="#+id/issue_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#color/transparent_white_settings">
<de.basecom.noznewsapp.views.NewsScrollListView
android:id="#+id/listview_issues"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
android:divider="#null"
android:dividerHeight="0dp" />
</LinearLayout>
<!-- Layout Einstellungen -->
<de.basecom.noznewsapp.views.FontTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="true"
android:textColor="#color/buttonHoverBackground"
android:textSize="#dimen/sliding_image_kicker_font_size"
android:paddingLeft="#dimen/paddingLarge"
android:paddingTop="#dimen/paddingMedium"
android:paddingBottom="#dimen/paddingMedium"
android:text="#string/settings"
android:textStyle="bold"
android:textScaleX="#dimen/letter_spacing"
android:gravity="center_vertical"
android:background="#color/settings_header_color"
android:layout_gravity="center_vertical"/>
<include layout="#layout/separator_line_grey"/>
<!-- Einstellungs- Werte -->
<LinearLayout
android:id="#+id/settings_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#color/transparent_white_settings">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/paddingLarge">
<de.basecom.noznewsapp.views.FontTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/receive_pushmessages"
android:textAllCaps="true"
android:textScaleX="#dimen/letter_spacing"
android:textSize="#dimen/sliding_image_kicker_font_size"
android:layout_centerVertical="true"
android:textColor="#color/buttonBackground"/>
<Switch
android:id="#+id/receive_pushmessages_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="#string/empty_string"/>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
For the listview I used a custom implementation, to give it a fix height and make it able to scroll within the scrollview (note: I have to use the listview within the scrollview, because I have lots of elements, so that using a linearlayout wouldn't be nice).
public class CustomListView extends ListView {
public CustomListView(Context context) {
super(context);
}
public CustomListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomListView(Context context, AttributeSet attrs,int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Calculate entire height by providing a very large height hint.
// But do not use the highest 2 bits of this integer; those are
// reserved for the MeasureSpec mode.
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
Each item of the listview contains a label and a gridview, which is all shown correctly. But now I want to implement the functionality, that the user can click on the label to show and hide the visibility of the gridview.
But if I click on the label and the gridview is shown, the height of the listview doesn't adapt to the new open element. It always stays at the same height and if I open an element, the elements below are no longer visible. This also even happens, if I call the requestLayout() method of the listview to trigger its onMeasure again.
Anybody got an idea what I am doing wrong?
EDIT: Updated my xml file :)
Finally I was only able to solve this issue by replacing Listview with a LinearLayout and add my items in code to the Layout.