Setting button images at run-time - android

I'm finding Android's choice of image resources for buttons based on screen-density to be unhelpful.
I'm developing an app for kids, and so I want it to have nice big obvious buttons, but at the same time I have to limit myself to the available screen real-estate.
Essentially I want to use image sizes appropriate to the screen-size that I have, not to it's density.
For example, lets say I want to fit 5 buttons down the side of the screen in landscape mode. I'd like to do something like this..
Get the height of the screen in PIXELS.
Calculate the height of each button (hButton), allowing for some space in between.
Load the appropriate image resource. I.e. the smallest one that is at least hButton pixels.
Scale the image to be hButton pixels high.
Something like that.
Does Android have a nice way of doing this, or do I have to code that myself? How do I access the appropriate images? (most of my buttons use two images - Up and Down)
Thanks
EDIT:
It seems I wasn't clear enough in my question. I don't need to know how to lay out buttons, and I have a good understanding of how Android chooses images based on density - THAT is the problem.
Consider these two devices -
1/ Galaxy I9000 phone - screen size 4" HDPI
2/ Samsung Tab 3 tablet - screen size 7" HDPI
Because both have the same screen density, both will show images at the same physical size. An icon that is 1" square on one will be 1" square on the other. THAT is the problem. I want the buttons to be proportional to the screen size.
I could try using size specific resources (e.g. drawable-small), but then there will be issues between small devices of different densities, which would then mean creating lots more directories, which seems like a bad idea.
I leaning towards putting a variety of sizes in the no-dpi directory, and then loading as needed.

you can ask you button how bit it is
int hButton = imageButton.getHeight()
then you can get the height of the button in the same way and so some simple school math:
getHeight()/buttonCount+(buttonCount*padding)
load the biggest image you have got and scale it down to your needs, since you don't know how big it is, unless you map it yourself. By that I mean that you can build something like a utils class that contains a map with the imageNames and their size in px

The layout XML in Android is very flexible and powerful. You can layout your buttons dynamically like below.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="10dp"
android:layout_weight="1"
android:text="Button A"/>
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="10dp"
android:layout_weight="1"
android:text="Button A"/>
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="10dp"
android:layout_weight="1"
android:text="Button A"/>
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="10dp"
android:layout_weight="1"
android:text="Button A"/>
</LinearLayout>
As for image resources, if you think the standard Android image resource selection is not helpful, I'm sure you are misunderstanding something. It is not about the size of buttons. It is about the density of images.
If you are thinking about using simple shapes as buttons, you may want to know about ShapeDrawables.
https://developer.android.com/reference/android/graphics/drawable/ShapeDrawable.html
https://developer.android.com/guide/topics/resources/drawable-resource.html#Shape

for get screen runtime height and width
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
for button height
int buttonHeight = hButton.getHeight():
then get the smallest button height
calculate image height and set it as image resource.
if u r asking for image resizing code
then chek here.
Bitmap yourBitmap;
Bitmap resized = Bitmap.createScaledBitmap(yourBitmap, newWidth, newHeight, true);

Related

How to create background images for multiple screen sizes and densities

I'm currently working on an app that will run on different smartphones, and we have our background image that will appear on all of the activities of the app.
Currently, all parent layouts are ConstraintLayout, and the background images are set in an ImageView that covers the entire screen. However, on some screen sizes, setting the ImageView on fitCenter simply doesn't work because either:
The screen can be too wide and the sides have white bars.
The screen can be too narrow, and a portion of the left and right sides of the background image get cut.
I know I can run a different scaleType, but that runs the risk of screwing up the original aspect ratios of the background image.
Are there design rules for this?
I've looked but I've only found this from Android Dev's site. It has most of the screen sizes noted down, but not the aspect ratio.
What's the best way to go about this?
Should we make one for the largest size in each screen density and just hope that the same screens in the same screen density range scale it properly? Or just one per dimension? Or just one per aspect ratio?
i usually using ConstraintLayout to maintain image ratio
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintGuide_percent="0.5"
android:orientation="vertical"/>
<ImageView
android:id="#+id/img_poster"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="3:4"
app:layout_constraintEnd_toEndOf="#id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
with this as long as the image ratio is 3:4, it wouldn't cropped the actual image

Incorrect image size on different screen size

I have a screen on which I need to display a number of images inside a horizontal LinearLayout.
I designed it for an xhdpi. I set the sizes of each ImageView to 100dp, and on an emulator (xhdpi 768x1280 4.7" screen) it looks something like
this while on a tablet emulator (xhdpi 1534x2048 9" screen) it looks like this.
In the latter, the images aren't scaled properly to look like it does on the smaller screen.
Is there a way to make it look the same on both screen sizes?
to make your layout adjust on different screen you need to design it to be responsive. Yes like what G.Dator said, you can use weight attribute. Here's the example :
<LinearLayout
android:layout_height="200dp"
android:layout_width="match_parent"
android:orientation="horizontal">
<ImageView
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_weight="25"/>
<ImageView
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_weight="25"/>
<ImageView
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_weight="25"/>
<ImageView
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_weight="25"/>
</LinearLayout>
Please let me know if you have further question.
Actually, the image is the same size in 2 devices. The problem is the difference between your dp width of your phone (384dp) and your tablet (767dp). There're few ways to resolve it:
using multiple layout files for sw360 and sw720. You can check this Google Guide
Using the same weight for all your ImageView with adjustViewBound=true to keep your image ratios.
Using code to set your ImageView size programmatically.
In addition to implementing a responsive layout structure (like what #Bhimbim mentioned), there is a library (https://github.com/intuit/sdp) which can be useful when you want to code once and use it on multiple different devices, it offers you sdp unit instead of dp which helps your view to scale better.
Example:
layout_width="#dimen/_30sdp"
layout_height="#dimen/_30sdp"
(Sorry i couldn't comment as i have registered recently).

Too much padding around Button's Text

I have a fragment that takes up the whole screen, with Buttons and a SeekBar which scale to fit it, as well as fixed size TextViews. I use linear horizontal and vertical layouts with weights to achieve this.
The problem is I can't get the button text large enough without it making the buttons expand in size. For some reason, any text size greater than about 35sp makes the button expand, no matter how big the button is. This screen shot shows the button sizes have plenty of space for the text:
Ideally I would like the "<" and ">" characters to fill the buttons. (I was going to programmatically change the font size according to the button size, e.g. for different screen sizes) but haven't tried since I can't even get the static layout to work.
Edit: I would like to avoid images, since if I had 15 buttons, and 8 buckets, that would be 120 images I need!
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/VerticalLinearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="0dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="0dp" >
<!-- ........ -->
<TextView
android:id="#+id/trackTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="2" >
<Button
android:id="#+id/trackPreviousButton"
style="android:buttonBarStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="#string/button_track_previous"
android:textSize="35sp" />
<Button
android:id="#+id/trackNextButton"
style="android:buttonBarStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="#string/button_track_next"
android:textSize="35sp" />
</LinearLayout>
<SeekBar
android:id="#+id/seekBar"
style="#style/tallerBarStyle"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<!-- ........ -->
</LinearLayout>
I have tried adding the following line to Buttons, but it only makes a small difference, if any:
android:padding="0dp"
Advice on getting the font height to fill the buttons without padding is my primary question. (But if the problem of dynamically sizing the text to fill the buttons for different screen sizes can be solved at the same time, that would be brilliant).
Edit: it turns out that using larger font sizes affects the effect of weighting for the height of the linear layouts, which is why there seemed to be padding - larger font size increased the button size, not because of the padding (which was 0) but because of the weighting
Button is not the right widget for your purpose. Use an ImageButton (or even an ImageView) instead.
I was going to programmatically change the font size according to the button size, e.g. for different screen sizes
Your current approach will land you in a lot of problems regarding proper sizing of your UI components. Given the plethora of android devices out there, screen size is just one aspect of the problem. You will also be dealing with varying screen densities. Best approach would be to put size/density buckets (drawable-mdpi/hdpi/xhdpi) to use. Help android in working for you.
Use drawables to indicate next and previous. If you're worried about the drawables being too small for tablet screens, create appropriate drawable resources/folders:
// Phones - 4 to 7 in
drawable-ldpi
drawable-mdpi
drawable-hdpi
drawable-xhdpi
drawable-xxhdpi
// Tablets - 7 to 10 in
drawable-large-mdpi
drawable-large-hdpi
// Tablets - 10 in
drawable-xlarge-mdpi
This list may not be exhaustive. Consider doing some research before finalizing your size/density buckets.
Output:
# drawable size 32dp:
# drawable size 64dp
Now it becomes quite straightforward - finalize drawable size by visual inspection on a phone, on a 7 inch tablet, and on a 10 inch tablet. Then use density scales to create and store appropriately sized drawable in the folders I mentioned above. Let android deal with what bucket to pick from.
The problem is by default buttons include a minHeight attribute. I had the same problem and solved it with just a single line of code in my XML file:
android:minHeight="0dp"
There is a quick and easy solution to your problem!
Auto-sizing text in Android is fiendishly difficult in my experience, especially when padding is involved. I would advise that instead of using an angle bracket character, you use a drawable - there are plenty of arrow icons available online - and an ImageButton. For example:
<ImageButton
android:id="#+id/trackNextButton"
style="android:buttonBarStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="#drawable/left_arrow"
android:scaleType="fitXY"
android:padding="0dp"
android:textSize="35sp" />
By using different ScaleTypes you can alter the stretching of the image. Even better, the screen sizes problem is solved because you can add different drawables for different densities.
Use minWidth="0" or "1" to reduce the horizontal padding on a text Button.

density pixels(dp) is not working fine for all resolutions

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/gray"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#color/darkgray"
android:gravity="center"
android:orientation="horizontal" >
<Button
android:id="#+id/attenders"
android:layout_width="110dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:background="#color/gray"
android:layout_marginRight="8dp"
android:text="Attenders" />
<Button
android:id="#+id/send"
android:layout_width="110dp"
android:layout_height="40dp"
android:layout_marginLeft="8dp"
android:layout_gravity="center"
android:background="#color/gray"
android:text="Send IM" />
</LinearLayout>
</LinearLayout>
this is my code but the dp is not working fine for all screen resolutions.
suggestions plz, plz tell me if i am doing anything wrong
problem is that when i use dp for setting height or width of a button
it does not gets fits to all resolutions i-e on small screens it looks
big and on big screens it looks small, whereas i know that when we use
dp for setting height and width of any component it automatically
converts/adjusts according to screen resolution
What I understand from this is that you thought using dp instead of px (or in, or cm) will magically work such that they will all have the same physical size on all devices, regardless of that device's density (ppi).
That's not the case.
dp, or dip, as explained here, is
An abstract unit that is based on the physical density of the screen.
These units are relative to a 160 dpi (dots per inch) screen, on which
1dp is roughly equal to 1px.
A screen with more dpi (denser, meaning more pixels are packed into a square area of the screen), will essentially draw a physically smaller image compared to a screen that has 160dpi when tasked to draw the same, say, 100x100 dp image.
When running on a higher density screen, the number of pixels used to
draw 1dp is scaled up by a factor appropriate for the screen's dpi.
Solution
There are two easy ways to have your app look proportionally the same on different screen sizes.
The first is to use different layout folders (layout-ldpi, layout-mdpi, etc.). This technique is well-explained here. A much more recommended way would be to use different style values for each density, so you can still maintain one layout folder and refer to the styles instead for measurement. This can be done using the same technique, but instead you will have values-ldpi, values-mdpi, etc. This is useful for having standard sized UI elements across screen sizes.
The other way is to use weights all over your layout. Weights adjust automatically regardless of screen size of density. This will help a lot if you want, say, three columns that have varying width -- you can easily use weights to tell the layout that column A needs to occupy 40% of the available width of the screen, and B and C will have 30% each. This is useful for having a standard layout across screen sizes.
A clean-looking, nicely coded app will implement both.
It is beacause you are giving fixed dimensions which can only be fit for a particular screen size which you are using. So try avoiding static dimensions and make use of match_parent,wrap_content and fill_parent so that you can get your layout fit for every screen size.

What about percentage usage?

So, i'm thinking about the usage of percent, example, in margins.
We can use overlay to separate our layout by dpi sizes, but why can't we use percentage?
Something like that:
Display display = getWindowManager().getDefaultDisplay();
float width = display.getWidth();
float height = display.getHeight();
//20% of left margin
float imageMarginLeft = ( width * 20 ) / 100;
And then set this margin to the image, or whatever element.
Is this bad? I just wanna discuss about it.
Thanks.
LinearLayout can do percentages by using weight.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="100">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="20"
android:text="Button" />
</LinearLayout>
Weight based layouts hinder performance if you use a lot of them, especially so when they're nested. Doing it programmatically will likely impact layout time as well.
Edit
Since you're looking for discussion, I would suggest that percentage based layouts are bad in general. The problem is that physical screen size varies so much with Android. Half the screen on an Incredible is much different than half the screen on a Galaxy S III, which is much different from half the screen on a Nexus 7, etc. The benefit of using dp units is that they're related to the physical size of things on the screen. It keeps buttons from being tiny (and hard to select) on tiny screens and it keeps them from being enormous (and ugly) on large screens.

Categories

Resources