set remaining height to view at runtime - android

I am writing an application where need to assign rest of screen space to view.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/txtView_1"
android:layout_width="match_parent"
android:layout_height="100dp" />
<TextView
android:id="#+id/txtView_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Test Text" />
</LinearLayout>
and to set runtime I am using following:
private void process() {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int txtView1Height = txtView_1.getHeight();
LayoutParams layoutParams = (LayoutParams) txtView_2.getLayoutParams();
layoutParams = new LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
(metrics.heightPixels - txtView1Height));
txtView_2.setLayoutParams(layoutParams);
}
But here it's taking not exact same remaining height..since textview sting not placing in center(this is how I simply check)...it might be mistaken to set height in pixel.
Any suggestion here?

You can use weight xml parameter
<TextView
android:id="#+id/txtView_2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:gravity="center"
android:text="Test Text" />
or in your case simple set height to match_parent
android:layout_height=match_parent
To check even more simpler set gravity to bottom. If you still want to do this programmatically dont use DisplayMetrics to get height (Action Bar and Software Buttons are also a part of display) use your root LinearLayout height. Also check if txtView1Height is not 0 (maybe view was not drawed at the moment of calculation)

Related

fit size of parent layout

I have a simple linear layout and want to divide the screen into two equally sized parts.
In the upper one, I want to put a SurfaceView that has exactly the same size as its parent, i.e. half of the screen. Unfortunately, it always either takes all the screen or nothing (depending on the configuration).
Why is that and how can I change it?
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="2"
android:orientation="vertical">
<LinearLayout android:id="#+id/layoutUpperDaw"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#192832">
<com.example.MySurvfaceView
android:id="#+id/id_mySurfaceView"
android:layout_width="match_parent"
android:layout_height="0pt"
android:layout_weight="1"
OR
android:layout_height="match_parent"
>
</com.example.MySurvfaceView>
</LinearLayout>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#193222">
...
</LinearLayout>
</LinearLayout>
When you provide weight you have to set height or weight to 0dp as below.
<LinearLayout android:id="#+id/layoutUpperDaw"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#192832">
and
<com.example.MySurvfaceView
android:id="#+id/id_mySurfaceView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
Update: Answer above is correct about weight usage, make sure either hight or width is 0dp at all places where you used weight.
You don't really need nested LinearLayout. Following should work.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.MySurvfaceView
android:id="#+id/id_mySurfaceView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
</com.example.MySurvfaceView>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#193222">
</LinearLayout>
</LinearLayout>
Programmatically:
Find the parent layout.
GridLayout gridLayout =(GridLayout)findViewById(R.id.gridLayout);`
Get measured height and Width of parent.
int height = gridLayout.measuredHeight();
int width = gridLayout.measuredWidth();
3.Calculate child view height and width.For example two child each taking 50% of height in the parent but taking full width of parent:
int childHeight = height/2;
int childWidth = width;
4.Get instanceof LayoutParams depending on parent type.
GridLayout.LayoutParams params = new GridLayout.LayoutParams();
5. Set height and width on layout params.
params.width = childWidth;
params.height = childHeight;
6.Create child view and set Layout params.
ImageView imageview = new ImageView();
imageview.setLayoutParams(params);
7.Add child View to parent.
gridLayout.addView(ImageView);

Position textareas and buttons in % of the screen

I started yesterday with developing for Android. I already know Java, so you don't have to explain general Java things for a beginner.
Information:
IDE: Android Studio (latest)
Minimum API: 10
I want to code a fun app where the user types a countdown in a C4 Bomb UI and the bomb's ticking after the input.
I have now the problem that I can not position the elements margin in % of the screen.
Here's an image with the text field, buttons and the margins I calculated with the image dimensions.
How can I do this?
You could use the following algorithm:
//declare two variables for width and height of the screen, that you could use later
private int screenWidth;
private int screenHeight;
//first get the size of the screen - call this method in the onCreate method of your Activity
private static void getScreenResolution(Context context){
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
}
//then use dynamically positioning of the elements as you use LayoutParameters for your elements like this:
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); //width, height
params.setMargins(11*screenWidth/100, 34*screenHeight/100, 0, 0);//left, top, right, bottom - here you could use the % like 11% from screenWidth = 11*screenWidth/100 (all the digits are for example)
//get the element which you want to be positioned at the current position (for example an ImageView)
ImageView myImage = (ImageView)findViewById(R.id.myImage);
myImage.setLayoutParams(params);
P.S. If your layout is RelativeLayout, you should use RelativeLayout.LayoutParams instead of Linearlayout.LayoutParams (just change the word)
You could use weighted layout(empty layout on left and right side of your image then wrap it again for vertical). Let say I want to create an image with margin 25% on both side, then the weight for each empty layout is 1, and for the image is 2.
UPDATE:
here's a little example, the "view" component is just a placeholder for margin
The top and bottom margin is 25% of height, while the left and right margin is 20% of screen's width.
<LinearLayout 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:orientation="vertical" >
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2">
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3" />
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />

How to rewrap_content for an android view?

I have a list view with two textviews, one of them has its visibility set to View.GONE by default, so the listview does the wrap_content for the minimum size, the size of the listview with all the secondary textviews GONE, when I turn one of them View.VISIBLE (by clicking on the item), the height stays the same height it calculated from the very first wrap_content when it was first viewed. Tried different approaches that I read but none of them worked on my case such as
mListView.invalidate();
mListView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)mListView.getLayoutParams();
params.height = params.WRAP_CONTENT;
is there any way to force the view to recalculate the height wrap_content value after each click?
Edit1:- This is my listview layout (two is the one that is set to GONE)
<?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="wrap_content">
<TextView
android:id="#+id/list_item_one"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Question?"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:paddingTop="8dp"
android:paddingBottom="4dp"
android:textStyle="bold"/>
<TextView
android:id="#+id/list_item_two"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Answer!"
android:layout_below="#id/list_item_one"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:paddingBottom="4dp"/>
</RelativeLayout>
You should call requestLayout() when you want to re-calculate the dimensions. That is according to this neat view lifecycle:
Original link here.

Change margins programmatically doesn't work as expected

I have a GUI where Initially margins of innerLayout are 0,10,0,100 and in my intention hideinfoarea() should remove the infoLayout and change the margins in 0, 10,0,10 and showInfoarea() should restore the initial margins and show infoLayout again.
Unfortunately when I set these margins some Layout become not well shown, for example the title is too close to mainLayout, and a piece of image will be covered by infoLayout when I re-enable it.
despite in my test with layout editor the margins are perfect.
In adition when I invoke showInfoarea() why the layout margins aren't restored to the original conditions, if I simply reverse the operation of hideInfoarea()?
Here my code
RelativeLayout mainLayout;
LinearLayout innerLayout;
public void hideInfoarea(){
mainLayout = (RelativeLayout) findViewById(R.id.mainContainer);
innerLayout = (LinearLayout) findViewById(R.id.innerLayout);
mainContainer.removeView(infoLayout);
//adjust margins
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) innerLayout.getLayoutParams();
params.setMargins(0, 10, 0, 10);
innerLayout.setLayoutParams(params);
}
public void showInfoarea(){
mainLayout = (RelativeLayout) findViewById(R.id.mainContainer);
innerLayout = (LinearLayout) findViewById(R.id.innerLayout);
mainContainer.addView(infoLayout);
//adjust margins
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) innerLayout.getLayoutParams();
params.setMargins(0, 10, 0, 100);
innerLayout.setLayoutParams(params);
}
Here the XML
<!-- The main content view -->
<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"
android:padding="5dp"
android:gravity="fill_horizontal|fill_vertical"
android:background="#color/Platinum"
android:id="#+id/mainLayout">
<TextView
android:id="#+id/txtTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="Sample"
android:textSize="12dp"
android:layout_marginBottom="10dp"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:id="#+id/innerlayout"
android:layout_marginTop="10dp"
android:layout_marginBottom="100dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:id="#+id/imageView"
android:scaleType="fitXY"
android:src="#drawable/rectangle"
android:layout_marginBottom="100dp"
android:layout_marginTop="10dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="400dp"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:background="#drawable/background_label_mm"
android:layout_centerHorizontal="true"
android:orientation="vertical"
android:id="#+id/infoLayout"
android:layout_margin="5dp">
</LinearLayout>
</RelativeLayout>
<!-- The navigation drawer -->
<ListView
android:id="#+id/drawer"
android:layout_width="320dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#F3F3F4"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"/>
</android.support.v4.widget.DrawerLayout>
Be carefull, as you can read one the Reference: setMargins(int left, int top, int right, int bottom) method use px and your layout use dp. You have to do a conversion like:
// where "dp" is your value dip
int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
(float) dp, getResources().getDisplayMetrics());
// then set your margins
params.setMargins(0, px, 0, px);
See this answer: What is the correct way to specify dimensions in DIP from Java code? and the reverse one: Converting pixels to dp.
Also, you can read another thing one the Reference:
Sets the margins, in pixels. A call to requestLayout() needs to be done so that the new margins are taken into account.
Hope this helps.

layout_height should be a function of layout_width

Assuming portrait mode, I have an ImageView who's image will be of variable size (yet always square). I would like the ImageView's width to always be equal to the layout's width (fill_parent) and as you can see the scaleType is "centerCrop" which will scale.
The problem is that if I set the *layout_height* also to "fill_parent" then, being that centerCrop retains the original aspect ratio, the height takes precedence and the image is cropped on the left and right. (this of course assumes a screen that is taller than it is wide). However, if I set the layout_height to "wrap_content", then the height is no longer scaled and I end up with a cropped rectangle. It does this because it respects the original height of the image.
Is there a layout_height setting that will give precedence to a layout_width of "fill_parent"?
<ImageView
android:id="#+id/iv_image"
android:layout_width="fill_parent"
android:layout_height="?"
android:layout_below="#id/header"
android:layout_centerHorizontal="true"
android:contentDescription="#string/cd_image"
android:padding="0dp"
android:scaleType="centerCrop"
android:src="#drawable/blank_album" />
Removing the android:layout_height attribute causes a crash:
java.lang.RuntimeException: Binary XML file line #16: You must supply a layout_height attribute.
Setting android:layout_height="0dp" crushes the image vertically.
Answer: Using a combination of responses from other users, I was able to find a simple solution that works well for me.
First, the image view has this configuration (note the fitStart):
<ImageView
android:id="#+id/iv_album"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#id/header"
android:layout_gravity="top"
android:background="#FF00FF00"
android:contentDescription="#string/app_name"
android:padding="0dp"
android:scaleType="fitStart"
android:src="#drawable/blank_album" />
Then programmatically, a small modification to the height of the image to match the width (within Activity.onResume())
ImageView iv = (ImageView)findViewById(R.id.iv_album);
boolean bPost = iv.post(
new Runnable()
{
public void run()
{
ImageView iv = (ImageView)findViewById(R.id.iv_album);
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)iv.getLayoutParams();
params.width = ASong.this.findViewById(R.id.song_view_layout_top).getWidth();
params.height = params.width;
iv.setLayoutParams(params);
}
});
if (bPost == false)
{
throw new RuntimeException("runnable not posted");
}
I had to deal with this issue yesterday. This is the XML that solved my problem:
<ImageView
android:id="#+id/character"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:background="#android:color/transparent"
android:scaleType="fitCenter"
android:src="#drawable/ma_un1_001" />
see thread here: Center drawable and scale height
To cut a long story short:
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitCenter"
Alternatively, you can do it programmatically:
Surround the ImageView with a LinearLayout
<LinearLayout
android:id="#+id/container"
android:layout_below="#id/header"
android:layout_centerHorizontal="true"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="#+id/iv_image"
android:layout_width="fill_parent"
android:layout_height="?"
android:contentDescription="#string/cd_image"
android:padding="0dp"
android:scaleType="centerCrop"
android:src="#drawable/blank_album" />
</LinearLayout>
Then, in your onCreate(), insert
findViewById(R.id.container).post(
new Runnable() {
public void run() {
LinearLayout container = (LinearLayout)findViewById(R.id.container);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)container.getLayoutParams();
params.height = params.width;
container.setLayoutParams(params);
}}
);
The code must be into post() because the main process can't directly modify the layout structure.

Categories

Resources