Why linearlayout's size -1? - android

I'm trying to get linearlayout's size.
I tested as following code.
But I just get value -1 (linearlayout's width).
How to get correct size?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello World, MyActivity"
/>
</LinearLayout>
package com.example.LayoutSize;
import android.app.Activity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.LinearLayout;
public class MyActivity extends Activity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.mainLayout);
ViewGroup.LayoutParams layoutParams = linearLayout.getLayoutParams();
System.out.printf("linearLayout width : %d", layoutParams.width);
}
}

The reason you get -1 is because the width parameter is set to MatchParent which has a value -1.
To get the size of a layout, your should be using getWidth() or getMeasuredWidth() methods. However, these methods won't give you a meaningful answer until the view has been measured. Read about how android draws views here.
You can get the correct size, by overriding the onWindowFocusChanged() as mentioned in this thread.
Alternatively, (hacky solution), you could do this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final LinearLayout linearLayout = (LinearLayout) findViewById(R.id.mainLayout);
linearLayout.post(new Runnable() {
#Override
public void run() {
System.out.printf("linearLayout width : %d", linearLayout.getMeasuredWidth());
}
});
}

public static final int MATCH_PARENT = -1;

Related

layout() requires delay to changes in order to have visual changes

I am trying to 'dynamically' create a layout in a program, but I am having issues getting the layout to change its position and size without a delay.
Code:
package com.example.alexander.compassvsredneckinterpretertimetable;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.ShapeDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.support.constraint.ConstraintLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
public class testActivity extends Activity
{
class testUI
{
LinearLayout linearLayout;
TextView start;
TextView end;
int startValue, endValue;
private ShapeDrawable makeBackgorundShape()
{
ShapeDrawable BackgroundShape = new ShapeDrawable();
BackgroundShape.setShape(ItemBackground.makeRoundRect());
BackgroundShape.getPaint().setColor(0xffa6b2fc);
return BackgroundShape;
}
testUI(Context context, final ConstraintLayout parent, int startValue_, int endValue_)
{
this.startValue = startValue_ * 100;
this.endValue = endValue_ * 100;
start = new TextView(context);
start.setText(". " + String.valueOf(endValue) + " .");
end = new TextView(context);
end.setText(". " + String.valueOf(startValue) + " .");
linearLayout = new LinearLayout(context);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
linearLayout.addView(start);
linearLayout.addView(end);
linearLayout.setBackground(makeBackgorundShape());
parent.addView(linearLayout);
final Handler handler = new Handler();
Runnable runnable = new Runnable()
{
#Override
public void run()
{
linearLayout.layout(parent.getLeft(), linearLayout.getTop() + startValue, parent.getRight(), linearLayout.getBottom() + endValue); //without being postDelayed, this doesn't work
}
};
handler.postDelayed(runnable, 1000);
//handler.post(runnable); //doesn't work
}
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
ConstraintLayout constraintLayout = findViewById(R.id.constLayout);
new testUI(this, constraintLayout, 8, 10);
}
}
xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="#+id/constLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".testActivity">
</android.support.constraint.ConstraintLayout>
if handler.postDelayed(runnable, 1000); is changed to handler.post(runnable); or the handler and runnable are removed completely (just leaving the layout line), the layout doesn't change position or size at all.
I am not sure what the minimum delay is, but having the delay results in elements visibly flickering or changing position or size. Is there a way to get rid of the delay?
The canonical way of changing a View's dimensions in Android is to adjust the View's LayoutParams. You don't want to call layout() directly (in this situation); it's not designed to be used in that way.
Perhaps something like this (instead of your Runnable):
ConstraintLayout.LayoutParams params;
params = (ConstraintLayout.LayoutParams) linearLayout.getLayoutParams();
params.width = LayoutParams.MATCH_PARENT;
params.height = endValue - startValue;
params.topMargin = startValue;
linearLayout.setLayoutParams(params);
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.connect( R.id.myLinearLayout, ConstraintSet.TOP, R.id.constLayout, ConstraintSet.TOP, 0 );
constraintSet.applyTo( parent );
In order for this to work, all of constLayout's children must have resource IDs. For that reason, you may find it easiest to just have them in the .xml file to begin with:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="#+id/constLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".testActivity">
<LinearLayout
android:id="#+id/myLinearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<TextView
android:id="#+id/startValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="#+id/endValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</android.support.constraint.ConstraintLayout>
Naturally, you would find them with findViewById(), rather than adding them dynamically, in this case.

Getting the size of an inner layout in pixels

With the following Java and XML code, I was wondering how to retrieve the dimensions in pixels of an inner/child layout (LinearLayout, whereas the parent is RelativeLayout with paddings of 20dp) properly:
Java code:
public class TestActivity extends Activity {
private LinearLayout linLay;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
linLay = (LinearLayout)findViewById(R.id.linLay);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT);
linLay.setLayoutParams(lp);
getDimensions();
}
private void getDimensions() {
System.out.println(linLay.getHeight());
System.out.println(linLay.getWidth());
}
}
XML:
<?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:padding="20dp" >
<LinearLayout
android:id="#+id/linLay"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true">
</LinearLayout>
</RelativeLayout>
... Since I get outputs of 0 for the dimensions, I am aware that the LinearLayout needs to be set first on the screen before I could retrieve the dimensions... But what am I doing wrong here?
It didn't get its dimensions at the time you try to output them.You can just add a delay or just use method below.
private void getDimensions() {
ViewTreeObserver vto = linLay.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
#Override
public voidonGlobalLayout() {
linLay.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int height =linLay.getMeasuredHeight();
int width =linLay.getMeasuredWidth();
System.out.println(height);
System.out.println(width);
}
});
}

Fixed size custom View's UI components is not visible on screen

I have a fixed size custom view as follow.
RateAppBanner.java
public class RateAppBanner extends LinearLayout {
public RateAppBanner(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.rate_app_banner, this, true);
this.setBackgroundColor(Color.RED);
View view = this.findViewById(R.id.textView1);
if (view == null) {
Log.i("CHEOK", "WTF!");
} else {
// Reach here!
Log.i("CHEOK", "---> " + ((TextView)view).getText());
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int w = 320;
int h = 100;
setMeasuredDimension(w, h);
}
}
rate_app_banner.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#ffff0000"
android:text="Hello World" />
</merge>
However, I realize the textView1 is not visible on screen, even thought I can find it through findViewById.
I use the dump View Hierarchy through Eclipse. Here's what I get.
This puzzles me a lot. I can't see textView1 in the view hierarchy, even I can discover it through findViewById. Do you have any idea why textView1 is not visible on screen?
This is how I add RateAppBanner into my main activity.
MainActivity.java
import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout mainView = (LinearLayout)this.findViewById(R.id.screen_main);
mainView.addView(new RateAppBanner(this));
}
}
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/screen_main">
</LinearLayout>
</FrameLayout>
Complete source code
The complete workable souce code, which compiled using Eclipse can be downloaded from abc.zip
p/s The code example shown in rate_app_banner.xml is a stripped down version of complex UI layout. To narrow down the problem scope, I make the layout file contain only single TextView.
Another approach
Instead of using merge, I had tried
rate_app_banner.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#ffff0000"
android:text="Hello World" />
</LinearLayout>
It doesn't work still...
I tested using your source abc.zip. Please change the red color of text view to other. then add
onMeasure(w, h);
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int w = 320;
int h = 200;
super.onMeasure(w, h);
setMeasuredDimension(w, h);
}

Android use RelativeLayout Programmatically

I have a basic app working, but now I am focusing on formatting the app and running into difficulty laying things out as I want them.
I have a list of images that the user can switch from one to the next with using a next button. Both the images and the next button are added programmatically to the page (I clear out anything in the layout, and then add the ImageView and Button). Now, instead of laying them out one on top of the other, I am trying to lay them out next to each other, so the image will take up most of the space, and then the next button will be to its right.
Looking through the documentation I was leaning towards using a RelativeLayout to accomplish this. However, I ran into some questions while using RelativeLayouts programmatically.
Activity.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true">
<RelativeLayout
android:orientation="vertical"
android:id="#+id/activity_training_package_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.example.xxx.PackageActivity"
tools:ignore="MergeRootFrame">
</RelativeLayout>
</ScrollView>
Attempt to programmatically add the button:
public void addNextButton(final int currentFile, final RelativeLayout layout) {
Button next = new Button(this);
next.setWidth(100);
int id = layout.getChildAt(0).getId(); // the image is the only thing there
RelativeLayout.LayoutParams lay = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
lay.addRule(RelativeLayout.RIGHT_OF, id);
next.setLayoutParams(lay);
next.setText("NEXT >>");
next.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
showNextFile(currentFile, layout);
}
//layout.setLayoutParams(lay);
layout.addView(next);
...
I am just wondering which LayoutParams I am supposed to be setting for this, the LayoutParams of the layout, or of the view? When I try to set it to the layout, I get a cast exception (it is expecting a FrameLayout.LayoutParams, not a RelativeLayout.LayoutParams for some reason).
Could someone please point me in the right direction to figure out how layouts are used? I cannot seem to find resources that explain which LayoutParams I should be setting.
TL;DR How do you use RelativeLayouts and LayoutParams programmatically?
The simplest solution is to use the HorizontalSrollView with a LinearLayout.
activity_test.xml
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal" />
</HorizontalScrollView>
TestActivity.java
public class TestActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
LinearLayout container = (LinearLayout)findViewById(R.id.container);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
String next = getResources().getString(R.string.next);
for(int i=0;i<5;i++){
ImageView imgView = new ImageView(mActivity);
imgView.setLayoutParams(params);
imgView.setImageResource(R.drawable.photo);
container.addView(imgView);
Button button = new Button(mActivity);
button.setLayoutParams(params);
button.setText(next);
container.addView(button);
}
}
}
set Linear Layout weight Property in your XML file and assign weight to the imageview and button
main_activity.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:orientation="horizontal"
android:weightSum="1" />
MainActivity.java
package com.example.stackoverflowdemos;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TableLayout;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout container = (LinearLayout)findViewById(R.id.container);
//Dynamically generate imageview and button
ImageView imgView = new ImageView(this);
imgView.setLayoutParams(new TableLayout.LayoutParams(0, LayoutParams.FILL_PARENT, .2f)); //set imageview height and width using weight
imgView.setImageResource(R.drawable.ic_launcher);
container.addView(imgView);
Button button = new Button(this);
button.setLayoutParams(new TableLayout.LayoutParams(0, LayoutParams.WRAP_CONTENT, .8f)); //set Button height and width using weight
button.setText("next");
container.addView(button);
}
}

TextView failure

I'm programming my first android app.
I want to set text on a TextView.
(I already searched here and found out, how to do it...But it still don't work)
Do you know, what the problem is?
This is my Java code.
package com.example.randomcraps;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
import com.example.*;
public class MainActivity extends Activity {
TextView text = (TextView) findViewById(R.layout.number);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void getRandomNumber(){
int i;
double savePoint;
savePoint = Math.random();
savePoint = savePoint*100+1;
i = (int)savePoint;
text.setText(i);
}
}
This is my XML Code
<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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginTop="26dp"
android:text="#string/Button1"
android:onClick="getRandomNumber" />
<TextView
android:id="#+id/number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="#string/RandomNumber" />
</RelativeLayout>
Change to
TextView text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.number); // id of textview in activity_main.xml
}
findViewById looks for a view with the id mentioned in the current inflated layout. So you need to set layout to the activity and then initialize your views.
Also change
text.setText(i);
// looks for a resource with the id mentioned if not found you get ResourceNotFoundException
To
text.setText(String.valueOf(i));
// int i; i is an int value. Use String.valueOf(intvalue)
Edit:
Your method signature is different. It should be
public void getRandomNumber(View V){ // missing View as param
... //rest of the code
}
Coz you have
android:onClick="getRandomNumber"
Quoting from docs
public static final int onClick
Name of the method in this View's context to invoke when the view is clicked. This name must correspond to a public method that takes exactly one parameter of type View. For instance, if you specify android:onClick="sayHello", you must declare a public void sayHello(View v) method of your context (typically, your Activity).
Change your code to this.
TextView text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.number);
}
Also
text.setText(String.valueOf(i));
NOTE: findViewByID finds view from content. So basically you have to use that method after you set your content.
Set text color after setText and for guarantee set the font size. Sometimes it makes the color default white.

Categories

Resources