I am developing a feature for my app where the user can click on buttons that are placed within an image background. The problem: I need to place the buttons to a particular location within the image so it doesn't look displaced and works dynamically to different kind of devices' resolutions. Here's an image example:
I would like to place the buttons exactly where these rounded squares are. How can I be sure they will look exactly the same in different devices as well? I might need to place some text above each button. The buttons they have to be clickable and I have some animation over the buttons to allow the user to know when the button is being clicked. Any lead is much appreciated. Any feasible solution could be the accepted answer.
The game clash of clans have something similar:
This is exactly what I am trying to achieve!
Since there are a lot of Android devices, in practice you can't show buttons exactly in all devices. You can use a RelativeLayout or a LinearLayout to assure that the top title will be above buttons
There will be a parent view with two children : One is for the title, and another is for all the buttons
If you use a RelativeLayout, you could place the buttons at any point within the Image.
Just make sure that you use DP units of measurement and have size appropriate images for each density.
A short example:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button android:layout_marginLeft="10dp"
android:layout_marginTop="10dp" />
<Button android:layout_marginLeft="30dp"
android:layout_marginTop="30dp" />
<Button android:layout_marginLeft="10dp"
android:layout_marginTop="50dp" />
</RelativeLayout>
I found a hacked solution by using the percentages of the width and height of the device. It worked for tablets and 2 more different screen size devices.
int w = front_layout.getWidth();
int h = front_layout.getHeight();
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
int top = convert(h * 0.248f);
int bottom = 0;
int left = convert(w * 0.186f);
int right = 0;
params.setMargins(left, top, right, bottom);
btn1.setLayoutParams(params);
private int convert(float value) {
return (int) Math.ceil(value);
}
The only downside of it is that I have to find the exact percentages by try and error. A better solution will score my accepted answer!
Related
For my GUI i use the RelativeLayout and want to keep it as it is the best for different screeen resolutions.
For example i have this Background, where i want to put an ImageView exactly over the TV-screen (to show some pictures on the TV).
I want this to work in different screen resolutions.
How can i achieve this? Or is this even possible? Examples are welcome :)
My Background Image:
If I were you, I would separate the TV image from the background and make it a new ImageView. Then you can set the position of TV-Screen ImageView regarding to the TV ImageView.
Well i think you can try this
<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"
tools:context=".MainActivity">
<RelativeLayout
android:id="#+id/back"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/ic_launcher"></RelativeLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="?attr/actionBarSize"
android:src="#drawable/ic_launcher"
android:layout_alignTop="#+id/back"
android:layout_alignRight="#+id/back"/>
</RelativeLayout>
But i think there could be an issue with different resolution try this and let me know if it worked.
You can have your TV as a PNG. Carve out the screen from this image. This will make the TV image TRANSPARENT for the screen(red outlined portion)
Next, your images/screen-slides must be exactly same as the TV image in terms of width and height. However, the actual content of the image/screen-slides must only be in the hollow portion.
I think i figured out how to do this.
At first i changed the background-picture from a Layout-Background to an ImageView:
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/imageView"
android:src="#drawable/background1"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:scaleType="fitXY" />
Then i can set the TV-image relative to the Background-ImageView's f.e. top and right margin. (looks hardcoded like this)
<ImageView
android:layout_width="125dp"
android:layout_height="85dp"
android:id="#+id/imageView1"
android:src="#drawable/tvImage"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="44dp"
android:layout_marginRight="169dp"
android:layout_marginEnd="169dp"
android:scaleType="fitXY" />
Basically there are now two things i have handle, to make the TV-image fit when changing the screen resolution:
1) the width and height of the picture.
2) the position of the picture.
To find out 1):
My Background is f.e. 500x250dp.
In an Image program i measured the size i need for the TV-image: 125x85dp.
Now i can calculate the width and height back depending on the background size.
500/125 = 4 for width calculation
250/85 = 2,9 for height calculation
So if the Screen changes for example to 800x400dp the width and height for the TV-image an be calculated like this:
800 / 4 = 200dp
400 / 2,9 = 137dp
So my TV-image should have a size of 200x137
To find out 2)
Again i have to calculate like in Point 1). Find out the position of the TV-screen and then set the layout margins according to the calcualtions. I havent implemented this point yet, so i can't explain more, but i think you get what i want to say. If not feel free to ask :)
And in the end, i can setup the TV-image with this code (hardcoded values should be the calculated variables!)
RelativeLayout.LayoutParams layoutPar = (RelativeLayout.LayoutParams) tvImage.getLayoutParams();
layoutPar.setMargins(0,88,210,0); // or whatever
layoutPar.height = 137;
layoutPar.width = 250;
tvImage.setLayoutParams(layoutPar);
Disclaimer: I rewrote most of this question, including its title, because I partially figured it out.
I'd like to maximize the size of the button on all screen sizes, because it looks silly when it is to small. It should look similar to this:
(Sadly, I cannot include a picture, because my reputation is too low.)
But if I turn the orientation of the device, for example, the button matches it's parents width, becoming ugly proportioned.
(Sadly, I cannot include a picture, because my reputation is too low.)
I now have figured out how to get the dimensions of its parent (the LinearLayout) and how to set the button's size. I used the following code:
window is the ID of the LinearLayout containing (only) the button.
this code is located in the onCreate()-method of the MainActivity.
// Adapt button's size to smaller dimension:
final View window = findViewById(R.id.window);
window.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int width = window.getMeasuredWidth();
int height = window.getMeasuredHeight();
int smallerSize;
if (width < height) {
smallerSize = width;
} else {
smallerSize = height;
}
View button = findViewById(R.id.fartButton);
button.setLayoutParams(new LinearLayout.LayoutParams(smallerSize, smallerSize));
window.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
The problem with this approach is, that it doesn't seem to account for padding. The button get's cut off a little bit on the smaller side (in portrait mode its width, in landscape mode its height).
Interestingly, the image inside the button fits the window perfectly. If for example the height gets cut off a bit, the image still is visible in its full height (only some "extra" parts of the button get cut off, like a little border and shadow).
Is there a way to get the maximal size of the button, which would be the size of the window, but without action bar and minus padding, to prevent any part of the button to get cut off?
Your example above "should look similar to this:" does not seem to have loaded, illustration would help...
But you can manage screen proportions pretty well using android:layout_weight
I'm not sure I'm envisioning your exact needs, but you might try something like this:
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="X"
android:text=" "
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="button"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="X"
android:text=" "
/>
</LinearLayout>
where different values for X would control the horizontal aspect ratio for your button in a view.
I just figured it out. Was much easier than I thought. Thanks to everyone who answered, though. It helped me a lot on the way!
The padding that is applied to the window can easily be accesed through the getPadding...() methods. I just needed to adjust the part where the width and height get saved:
int width = window.getMeasuredWidth() - window.getPaddingLeft() - window.getPaddingRight();
int height = window.getMeasuredHeight() - window.getPaddingTop() - window.getPaddingBottom();
I thought, that even by manually excluding the padding, the highlight when pressing the button would be cut off, because it is a bit bigger than the button itself. But this is not the case and it works perfectly. The button now gets displayed in its whole glory. ;)
You can overload your onMeasure method to always return a square.
Create a class that extends to Button and include this
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
setMeasuredDimension(size, size);
}
Not sure how this will work if you give exact dimensions but it should work if you set width, height to match parent
I think the solution will be quite obvious, but as long as I'm rookie in android forgive me :)
I want to place some picture on the right upper side of the view, and a textview, which will fit the rest of the view. Here's what I've done:
<?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"
android:orientation="vertical" >
<ImageView
android:id="#+id/logo_in_listing"
android:layout_width="100dip"
android:layout_height="100dip"
android:layout_alignParentRight="true"
android:layout_marginRight="11dip"
android:layout_marginTop="11dip"
android:background="#drawable/border_for_imageview"
android:src="#drawable/facebook_logo" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/someString"
android:id="#+id/textview1"
android:layout_toLeftOf="#id/logo_in_listing"
android:layout_margin="3dip"/>
</RelativeLayout>
Here's what I get:
My questions:
1) How to make the textview fit also the lower part of imageview? I don't want that space to be left unused.
2) As you see, I've used dips for placing ImageView. What would you recommend in this case? I mean, how to write in a way, that it will be same for all screen sizes? Or maybe dip is OK?
You have to use Spanned interface. Here's a good example
1) How to make the textview fit also the lower part of imageview? I
don't want that space to be left unused.
Flow around text isn't possible with currently available layouts. However you can display content as HTML in a WebView or even spanned-HTML in a TextView.
2) As you see, I've used dips for placing ImageView. What would you
recommend in this case? I mean, how to write in a way, that it will be
same for all screen sizes? Or maybe dip is OK?
Dip is for device independent pixels. On different screen sizes, 1 Dip will take different number of pixels, but visually, 1 dip will appear almost same to eye on all screens.
If You donĀ“t want to left space, You could use spannables. For example:
int TEXT_START = 0;
int TEXT_END = yourTextView.length();
Spannable span = (Spannable) yourtextview.getText();
span.setSpan(new AlignmentSpan.Standard(Alignment.ALIGN_CENTER), TEXT_START, TEXT_END,
0);
For Your second Question: use dp instead of dip.
I have an android application which can playback audio/video and show pictures.
For videos I want to overlay a play button on top of the preview image and also in list views..
Right now how I'm doing it is with an ImageView in xml, and then the drawable is a layer layer-list which I define programmatically because one of the images is dynamic, the play button is static of course. I want to align the play button 10px from the bottom, and centered horizontally.
My ImageView is defined like this (in xml)
<ImageView
android:id="#+id/EvidencePreview"
android:layout_width="267dp"
android:layout_height="201dp"
android:scaleType="centerCrop"
android:layout_margin="3dp"
android:layout_gravity="center_horizontal|center_vertical"/>
The ImageView is part of a form where the user can edit title and other information.
Then in my activity now I create the layer list like this:
Resources resources = mContext.getResources();
Drawable playOverlayDrawable = resources.getDrawable(R.drawable.play_overlay_large);
Drawable[] layers = new Drawable[2];
layers[0] = Drawable.createFromPath(tb.filePath);
layers[1] = playOverlayDrawable;
LayerDrawable layerDrawable = new LayerDrawable(layers);
ViewGroup.LayoutParams lp = iv.getLayoutParams();
int imageHeight = lp.height;
int imageWidth = lp.width;
int overlayHeight = layers[1].getIntrinsicHeight();
int overlayWidth = layers[1].getIntrinsicWidth();
int lR = (imageWidth - overlayWidth) / 2;
int top = imageHeight - (overlayHeight + 10);
int bottom = 10;
layerDrawable.setLayerInset(1, lR, top, lR, bottom);
iv.setImageDrawable(layerDrawable);
This only works when the orientation of the image is horizontal.
Keep in mind that the image/thumbnail is the MINI_KIND which means its supposed to be 512 x 384 but I'm seeing that it actually isn't the size.. On my phone they are either 480x800 or 800x480 depending on the orientation the camera was in..
Since my layout width/height is pre defined I just want a way to keep the play button layer from scaling at all and align it the same way everytime..
The other obvious way to do this would be to use a relative layout (or perhaps a frame layout?) but I was hoping to avoid that since I'm using the same code for displaying both images and videos (both of which have an image thumbnail preview -- but only videos should have the play button on them).
Any idea how to align the layers with a layer list, or alternatives that would work just as well or better?
I ended up using a FrameLayout like this:
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:layout_gravity="center_horizontal|center_vertical" >
<ImageView
android:id="#+id/MediaPreview"
android:layout_width="267dp"
android:layout_height="201dp"
android:scaleType="centerCrop"
android:src="#drawable/loading" />
<ImageView
android:id="#+id/VideoPreviewPlayButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:layout_gravity="center_horizontal|bottom"
android:visibility="gone"
android:src="#drawable/play_overlay_large" />
</FrameLayout>
Then I just set the visibility to View.VISIBLE to the preview play button for videos and left it gone for photos.
For my list view I used the layer list method shown above because all of the thumbnails were the same dimension. Hope this helps someone else!
notice that the layout_gravity on the ImageView with id VideoPreviewPlayButton puts it at the bottom centered horizontally, and the 10dp paddingBottom moves it up a bit from the bottom.
Consider using RelativeLayout as the container for your views. It gives you freedom of placing child views. You could bind your button to the right or top edge of your imageview.
I have a RelativeLayout which holds an ImageView and an ImageButton. The ImageView serves as an container for a background image. Now I'm trying to set the button at a fixed position so that it always appears on the same position on the background image.
Here is the layout file I'm using:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relativeLayout1" android:layout_height="match_parent"
android:layout_width="match_parent" android:gravity="center_horizontal">
<ImageView android:src="#drawable/bg_1" android:id="#+id/imgView"
android:adjustViewBounds="true" android:layout_height="match_parent"
android:layout_width="match_parent" />
<ImageButton android:layout_width="120dp"
android:background="#drawable/button_1" android:layout_height="30dp"
android:id="#+id/imgButton" android:layout_marginLeft="100dp"
android:layout_marginTop="170dp" />
</RelativeLayout>
As you can see I've tried positioning the button with it's left-/top-margin using dp as unit, but this doesn't work. Since the background image is beeing scaled down/up, the position would have to be dynamic in some kind of way.
I understand that absolute positioning, with pixel-values for x-/y-position, is something that won't work on Android, like it is explained here. I still need to solve this and am not sure how.
Would I have to calculate the values for left-/top-margin (not sure how that would be) and then set them with something like this?
final float density = getResources().getDisplayMetrics().density;
int width = (int)((float)120 * density);
int height = (int)((float)120 * density);
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(width, height);
rlp.leftMargin = newMargin;
rlp.topMargin = newTopMargin;
ImageButton imgButton = (ImageButton) findViewById(R.id.imgButton);
imgButton.setLayoutParams(rlp);
Hope I didn't forget something ...
//EDIT:
I was thinking, the reason for the issue might be, that the scaled image has different "borders", depending on the screen size.
With an image at a 1:1.6 ratio on a HVGA screen I have black bars on the left and right, whereas on a WVGA screen the bars are on the left. Considering I'm using the default scaling. I will look into it and post again, if necessaray...
Why scaling happens? Because of different dpi on different devices? Do you have different drawabled for different dpi settings? If it isn't just dpi issue and you want to scale that background image freely then you can't do the job using standard layouts. You should implement a custom one.