Making UI elements relative to screen size? - android

Lets say I wanted to make a relative view with two columns of buttons, left and right.
Where each button takes up exactly 20% of the screen, separated by 10%, with the remaining border on the sides. But to do this for any screen size. DP I think won't work because how do you know the DP pixel count on each different screen?
Basically how do you keep UI's relatively the same and fitting between all devices?

Short answer: LinearLayout.
Long answer is here:
Defining a percentage width for a LinearLayout?
There are also ways of getting density at runtime, but the above is easier in the long run.
Get ready for some pseudo-xml!
<LinearLayout double fill parent, vertical>
<RelativeLayout w = 0, h = 0, weight smallish>
<Button A />
</RelativeLayout>
<LinearLayout w = 0, h = 0, weight largish. horizontal>
<!-- maybe you want these to be RelativeLayout and set the buttons
as centerHorizontalInParent="true" -->
<LinearLayout w = 0, h = 0, weight whatever 20% is>
<Buttons with some padding/margins>
</LinearLayout>
<Some kind of spacer, or just pad the LLs />
<LinearLayout repeat above />
</LL>
</LL>
Edit:
If you are bent on doing alot of dynamic resizing, I have this custom class for getting screen size:
public class ScreenGetter {
private float pixHeight;
private float pixWidth;
private float dpHeight;
private float dpWidth;
private float density;
public ScreenGetter (Context context){
Display display = ((WindowManager)
context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics ();
display.getMetrics(metrics);
pixHeight = metrics.heightPixels;
pixWidth = metrics.widthPixels;
density = context.getResources().getDisplayMetrics().density;
dpHeight = pixHeight / density;
dpWidth = pixWidth / density;
}
public float getPixHeight(){return pixHeight;}
public float getPixWidth(){return pixWidth;}
public float getDpHeight(){return dpHeight;}
public float getDpWidth(){return dpWidth;}
public float getDensity(){return density;}
}
Obviously you'll need to do some math to figure out what you want at different sizes and densities. You also need to account for parts of the screen you are not using (ActionBar, etc.)

Related

Converting dp into pixels for multiple screen support

I am having a hard time to make this right.
Basically I am creating an ImageView and applying a LayoutParameter to it.
LayoutParams lp = new LayoutParams(width, height);
lp.gravity = Gravity.CENTER;
I know that width and height parameters receive pixel numbers, so I am passing them in DP and converting it to absolute pixels using:
public int convertToPixels(float dpSize){
final float density = getResources().getDisplayMetrics().density;
return ((int) (dpSize * density + 0.5f));
}
As far I know, this should make a drawable fill exactly the same area in different screens, right? Unfortunately, that is not happening at all.
Is there something wrong with these methods I am using?
These two emulators below have the same image and the same amount of DP.
Left emulator is 1.0 density and right one is 2.0. Why still does it look
so different ? Don't undertand..
Use :
public class Convert{
public static float convertDpToPixel(float dp){
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return Math.round(px);
}
}
Just use it in a static way:
float requiredPixel = Convert.convertDpToPixel(16.0);
For more info: https://developer.android.com/guide/practices/screens_support.html

Measuring margin of a "fitCenter" imageView in Android

Given a simple RelativeLayout like this:
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#0fffff">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="#drawable/img001" />
</RelativeLayout>
the left/top spacing between the layout border and the image border depends on the W/H ratio of the image being load in the imageView.
How can I know (programmatically) the real margin (width and height of the cyan area) after an image is shown in this layout?
This method will calculate the new rectangle which bounds the object after FIT_CENTER and all other related values.
It should work on all cases of object and container.
public static Rect calculateFitCenterObjectRect(float containerWidth, float containerHeight, float objectWidth, float objectHeight) {
// scale value to make fit center
double scale = Math.min( (double)containerWidth / (double)objectWidth, (double)containerHeight / (double)objectHeight);
int h = (int) (scale * objectHeight); // new height of the object
int w = (int) (scale * objectWidth); // new width of the object
int x = (int) ((containerWidth - w) * 0.5f); // new x location of the object relative to the container
int y = (int) ((containerHeight - h) * 0.5f); // new y location of the object relative to the container
return new Rect(x, y, x + w, y + h);
}
You can use FrameLayout to position the view wherever you want after using the previous method with the new x, y, width, height of the scaled object.
If you know the width of the ImageView, like this
int ivWidth = iv.getMeasuredWidth();
and the total width of the layout (your RelativeLayout), like this
int layoutWidth = yourLayout.getWidth();
then, you can easily get the horizontal margin, like this
int horizontalMargin = (layoutWidth - ivWidth)/2;
And the same goes for height.
You should call functions like getWidth and getHeight after the dimensions of your layout have been calculated, as described by Veer's and Khan's answer on How to get the width and height of an Image View in android?.
Calling getWidth or getHeight in onCreate will return 0.

Android align button programmatically

I have an Android button on a RelativeLayout which I want to animate.
The animation is currently done with a ObjectAnimator to move the button 50dp up and down on a scroll event.
The position of the button is currently calculated programmatically with
height = context.getResources().getDisplayMetrics().heightPixels
y = height - buttonheight - bottomMargin
My problem with this is, that the calculation works fine in the portrait mode, but as soon as I switch to landscape mode the distance between bottom and button is bigger than in portrait mode.
What did I miss?
Try to convert pixels to dp right before putting your button on the layout:
public static float convertPxToDp(int px, Context context) {
final float scale = context.getResources().getDisplayMetrics().density;
float dp = (float) ((px - 0.5f) / scale);
return dp;
}
This should work!
This is correct and obvious when you will change your orientation your height calculation value will also change as display matrics.heightPixel will return more height in case of landscape mode.
height = context.getResources().getDisplayMetrics().heightPixels
It will return more value and accordingly it will be recalculated. If you want to just give fixed value of space between button and bottom than you have to recheck your height calculation idea.
first try to convert pixel to dp like this :
Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics ();
display.getMetrics(outMetrics);
float density = getResources().getDisplayMetrics().density;
float dpHeight = outMetrics.heightPixels / density;
float dpWidth = outMetrics.widthPixels/density;
then i think you must change your algorithm in landscape mode
Converting to dp did not work.
So my solution is to wrap a RelativeLayout around my button, and animate the button relative to its parent, which is fixed.
<RelativeLayout android:layout_width="56dp"
android:layout_height="85dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="13dp">
<Button
android:id="#+id/button"
android:layout_marginTop="10dp"
android:layout_width="56dp"
android:layout_height="56dp"/>
</RelativeLayout>

Image layout not working correctly

I am setting an image programatically so it looks like circle but it looks like oval shape in some devices.
my code is-
int circleLeft = (int) (width * 3.3) / 100;
circleLayoutParams.setMargins(circleLeft, (int) (height * 0.29),
circleLeft, (int) (height * 0.18));
circleMenu.setLayoutParams(circleLayoutParams);
xml-
<com.example.converter.view.CircleLayout
android:id="#+id/main_circle_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:background="#drawable/glow_circle"/>
i have put images in drawable folder.what is wrong with this code.is it image size problem?
I encountered same problem in my app. It is because variation of PPI and Screen size of different devices. I solved it by getting screen size. It can be done by following code:-
//method to get screen size
public ArrayList<Integer> GetDeviceScreenSize()
{
ArrayList<Integer> size= new ArrayList<Integer>();
if((android.os.Build.VERSION.SDK_INT >= 13)){
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int w = metrics.widthPixels;
int h = metrics.heightPixels;
size.add(0,w);
size.add(1,h);
}else{
Display display = ((WindowManager)ctx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
size.add(0, width);
size.add(1,height);
}
return size;
}
After you get device screen size through this method, you can set height and width of some part of height and width you got from this method. It should be like:-
ArrayList<Integer> size= GetDeviceScreenSize();
float width = (( (float)size.get(0))/320)*135;
int circleLeft = (int) (width * 3.3) / 100;
Remember, you'll have to try dividing and multiplying the device width and height with different units to get the exact size that you want, but once you get it, It will work on all devices, no matter what is there screen size.

How to programatically set the width of an Android EditText view in DPs (not pixels)

I'm dynamically generating a grid of EditText views in code based on a specified number of rows and columns. I want each of the EditText views to be the same width (e.g., 100dp).
Although I can set the size of the views with either setWidth or by creating a LayoutParam object, I only seem able to specify the value in pixels. I instead want to use the DP (density independent) units, similar to what I've done using an XML layout.
How can this be done in code?
I have a method in a Utils class that does this conversion:
public static int dip(Context context, int pixels) {
float scale = context.getResources().getDisplayMetrics().density;
return (int) (pixels * scale + 0.5f);
}
float value = 12;
int unit = TypedValue.COMPLEX_UNIT_DIP;
DisplayMetrics metrics = getResources().getDisplayMetrics();
float dipPixel = TypedValue.applyDimension(unit, value, metrics);
Using the below code i was able to do it.
int width = (int)
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, (100)your Size
in int, getResources().getDisplayMetrics());

Categories

Resources