I am trying to resize my layouts, based on which device I am using.
I am testing on two differents phones (Samsung Galaxy S8+ and Sony Xperia Z2 (and even two different emulators)).
I've added some code into the Manifest file.
I've created different folders with the right (supposedly) names (layout, layout-small, layout-large, layout-xlarge).
I put my code into the values folder, file "dimens.xml" and call it from my layouts.
But nothing seems to work.
The only time my screens are changing is when I am modifying the corresponding file into the "layout" folder.
I would love any help or advice. Thank you!
I've read many times the documentation on Android Developer and Stack Overflow and I can't seem to find a solution.
Snippet of AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.applicationpro">
<supports-screens android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true"
android:resizeable="true" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
Snippet of res/layout-large/my_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/mainLL"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/bg4"
android:orientation="vertical"
tools:context=".activity.LoginActivity">
<ProgressBar
android:id="#+id/loginPG"
android:theme="#style/FragmentsProgressBar"
style="#style/Widget.AppCompat.ProgressBar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:layout_marginTop="100dp"/>
<android.support.design.widget.TextInputLayout
android:id="#+id/loginTIY"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/margin_top_large">
<AutoCompleteTextView
android:id="#+id/loginTV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/prompt_login"
android:maxLines="1"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
dimens.xml
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="standard_55">65dp</dimen>
<dimen name="standard_105">135dp</dimen>
<dimen name="standard_155">155dp</dimen>
<!-- Small Dimensions = "Medium Dimensions * 0.75" For Example: 210*.75 = 157.5-->
<dimen name = "margin_top_small">150dp</dimen>
<!-- Medium Dimensions -->
<dimen name = "margin_top_medium">200dp</dimen>
<!-- Large Dimensions = "Medium Dimensions * 1.5" For Example: 210*1.5 = 315 -->
<dimen name = "margin_top_large">300dp</dimen>
<!-- XLarge Dimensions = "Medium Dimensions * 2" For Example: 210*1.5 = 420 -->
<dimen name = "margin_top_xLarge">400dp</dimen>
</resources>
TL;DR
This is another approach using ConstraintLayout and not a single layout for every screen size
You can support different screen sizes by using ConstraintLayout:
ConstraintLayout allows you to create large and complex layouts with a flat view hierarchy (no nested view groups). It's similar to RelativeLayout in that all views are laid out according to relationships between sibling views and the parent layout, but it's more flexible than RelativeLayout and easier to use with Android Studio's Layout Editor.
You can use those attributes to specify your views size in precents:
app:layout_constraintWidth_percent=".5"
app:layout_constraintHeight_percent=".5"
For example, single button that is equal to 50% of the screen both in height and width:
<?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">
<Button
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent=".5"
app:layout_constraintHeight_percent=".5"/>
</androidx.constraintlayout.widget.ConstraintLayout>
And it will look something like this:
I can recommend using ConstraintLayout with guidelines and Chains to support different screen sizes (In addition to what I mentioned above - app:layout_constraintWidth_percent and app:layout_constraintHeight_percent).
At first look this may look like a lot of work and some may wonder if this is really worth the effort but here is why I believe ConstraintLayout is the proper way to build your UI:
It's really user-friendly.
ConstraintLayout is very easy and simple to learn.
once you have learned it you will see that you are saving a lot of development time because making your UI is simply fast.
Constraint layout is meant to support different screen sizes so no need to build a layout for every screen size (this also connect to the previous advantage- saving development time).
Related
I am trying to change between images using fade in/out and I am having a difficult time.
This is what I have for the code
public void fade(View view)
{
ImageView loveLive = findViewById(R.id.lovelive);
ImageView rikoCheer = findViewById(R.id.rikoCheer);
loveLive.animate().alpha(0f).setDuration(2000);
rikoCheer.animate().alpha(1f).setDuration(2000);
}
public void fade2(View view)
{
ImageView rikoCheer = findViewById(R.id.rikoCheer);
ImageView loveLive = findViewById(R.id.lovelive);
rikoCheer.animate().alpha(0f).setDuration(2000);
loveLive.animate().alpha(1f).setDuration(2000);
}
Here is my xml file
<?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"
tools:context=".MainActivity">
<ImageView
android:id="#+id/lovelive"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="fade"
app:srcCompat="#drawable/lovelive"
tools:layout_editor_absoluteX="50dp"
tools:layout_editor_absoluteY="-69dp" />
<ImageView
android:id="#+id/rikoCheer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0"
android:onClick="fade"
app:srcCompat="#drawable/rikocheer"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
so my goal for this is to fade in and fade out between images
What's going wrong exactly? If nothing's showing up it might be that you don't have any layout constraints set up for your images (the tools: stuff only affects the layout editor, like fake data for testing, it doesn't apply when you run the app)
There's something called a TransitionDrawable you might want to use, you'd basically create a new Drawable XML file and put this in it
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/lovelive" />
<item android:drawable="#drawable/rikocheer" />
</transition>
and then you can just use that in an ImageView or whatever.
In your code you'd go
myImage = (TransitionDrawable) findViewById<ImageView>(R.id.thatImageView).getDrawable()
and then you can call myImage.startTransition(duration) to go from image 1 to image 2, or myImage.reverseTransition(duration) to go back to the first image. You can switch immediately with resetTransition() for image 1 or startTransition(0) to go straight to image 2
You also might want to use setCrossfadeEnabled() on the TransitionDrawable - when it's false the first image is always opaque, so the second is drawn on top of it like an overlay. If it's set to true you get one fading out while the other fades in - depends what you want!
I'm writing an Android app with minSdkVersion = 15 (testing on 19). I would like to have an overlay with a small phone picture in the middle. I added the drawable (xml) resource ic_smartphone_black_24dp from the standard Android's pictures and created an ImageView for the overlay like this:
<ImageView
android:id="#+id/overlay"
android:layout_width="0dp"
android:layout_height="0dp"
android:alpha="1."
android:background="#drawable/overlay_full"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
This renders the overlay, but the smartphone picture is stretched to the whole ImageView:
I tried to scale the phone's picture in various ways (reading this, that and many others), but none of it worked. In particular I tried:
adding vectorDrawables.useSupportLibrary = true to gradle.build
adding
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
to the Activity
changing the ImageView to android.support.v7.widget.AppCompatImageView (and setting the background in java code and not in xml)
passing wrap_content instead of 0dp as layout_width/height (and removing the constraints)
setting the size in the overlay_full:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="#drawable/overlay_background">
<size
android:width="152dp"
android:height="152dp"/>
</item>
<item android:drawable="#drawable/ic_smartphone_black_24dp"
android:left="30dp"
android:top="30dp"
android:right="30dp"
android:bottom="30dp"
android:gravity="center"
android:scaleType="center"
android:width="30dp"
android:height="30dp">
<size
android:width="30dp"
android:height="30dp"/>
</item>
</layer-list>
The code works as expected in API 28 where I also tested. Any idea how to do this scaling in earlier API versions?
You could try something like this:
<ImageView
android:id="#+id/overlay"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="center"
android:background="#drawable/just_the_background"
app:srcCompat="#drawable/ic_smartphone_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
Also, you don't need to use AppCompat views directly in layouts, just let the library handle this for you (they are replaced automatically at build time). You only need to use them if you're extending them to add custom functionality.
I'd like my Spinner dropdown items to fill the entire screen width even tho my 'title' does not. Problem is the dropdown menu width seems to be limited the Spinner's title width.
My goal is to make it fill the entire screen width, with no spacing left or right, right below the action bar. A similar one to what I'm trying to do would be Instagram's menu to change profile.
I looked to similar questions but didn't find a solution that worked here. Also tried to create a custom adapter and making sure its views had match_parent attribute on their width. But didn't work either.
main.java (only relevant part of the code for legibility)
mMyListsSpinner = (Spinner) findViewById(R.id.spinner_mylists);
ArrayAdapter<String> snipperAdapter = new ArrayAdapter<String>(
FamilistActivity.this, R.layout.layout_spinner_title, dummyLists);
snipperAdapter.setDropDownViewResource(R.layout.layout_spinner_dropdown);
mMyListsSpinner.setAdapter(snipperAdapter);
mMyListsSpinner.setOnItemSelectedListener(this);
layout_spinner_title.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/spinner_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#color/color_white_bright"
android:maxLines="1"
style="#style/OverflowMenu"
android:text="this is my list"/>
layout_spinner_dropdown.xml
<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_spinner_dropdown"
android:layout_width="match_parent"
android:layout_height="#dimen/toolbar_actionbar_height"
android:maxLines="1"
android:textSize="18sp"
android:textColor="#color/color_green_dark"
android:background="#color/color_white_bright"/>
styles.xml (only the relevant part)
<style name="OverflowMenu" parent="Widget.AppCompat.PopupMenu.Overflow">
<item name="overlapAnchor">false</item>
<item name="android:dropDownVerticalOffset">16dp</item>
<item name="android:dropDownHorizontalOffset">-15dp</item>
</style>
my toolbar:
toolbar.xml
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/bar_appbar"
android:layout_width="match_parent"
android:layout_height="#dimen/toolbar_actionbar_height"
app:layout_collapseMode="pin"
android:background="#color/color_green_bright">
<Spinner
android:id="#+id/spinner_mylists"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:spinnerMode="dropdown"
android:dropDownWidth="match_parent"
style="#style/OverflowMenu"/>
By looking into AppCompatSpinner.java and running the debugger I saw in this line in computeContentWidth()
else if (mDropDownWidth == MATCH_PARENT) {
setContentWidth(spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight);
}
that SpinnerPaddingRight has a value that is not 0. I solved it by setting
android:paddingEnd="0dp"
in the Spinner view.
I am trying to use a CoordinatorLayout to anchor a view to another one and it is working almost perfectly. The problem is that when i switch to another fragment, open the keyboard, then switch back, the anchored view gets messed up. Sometimes after a couple seconds it (seemingly) randomly snaps back into place. Here is a gif to demonstrate what I am talking about.
As you can see, the FloatingActionButton is not aligned when I return to the fragment, but after a while it snaps back into place. What could cause this issue?
Fragment XML
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout android:id="#+id/coordinatorLayout_main"
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:fitsSystemWindows="false">
<!-- Other views -->
<!-- Bottom sheet -->
<include
android:id="#+id/bottom_sheet"
layout="#layout/bottom_sheet_primes"/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/button_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="#dimen/fab_margin"
android:src="#drawable/ic_play_arrow_white_24dp"
app:backgroundTint="#color/accent"
app:layout_anchor="#id/bottom_sheet"
app:layout_anchorGravity="top|end"/>
</android.support.design.widget.CoordinatorLayout>
The solution to this is to use android:windowSoftInputMode="adjustPan" attribute in your activity tag of the activity in question in the AndroidManifest.xml file.
How can I assign each view an automatic margin?
Example:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button ... />
<Button ... />
<Button ... />
<Button ... />
</LinearLayout>
I want each of these buttons to have the same amount of space between them.
Now I could just put a layout_marginTop and a layout_marginBottom attribute in each of the tags and set their values to what I want them to be, but isn't there an easier way to do this?
Can I somehow automatically set each view's margin in my LinearLayout to a specific value without having to type it in every tag?
You can use the layout weight of the object
Set each of the buttons to have an equal layout weight and then set each of their heights to match_parent
That should resolve your issue.