Prevent double spacing between childs inside RecyclerView GridLayout - android

I have the following ImageView for single image in GridLayout with 2 columns. But it adds double margins at the middle (because both has marginLeft and marginRight). How can I prevent this?
This is the xml:
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
app:srcCompat="#drawable/default_image" />

You can simply split the left & right margin values between the childs and the RecyclerView itself.
Like, if you intend to have 8dp margin on left & right and 8dp in middle, set 4dp left & right margin into childs layout and 4dp to RecyclerView layout.
If you have multiple rows, similar technique can be applied for top & bottom margins too.
Your child ImageView layout:
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
app:srcCompat="#drawable/default_image" />
Your RecylerView gridlayout:
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="4dp"
app:layoutManager="android.support.v7.widget.GridLayoutManager" />

it's convenient to use the RecyclerView‘s addItemDecoration(ItemDecoration decor).it would be better than in xml.

You can simply replace the code with below one:
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
app:srcCompat="#drawable/default_image" />

Related

Android: RelativeLayout + FrameLayout -> View align issue

I need to align top View which is wrapped inside FrameLayout to top of ImageView which has top padding/margin. Issue is that its aligning above padding/margin of ImageView. Is there any way how to ignore margins and paddings of ImageView and align it to top of visible image?
android:layout_alignParentTop="true"
android:layout_alignTop="#id/stop_timeline_icon"
android:layout_above="#id/stop_timeline_icon"
parameters are just pushing bottom edge of that FrameLayout above parent. (so I cant see it at all)
This is what I want to achieve. Orange line is my FrameLayout, grey square is my icon with top margin:
Layout:
<RelativeLayout
android:id="#+id/clickArea"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:clipChildren="false"
android:background="#drawable/menu_selector_background">
<FrameLayout
android:id="#+id/stop_timeline_top_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#id/stop_timeline_icon"
android:layout_alignEnd="#id/stop_timeline_icon"
android:layout_alignParentTop="true"
android:layout_alignTop="#id/stop_timeline_icon"
android:layout_above="#id/stop_timeline_icon">
<View
android:id="#+id/stop_timeline_top"
android:layout_width="2dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#color/doveGrey" />
</FrameLayout>
<ImageView
android:id="#+id/stop_timeline_icon"
android:layout_marginTop="18dp"
android:layout_width="20dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:src="#drawable/stop_icon"
app:tint="#color/doveGrey"/>
</RelativeLayout>

LinearLayout not showing all its children

After creating a LinearLayout with ImageViews as its children, I noticed that only the first row of items are shown. I thought the LinearLayout would automatically wrap its children onto a new line as necessary? The width seems fine but not the height.
Expected result
Expected blueprint (ImageView count is not to scale)
For some reason, when I create a LinearLayout inside another view, the width is shown correctly, but it never seems to adjust its height to fit & show all the children inside it.
Current result
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cv_facilities">
<LinearLayout
android:id="#+id/ll_facilities"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout
android:id="#+id/ll_titlerow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#+id/iv_expandcollapsearrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp" />
<ImageView
android:id="#+id/iv_topicsymbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp" />
<LinearLayout
android:id="#+id/ll_symbols"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#+id/iv_symbol_a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_language" />
<ImageView
android:id="#+id/iv_symbol_b"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_pets" />
<ImageView
android:id="#+id/iv_symbol_c"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_verified_user" />
<ImageView
android:id="#+id/iv_symbol_d"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_transport" />
<ImageView
android:id="#+id/iv_symbol_e"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_seat" />
<ImageView
android:id="#+id/iv_symbol_f"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_fingerprint" />
<ImageView
android:id="#+id/iv_symbol_g"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_areoplane_depart" />
<ImageView
android:id="#+id/iv_symbol_h"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_areoplane_arrive" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
This behavior of LinearLayout is "as intended": it will display its children in a horizontal or vertical line.
Since all of the child Views in your blueprint seem to be of a similar size, consider switching to GridLayout, it is available as androidx-library (e.g. androidx.gridlayout:gridlayout:1.0.0).
For child Views with varying dimensions, FlexboxLayout is a good alternative. It was introduced in a blog post in February 2017. There is a version for androidx available: 'com.google.android:flexbox:1.1.0'
A horizontal LinearLayout will not automatically wrap to a second line to fit it's children. Per the Android documentation it only supports a single direction:
LinearLayout is a view group that aligns all children in a single
direction, vertically or horizontally
What you could do is use flexbox-layout to achieve the wrapping behavior.
Don't make horizontal linearLayout with 6 imageView's
Make new vertical linearlayout and put on it two horizontal linear layout for each one 3 imageView .

Placing button that overlaps two views in Android

I would like to place a button like so (overlapping two views, centered):
I tried to solve the issue with a RelativeLayout and a negative margin but somehow I can't overlap the two views. Instead the button always get's placed at the bottom of the image view. Any ideas?
Thanks in advance for the help!
Here my code:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/tour_image"
android:layout_width="match_parent"
android:layout_height="220dp" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_marginBottom="-35dp"
android:layout_marginEnd="16dp">
<Button
android:id="#+id/go_to_map_button"
style="#style/FloatingActionButton.Light"
android:layout_width="70dp"
android:layout_height="70dp"
android:drawableTop="#drawable/ic_directions_walk_color_24dp"
android:paddingTop="12dp"
android:text="#string/tour_button_show_map"
android:textAllCaps="true"
android:textAppearance="#style/p.Small"
android:textColor="#color/primary_main" />
</RelativeLayout>
</RelativeLayout>
The code results in this layout:
In my opinion, the best way to handle this would be to convert your existing top-level RelativeLayout into a ConstraintLayout. Developer guide for ConstraintLayout is available here: https://developer.android.com/training/constraint-layout/index.html
Once you have a top-level ConstraintLayout, you can position a view on the edge of two views by constraining your button's top and bottom to the view edge:
<android.support.constraint.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">
<View
android:id="#+id/top"
android:layout_width="0dp"
android:layout_height="100dp"
android:background="#caf"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<View
android:id="#+id/bottom"
android:layout_width="0dp"
android:layout_height="100dp"
android:background="#fac"
app:layout_constraintTop_toBottomOf="#+id/top"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<View
android:id="#+id/overlap"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginRight="24dp"
android:background="#fff"
app:layout_constraintTop_toBottomOf="#+id/top"
app:layout_constraintRight_toRightOf="#+id/top"
app:layout_constraintBottom_toBottomOf="#+id/top"/>
</android.support.constraint.ConstraintLayout>
The important part of this code is that the "overlap" view has these two constraints:
app:layout_constraintTop_toBottomOf="#+id/top"
app:layout_constraintBottom_toBottomOf="#+id/top"
These are saying "match my top edge to the other view's bottom edge" and "match my bottom edge to the other view's bottom edge". Obviously that's impossible, since the view has a non-zero height, and so ConstraintLayout will automatically position it so that it is centered on the other view's edge. Further details are available in the developer guide I linked above.

Positioning in ConstraintLayout causes HorizontalScrollView to cut off content

<android.support.constraint.ConstraintLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="14"
android:layout_gravity="bottom"
android:background="#drawable/object_detailed_information_bar"
android:padding="#dimen/object_detailed_information_bar_padding">
<ImageView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:id="#+id/object_type_icon_image_view"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:src="#drawable/restaurant_marker_icon"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/object_name_text_view_margin_start_or_left"
android:layout_marginStart="#dimen/object_name_text_view_margin_start_or_left"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="#id/object_type_icon_image_view">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/object_name_text_view"
android:scrollHorizontally="true"
android:lines="1" />
</HorizontalScrollView>
</android.support.constraint.ConstraintLayout>
I positioned the TextView wrapped by ScrollHorizontalView to be the right of the ImageView using app:layout_constraintLeft_toRightOf="#id/object_type_icon_image_view". But it caused also unexcepted behaviour. Text stored in TextView can be scrolled but it's cut off by few letters. When i delete this line app:layout_constraintLeft_toRightOf="#id/object_type_icon_image_view", text it's fully shown while scrolling. Is there any way to fix that issue?
Screens:
android:text="123456789123456789123456789123456789123456789123456789"
Before scroll when positioned to the right of ImageView
After scroll when positioned to the right of ImageView - it's cut off
Before scroll without positioning
After scroll without positioning - it's ok
Short answer:
Change the width of your HorizontalScrollView to 0dp and constrain its right-hand edge to the parent:
android:layout_width="0dp"
app:layout_constraintRight_toRightOf="parent"
Explanation:
Right now, your HorizontalScrollView is using wrap_content for its width. This makes it attempt to be as long as the text, but the parent (the ConstraintLayout) won't allow its children to have a width larger than itself. So your HorizontalScrollView winds up being the same width as the ConstraintLayout.
However, you've positioned the HorizontalScrollView such that it has been moved slightly to the right. This means that there's part of the view that is invisible; the ConstraintLayout is clipping the HorizontalScrollView.
To fix this, you need to make sure that the HorizontalScrollView is as wide as the space between the right edge of the image and the right edge of the parent. You already have a left constraint on the HorizontalScrollView, so you need to add a right constraint. Once both sides are constrained, you can use a width of 0dp to mean "match constraints"; now the HorizontalScrollView will size itself to the available space.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/object_type_icon_image_view"
android:layout_width="200dp"
android:layout_height="0dp"
android:src="#color/link_blue"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<HorizontalScrollView
android:id="#+id/horizontalScrollView"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#color/red"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/object_type_icon_image_view"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="#+id/object_name_text_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Horizontal Scroll View"
android:textSize="25sp"
android:gravity="center"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="16dp" />
</HorizontalScrollView>
</android.support.constraint.ConstraintLayout>
Do you need this?

How can I evenly space my ImageViews in a RelativeLayout

I had a Android application built in which I had 3 ImageViews placed horizontally across a LinearLayout, they were placed with a android:layout_width="0dp" and android:layout_weight="1" such that they had an even spread in the layout.
Now I have to switch to use a RelativeLayout (because I want to overlap another image and that can't be done with a LinearLayout) so I want to start with replicating the same effect of having the 3 ImageViews evenly spread/scaled across the parent layout, but I'm not sure how to achieve this.
I feel like I need to make use of the android:scaleType... maybe center crop:
Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding).
Which sounds good but I can't seem to get it to work right... Any thoughts on how I would achieve this even spread of ImageViews across my RelativeLayout?
Snippet of code right now:
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" >
<ImageView
android:id="#+id/dragcircle"
android:layout_width="wrap_content"
android:tag="circle"
android:layout_alignParentLeft="true"
android:layout_height="wrap_content"
android:adjustViewBounds="false"
android:scaleType="centerCrop"
android:src="#drawable/circle" />
<ImageView
android:id="#+id/dragsquare"
android:layout_width="wrap_content"
android:tag="square"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/dragcircle"
android:adjustViewBounds="false"
android:src="#drawable/square" />
<ImageView
android:id="#+id/dragtriangle"
android:layout_width="wrap_content"
android:tag="triangle"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/dragsquare"
android:adjustViewBounds="false"
android:src="#drawable/triangle" />
Note: I can't find a question with the same constraints as this one on SO. There are a number of questions like:
Android: how evenly space components within RelativeLayout?
and
android RelativeLayout, equal spacing?
But if you check out the details you'll see that they are people who have not considered the LinearLayout as an option for equal spacing and switching layout types ends up being the solution. I have, I was using it, but it does not work for me because I need to overlap an image:
Note the example, I have 3 ImageViews with basic shapes, but I also have a 4th ImageView (it starts hidden) which is overlapping the middle one. This is why I must use a RelativeLayout
I think you're going to want to go back to your original LinearLayout to meet all of your needs here.
If the size of your fourth image must match one of your existing image then either you'd want to create a resource that is a composite of the two images to swap to when it needs to be overlaid or replace your center ImageView with a RelativeLayout or FrameLayout that contains the ImageView. When you need to add the fourth image, add it to that layout.
Something like:
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="#+id/dragcircle"
android:layout_width="0dp"
android:layout_weight="1"
android:tag="circle"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="#drawable/circle" />
<FrameLayout
android:id="#+id/centerimagewrapper"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1" >
<ImageView
android:id="#+id/dragsquare"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:tag="square"
android:src="#drawable/square" />
<ImageView
android:id="#+id/arrow"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="#drawable/arrow"
android:visibility="invisible" />
</FrameLayout>
<ImageView
android:id="#+id/dragtriangle"
android:layout_width="0dp"
android:layout_weight="1"
android:tag="triangle"
android:layout_height="wrap_content"
android:src="#drawable/triangle" />
You could hide the icon you want to place on existing images and keep your previous LinearLayout to achieve this. Each component of your LinearLayout would be a custom layout (inflated):
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relativeLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
>
<ImageView
android:id="#+id/img"
android:layout_width="100dip"
android:layout_height="100dip"
android:layout_centerInParent="true"
android:scaleType="fitXY"
android:background="#android:color/transparent"
android:src="img1_src"
/>
<ImageView
android:id="#+id/imgOverlap"
android:layout_width="50dip"
android:layout_height="50dip"
android:layout_centerInParent="true"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:background="#android:color/transparent"
android:src="img2_src"
android:visibility="gone"
/>
</RelativeLayout>
It appears not possible to use "layout_weight" in a RelativeLayout.
You could also consider a GridView and set its number of columns; each item of the GridView would be the inflated layout above.
you could also do it programatically and tell them to be 33% of the screen width. Look at DisplayMetrics and the attributes of each ImageView if you want to achieve this.
Try this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/dragcircle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:scaleType="fitXY"
android:src="#drawable/circle"
android:tag="circle" />
<ImageView
android:id="#+id/dragtriangle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:src="#drawable/triangle"
android:scaleType="fitXY"
android:tag="triangle" />
<ImageView
android:id="#+id/dragsquare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="#+id/dragtriangle"
android:layout_toRightOf="#id/dragcircle"
android:src="#drawable/square"
android:scaleType="fitXY"
android:tag="square" />
</RelativeLayout>

Categories

Resources