RelativeLayout getWidth returns zero - android

First, I know this is a duplicate of other question but I couldn't manage to fix it so I created my own question for help. I am trying to get the RelativeLayout width, it was successful at first but I don't know what I changed and the code returns only zero.
Here is my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView[] imageViewArray = new ImageView[20];
ArrayList<Float> xarray = new ArrayList<>();
ArrayList<Float> yarray = new ArrayList<>();
rlt = (RelativeLayout) findViewById(R.id.layout);
imageView = (ImageView) findViewById(R.id.imageView);
rlt.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
rlt.getViewTreeObserver().removeOnGlobalLayoutListener(this);
Toast.makeText(MainActivity.this, "right" + rlt.getWidth(), Toast.LENGTH_SHORT).
show();
layoutwidth = rlt.getWidth();
layoutheight = rlt.getHeight();
}
});
}
Here is my activity_main xml file:
<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:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:id="#+id/layout"
android:background="#android:color/black"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView"
android:src="#mipmap/you"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</RelativeLayout>
Simple one, but yet not working, any help please?

It's because your layout's width isn't set yet
You should override onLayout() method
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
height = bottom - top;
width = right - left;
}

Usually you would extend whatever View you're interested in (here RelativeLayout) and override onSizeChanged():
https://developer.android.com/reference/android/view/View.html#onSizeChanged(int,%20int,%20int,%20int)
Whether that is useful in your scenario or not is hard to tell, since your question is fairly generic.

Try
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run()
{
//get width here
}
}, 10);

Maybe try to put the code for the views into the "onPostCreate" Method

Related

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);
}
});
}

Animate changing LayoutParams (RelativeLayout)

when I click on a RelativeLayout it change the size.
How can I make this change animated? So it looks like the rectangle grows to full screen?
My Layout:
<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:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:background="#ff000000">
<RelativeLayout
android:id="#+id/srLayout"
android:layout_width="62.5dp"
android:layout_height="132.5dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="false"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="10dp"
android:clickable="true"
android:onClick="sleepRoom"
android:background="#ffffffff"></RelativeLayout>
</RelativeLayout>
The code:
public void sleepRoom(View view) {
RelativeLayout sr = (RelativeLayout) findViewById(view.getId());
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) sr.getLayoutParams();
params.height = RelativeLayout.LayoutParams.MATCH_PARENT;
params.width = RelativeLayout.LayoutParams.MATCH_PARENT;
sr.setLayoutParams(params);
}
Simple trick that worked for me:
Adding:
android:animateLayoutChanges="true"
to the xml of the view whose layoutParams you are changing.
Then, adding this line of code in your Java/Kotlin code before changing the params:
Java:
((ViewGroup) sr).getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
Kotlin:
(sr as ViewGroup).layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
To explicitly animate in this case, your sleepRoom() should look like this.
public void sleepRoom(View view) {
final RelativeLayout sr = (RelativeLayout) view;
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) sr.getLayoutParams();
params.height = RelativeLayout.LayoutParams.MATCH_PARENT;
params.width = RelativeLayout.LayoutParams.MATCH_PARENT;
sr.setLayoutParams(params);
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 1);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 1);
PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt("right", 0, 1);
PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt("bottom", 0, 1);
PropertyValuesHolder pvhRoundness = PropertyValuesHolder.ofFloat("roundness", 0, 1);
final Animator collapseExpandAnim = ObjectAnimator.ofPropertyValuesHolder(sr, pvhLeft, pvhTop,
pvhRight, pvhBottom, pvhRoundness);
collapseExpandAnim.setupStartValues();
sr.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
sr.getViewTreeObserver().removeOnPreDrawListener(this);
collapseExpandAnim.setupEndValues();
collapseExpandAnim.start();
return false;
}
});
}
However, normally android:animateLayoutChanges="true" should work.
For more specifics from the man Chet Haase, see: https://www.youtube.com/watch?v=55wLsaWpQ4g
because RelativeLayout extends View you can use all the animations you are using on "regular views". for example try using animate.scale() and see if it suits you. a simple way of doing it will be something like
#Override
protected void onCreate (Bundle savedInstanceState) {
sr = (RelativeLayout) findViewById(view.getId());
sv.setVisibility(View.GONE);
scaleEnd = sr.getScaleX();
sr.setScaleX(0);
}
...
#Override
protected void onPostCreate (Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
sr.setVisibility(View.Visible);
sr.animate.scaleX(scaleEnd);
}
Also if you want a Lollipop kind of animation have a look at: Use the Reveal Effect

getLocationOnScreen of a child of GridLayout

I'm attempting to get the x/y of an imageview within a GridLayout but my log keeps showing X & Y: 0 0 any ideas?
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/root" >
...
<GridLayout
android:id="#+id/gridLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:columnCount="3"
android:rowCount="5" >
...
<ImageView
android:id="#+id/fivetwo"
android:layout_width="75dp"
android:layout_height="75dp"
android:contentDescription="#string/gameboard"
android:gravity="center"
android:src="#drawable/tile"
android:layout_columnSpan="1"
android:layout_rowSpan="1" />
heres the java:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_level);
....
ImageView temp = (ImageView) findViewById(R.id.fivetwo);
int originalPos[] = new int[2];
temp.getLocationOnScreen( originalPos );
Log.i(TAG, "X & Y: " + originalPos[0] + " " + originalPos[1]);
...
Remember:getX() and getY()return 0 if components are not drawn yet (in onCreate(){} ).
To find out the position of a view as soon as it is ready:
Add a tree observer to the layout. This should return the correct position.
onCreate is called before the layout of the child views are done. So the width and height is not calculated yet. To get the height and width. Put this on the onCreate method
final ImageView temp = (ImageView) findViewById(R.id.fivetwo);
ViewTreeObserver vto = temp.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
temp.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int x = temp.getX();
int y = temp.getY();
Log.v(TAG, String.format("X:%d Y:%d",x,y);
}
});
You need to wait for the callback when the layout has placed the children views. The code you are using returns 0 because the position is returned before the layout is placed. Use this code:
temp.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
getViewTreeObserver().removeGlobalOnLayoutListener(this);
int[] locations = new int[2];
temp.getLocationOnScreen(locations);
int x = locations[0];
int y = locations[1];
}
});

How to set a FrameLayout fill_parent in width and always have a fixed ratio in height?

I see some questions about "ImageView"s, but I need a FrameLayout.
I have a FrameLayout, which I need its width:height = 2:1, and the width is fill_parent. There are many image views inside the frame layout, I can just set them width=fill_parent and height=fill_parent.
I don't find a way to do this, please help .
My xml code is:
<FrameLayout
android:id="#+id/cardView"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:layout_centerInParent="true">
<ImageView
android:id="#+id/frameView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitXY"
android:src="#drawable/card_style1"
/>
</FrameLayout>
See if this is what you want:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
final FrameLayout target = (FrameLayout) findViewById(R.id.frame_id);
target.post(new Runnable() {
#Override
public void run() {
int width = target.getWidth();
int height = width / 2;
LayoutParams lp = target.getLayoutParams();
lp.height = height;
target.setLayoutParams(lp);
}
});
}

getWidth and getHeight are returning a zero

I am trying to make a simple drawing program for the android.
I have a custom View class to handle the drawing. When I call its getWidth and getHeight metheds, I get a zero.
But, the drawing works fine, I hard code in the width and height so it works. Why is it doing this?
My View class
public class cDrawing extends View{
char BitMap[];
static final short WIDTH=160;
static final short HEIGHT=440;
static final char EMPTY=' ';
int mWidthSize;
int mHeightSize;
static final char RED ='R';
int y;
public cDrawing(Context context) {
super(context);
y=3;
// set up our bitmap
BitMap=new char[WIDTH*HEIGHT];
for(int i=0; i<WIDTH*HEIGHT; i++)
BitMap[i]=EMPTY;
// returns zero why???????
int h=getHeight();
h=400;
int w=getWidth();
w=320;
mWidthSize=w/WIDTH;
mHeightSize=h/HEIGHT;
// TODO Auto-generated constructor stub
}
The Activity class
public class cCanves extends Activity implements OnClickListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.canves);
cDrawing board=new cDrawing(this);
LinearLayout layout = (LinearLayout)findViewById(R.id.parent2);
layout.addView(board);
// set up buttons
View mEraser = findViewById(R.id.buteraser);
mEraser.setOnClickListener(this);
View mBlack = findViewById(R.id.butblack);
mBlack.setOnClickListener(this);
View mWhite = findViewById(R.id.butwhite);
mWhite.setOnClickListener(this);
View mRed = findViewById(R.id.butred);
mRed.setOnClickListener(this);
} // end function
public void onClick(View v) {
Intent i;
switch(v.getId())
{
case R.id.buteraser:
break;
case R.id.butblack:
break;
case R.id.butwhite:
break;
case R.id.butred:
break;
} // end switch
} // function
}
the xml file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="#+id/parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:orientation="vertical"
android:layout_height="fill_parent">
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:orientation="horizontal"
android:layout_height="wrap_content">
<ImageButton android:id="#+id/buteraser"
android:src="#drawable/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageButton android:id="#+id/butblack"
android:src="#drawable/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageButton android:id="#+id/butwhite"
android:src="#drawable/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageButton android:id="#+id/butred"
android:src="#drawable/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout android:id="#+id/parent2"
android:layout_width="fill_parent"
android:orientation="vertical"
android:layout_height="fill_parent">
</LinearLayout>
</LinearLayout>
The width and height are not defined until the view is actually rendered to the screen.
Use protected abstract void onLayout (boolean changed, int l, int t, int r, int b) (which you override in your activity) to know when the sizes are ready.
Complementing Mah's answer, I found out that you can get the values from parameters, like the code bellow:
ImageView imageProcess = (ImageView) li.inflate(
R.layout.andamento_sinistro_imageprocess, centerLayout, false);
imageProcess.setBackgroundResource(
(isActive)?(R.drawable.shape_processon):(R.drawable.shape_processoff));
RelativeLayout.LayoutParams imageProcessParams =
(RelativeLayout.LayoutParams)imageProcess.getLayoutParams();
imageProcessParams.leftMargin =
(int) (centerPosition - 0.5*imageProcessParams.width);
imageProcessParams.addRule(RelativeLayout.CENTER_VERTICAL);
centerLayout.addView(imageProcess);
The real catch here is the use of the LayoutParams, that have rules yet not processed by the element.
I'm not certain, but it may have something to do with where the code is in the lifecycle of your activity. If you're calling getWidth() and getHeight() before the View is displayed on screen, you'll get a value of 0. I've had that happen to me, too.
I'm not sure if there's a way around this. I had to rely on getting the hardware screen's width and height, instead of the view's width and height. You might end up having to approximate the width and height of your view and hard coding it.
You should call getWidth() and getHeight() in the overrided method onLayout.
Just Use the getViewTreeObserver() Listener, and inside this just
calculate the height and width.
Follow the code :
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
//Do your Stuff calculation , like view.getWidth() ...
});
The view only has dimensions after beeing displayed for the first time.
Other thing:
int h=getHeight();
h=400;
Is useless no ? Is it just for testing ?

Categories

Resources