Android layout renders wrong on Marshmallow - android

I have just noticed that my Android app layout is broken when displayed on Marshmallow. It is fine on Nexus 5 with Android 5.1.1 but it renders wrong on Nexus 5 and Nexus 5x with the latest version of Android.
The layout consist of little triangle (see red part) aligned to the bottom and above it there is some view (white) that should span all available height of its parent (grey part).
And this is how it renders on Android 5.1.1 (Nexus 5):
while on Android 6.0 (Nexus 5 and Nexus 5X) it is:
The problem looks like the red view doesn't respect its parent alignment (bottom, right) and it makes the white view (which is placed above) to disappear.
The simplified layout of the grey view and its children is (I have added some background colours to see the view bounds):
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#777777">
<View
android:id="#+id/preview_triangle"
android:layout_width="#dimen/preview_triangle_width"
android:layout_height="#dimen/preview_triangle_height"
android:layout_marginRight="#dimen/preview_triangle_margin_right"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:background="#ff0000"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/preview_triangle"
android:orientation="horizontal">
<View
android:layout_width="#dimen/preview_margin_horizontal"
android:layout_height="match_parent"/>
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="3dp"
android:background="#drawable/round_rectangle_white_radius_3dp">
<WebView
android:id="#+id/preview_webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
<FrameLayout
android:id="#+id/preview_close"
android:layout_width="#dimen/preview_margin_horizontal"
android:layout_height="#dimen/preview_margin_horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|top"
android:layout_marginLeft="#dimen/preview_close_margin_left"
android:src="#drawable/icn_close"
android:contentDescription="#null"/>
</FrameLayout>
</LinearLayout>
</RelativeLayout>
The above layout is placed into separate preview.xml file and then included into main layout like this:
<include
android:id="#+id/fragment_main_loyalty_preview_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_below="#id/fragment_main_loyalty_logo_container"
android:layout_above="#id/fragment_main_loyalty_buttons_container"
android:layout_marginTop="#dimen/fragment_main_loyalty_preview_container_margin_top"
android:layout_marginBottom="#dimen/fragment_main_loyalty_preview_container_margin_bottom"
android:visibility="visible"
layout="#layout/preview"/>
UPDATE
The problem disappears if I replace hosting ScrollView with FrameLayout or so.
I really don't get it why the intermediary parent renders fine and its child is affected by the top most parent :)
And the situation can be reproduced inside Eclipse just by switching target API in the designer.
UPDATE - SIMPLIFIED TEST CASE
Below is the simplest layout I was able to create and reproduce my problem.
Basically the red area should be placed between green and blue ones.
The height of the red area should match the space available between green and blue views as there is another view (see #id/margin_placeholder) which height affects the distance between these two.
Inside the red area I wanted to put white view at the bottom of red area.
And this little white fellow renders different way on Android 6.0:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:id="#+id/top"
android:layout_width="match_parent"
android:layout_height="90dp"
android:layout_marginTop="10dp"
android:background="#007700"/>
<View
android:id="#+id/margin_placeholder"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_below="#id/top"/>
<FrameLayout
android:id="#+id/bottom"
android:layout_width="match_parent"
android:layout_height="90dp"
android:layout_below="#id/margin_placeholder"
android:background="#000077"/>
<RelativeLayout
android:id="#+id/middle"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_below="#id/top"
android:layout_above="#id/bottom"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="#770000">
<View
android:layout_width="16dp"
android:layout_height="8dp"
android:layout_marginRight="16dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="#ffffff"/>
</RelativeLayout>
</RelativeLayout>
</ScrollView>

It renders fine if I upgrade targetSdkVersion from 16 to 20.

Related

Button getting out of the screen android layout

I got this relativelayout and on the design screen of android studio looks good
enter image description here
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:padding="8dp"
tools:context="com.checking.movi.movioperations.CartItems">
<TextView
android:id="#+id/txtcartprod"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Productos seleccionados:"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_cart"
android:layout_width="match_parent"
android:layout_height="649dp"
android:layout_below="#+id/txtcartprod"
/>
<Button
android:id="#+id/btn_placeorder"
style="?android:attr/buttonStyleSmall"
android:layout_below="#+id/recycler_cart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/mybutton"
android:text="Continuar"
android:textColor="#ffffff" />
</RelativeLayout>
But when I test on the phone the button gets out of the screen if I decrease the size of the recyclerview it does appear can you guys give me a little help with this don't know to tell it to keep the 3 on the same screen
Giving width and height to views in dp's (or pixels) isn't the correct way. Because screen size isn't the same in all devices. Your design tab at Android Studio shows your layout in Pixel phone whose height is greater than your mobile phones. So, you can't see that button in your mobile phone.
I have added one line to your button and deleted another
Added this:
android:layout_alignParentBottom="true"
Deleted this:
android:layout_below="#+id/txtcartprod"
Changed height of RecyclerView to match_parent (to make it depend on screen size):
android:layout_height="match_parent"
And added this line:
android:layout_above= "#id/btn_placeorder"
Final version:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:padding="8dp"
tools:context="com.checking.movi.movioperations.CartItems">
<TextView
android:id="#+id/txtcartprod"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Productos seleccionados:"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_cart"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above= "#id/btn_placeorder"
android:layout_below="#+id/txtcartprod"
/>
<Button
android:id="#+id/btn_placeorder"
style="?android:attr/buttonStyleSmall"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/mybutton"
android:text="Continuar"
android:textColor="#ffffff" />
</RelativeLayout>
I hope you understood all the changes I made. If you have difficulty, feel free to ask in the comments.

Android Activity Layout-Problem on only 1 of 15 test-devices (ImageView)

I'm testing a new activity in our Android app. On all but one devices, everything was fine - except for a Huawei P30 Pro.
The activity is quite simple: it shows an ImageView and a small menu-bar on the bottom. Before the image is set, a ProgressBar (spinning circle) gets shown.
On the Huawei P30 Pro, everything seems to work fine (the ProgressBar appears, the circle is spinning, the ProgressBar disappears), but no Image becomes visible. If you forward the image by pressing the Apply-button in the menuBar, the image gets correctly forwarded, so it actually is available, it just doesn't get shown within the activity.
We tested the same version of the app on several other devices (including Huawei P10, P20, several Samsung-phones and HTC) and everything was ok. But on both Huawei P30 Pro we had available, the same problem appeared.
The layout-code is pretty straightforward:
<LinearLayout 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="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_weight="10">
<LinearLayout
android:layout_height="0dp"
android:layout_width="fill_parent"
android:layout_weight="9"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:srcCompat="#tools:sample/avatars"
android:contentDescription="Image preview"/>
<ProgressBar
android:id="#+id/indeterminateBar"
android:indeterminate="true"
android:minWidth="100dp"
android:minHeight="100dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerInParent="true"
/>
</RelativeLayout>
</LinearLayout
android:layout_height="0dp">
<LinearLayout
android:layout_height="0dp"
android:layout_width="fill_parent"
android:layout_weight="1">
<!-- bottom menu-bar-code is here as a TableLayout, which works fine on all devices -->
</LinearLayout>
</LinearLayout>
Maybe the ImageView has a height of 0 so it isn't visible?
I'm puzzled about what it could be, since it's only that particular device...
I checked if the ImageView-drawable does properly get set (imageView.getDrawable() != null) and it looks like it does (it is not null), as well as the visibility-state, which also seems to be fine.
So at this point, I think it is a pure layout-problem.
I highly recommend to switch from LinearLayout to ConstraintLayout. Even though your current layout works on 14 of 15 devices, the height of the bottom menu is always 10% and this will not look good on devices with small heights (have you ever tried your layout in landscape? You will see what I mean).
Once switched to ConstraintLayout, your layout issue on the 15th device should also disappear.
I transformed your layout to use ConstraintLayout to show how it could look like. It also has less layouts inside.
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:contentDescription="Image preview"
app:layout_constraintBottom_toTopOf="#id/bottomMenuBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="#tools:sample/avatars" />
<ProgressBar
android:id="#+id/indeterminateBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:minWidth="100dp"
android:minHeight="100dp"
app:layout_constraintBottom_toTopOf="#+id/bottomMenuBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="#+id/bottomMenuBar"
android:layout_width="fill_parent"
android:layout_height="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<!-- bottom menu-bar-code is here as a TableLayout, which works fine on all devices -->
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Please be aware that for visibility reasons in the layout preview I have added a fixed height for the LinearLayout of the bottom menu. Once you have understood the ConstraintLayout you should also change it for the menu bar. I kept it as a LinearLayout for easier usage with your real layout code.

Custom view shrinking: previously occupied space is not cleared

In a custom view, OnMeasure and OnSizeChanged is used to set the instrisic size and get the final size respectively.
In OnDraw, a drawable is drawn using the current Width/Height.
Now if the view is told to change its intrisic size, it will requestLayout. This triggers OnMeasure/OnSizeChanged and finally OnDraw.
It works fine, the drawable is always displayed using the correct inner size.
The problem is, if the new inner size is smaller than the old one, android leaves the old drawing (which seems to be "under" the new one, but in fact should have been cleared by android).
I tryed to clear the view content inside OnDraw, but the drawing rectangle is alread clipped to the new view size.
It sounds like a bug in LinearLayout not clearing its content when a child's view size shrink. Testing on Android 4.4 / Samsung S3 4G / CyanogenMod cm-11-20151004-NIGHTLY.
Layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/content"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#000000"
android:padding="8dp">
<LinearLayout
android:orientation="horizontal"
android:id="#+id/content"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:gravity="top">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#CCD39F">
<MyCustomView
android:id="#+id/myview"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
What i see after updating the custom view size. Only the "black part" should be displayed, not the white one.
It should be something like this instead:
I found the problem and a workaround.
The real problem is in LinearLayout. From Android 4.0.3 to Android 6. When this vertical linearlayout has weight=1 and height=0dp, and it has only one child which height is smaller than the available height. The first time this child is drawn, no problem. If the height of this child shrink, the area below it is not repainted. So it stays with the old content of the first child, instead of being refilled with the layout background color.
In the following layout code, i demonstrate the problem and solution. The solution is to add a second child which will take the rest of the free space below the first child. Using this technics it works as expected when the first child shrinks, the second one expands and the newly "empty" space is repainted correctly.
So it is really a bug in LinearLayout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#000000">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="top">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#CCD39F">
<MyCustomView
android:id="#+id/icon"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- Solution. To see the problem, remove the following layout -->
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#111111" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="right">
<Button
android:text="Other demo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/btnNextImage" />
<Button
android:text="Next SVG"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/btnGoEmpty" />
</LinearLayout>
</LinearLayout>

Android RecyclerView Spacing Differences between Platforms

Disclosure up front, this is a school project.
I've run into a somewhat confusing-to-me layout issue regarding a list of CardViews inside of a RecyclerView, that being that the spacing between cards is non-existent on 5.0, whereas it's fine on 4.4. Here's two screenshots to demonstrate.
Android 4.4 (On Device, Galaxy S4)
Android 5.0.1 (On Device, Nexus 4)
I can see the card corners in the 5.x version, so the cards are there. I have a feeling this is something to do with some XML attribute that I need for running 5.x that the support library fakes automatically on 4.x, but googling has failed me. Here's the relevant XML:
Fragment Layout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context="com.hinodesoftworks.kanagt.HiraganaListFragment">
<android.support.v7.widget.RecyclerView
android:id="#+id/hira_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
Card Layout
<?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_height="match_parent"
android:layout_width="match_parent"
card_view:cardCornerRadius="4dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/kana_card_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="46sp"
android:text="あ"/>
<TextView
android:id="#+id/kana_card_roma"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/kana_card_display"
android:layout_toEndOf="#id/kana_card_display"
android:text="a"
/>
<TextView
android:id="#+id/kana_card_info1_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/kana_card_display"
android:layout_toEndOf="#id/kana_card_display"
android:layout_below="#id/kana_card_roma"
android:text="INFO 1"/>
<TextView
android:id="#+id/kana_card_info2_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/kana_card_display"
android:layout_toEndOf="#id/kana_card_display"
android:layout_below="#id/kana_card_info1_display"
android:text="INFO 2"/>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/kana_card_info2_display">
<ImageView
android:id="#+id/kana_card_diagram"
android:layout_width="match_parent"
android:layout_height="100dp"
android:scaleType="fitStart"
android:adjustViewBounds="true"/>
</HorizontalScrollView>
</RelativeLayout>
</android.support.v7.widget.CardView>
I'm really hoping this is a dumb mistake with a simple XML fix; that the support library version is working fine makes me hopeful of that.
If you want the padding on 5.0 follow the same rules as on previous platforms add this attribute to the CardView XML element
app:cardUseCompatPadding="true"
On Lollipop the shadows can be drawn outside of the view bounds. On Kitkat and lower extra space has to be reserved for the shadows. That's why on Lollipop the spacing would have to be set explicitly.

Android screen rendered really wrong

I'm using a GLSurfaceView to render a live wallpaper behind my apps interface which consists of android UI elements.
In the beginning of my app I ask the user if they would like to see this wallpaper or not.
ONLY if the user accepts the GLSurfaceView is inflated in the existing xml as a first element so it will stay behind.
My problem is exactly the opposite of what i would think it would.
When the wallpaper is ACTIVATED the screen renders properly, like so:
When I don't use the wallpaper it's rendered like a, partially burned graphic card:
As you see from the xml structure, my GLSurfaceView is not even injected in the problematic case.
Something weird is that when it's injected the DDMS Monitor displays it as just
If the opposite was the case it would be clear that the problem is caused by the GLSurfaceView. But now it seems as if the lack of it causes this problem.
Any ideas on what could be the problem?
I'm using Nexus 4 to test and it seems that it could be related based on DanJAB
XML layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
style="?metaButtonBarButtonStyle"
android:id="#+id/home_history"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="#+id/button_calibrator"
android:text="#string/history"/>
<View
android:id="#+id/button_calibrator"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/home_history"
android:layout_alignBottom="#+id/home_history"
android:layout_centerHorizontal="true"/>
<Button
style="?metaButtonBarButtonStyle"
android:id="#+id/home_help"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_toRightOf="#+id/button_calibrator"
android:text="#string/help"/>
<View
android:id="#+id/screen_menu_seperator"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_below="#+id/home_history"
android:background="#color/holo_blue"/>
<ListView
android:id="#+id/homescreen_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/screen_menu_seperator"
android:background="#android:color/transparent"
android:cacheColorHint="#android:color/transparent"/>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_alignParentBottom="true"
android:background="#color/holo_blue"/>
</RelativeLayout>
GLSurfaceView XML:
<?xml version="1.0" encoding="utf-8"?>
<android.opengl.GLSurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:visibility="gone"/>
and in java:
getLayoutInflater().inflate(R.layout.background, contents);
GLSurfaceView background = (GLSurfaceView) contents.findViewById(R.id.background);
This is a phone bug. Nexus 4 causes this issue with certain theme configurations.

Categories

Resources