second onSizeChanged gets height of zero - android

I have an app that displays some data graphically. It creates two Views to draw graphics in and adds them to my layout. Each view shows the data differently way but each View implements onSizeChanged() the same:
protected void onSizeChanged(int curw, int curh, int oldw, int oldh) {
if (bitmap2 != null) {
bitmap2.recycle();
}
canvas2= new Canvas();
bitmap2 = Bitmap.createBitmap(curw, curh, Bitmap.Config.ARGB_8888);
canvas2.setBitmap(bitmap2);
}
The views are invoked thusly:
LinearLayout myLayout = (LinearLayout)findViewById(R.id.revlay);
GraphView1 graphView1 = new GraphView1(this, theEventArrayList);
myLayout.addView(graphView1);
GraphView2 graphView2 = new GraphView2(this, theEventArrayList);
myLayout.addView(graphView2);
Always the first onSizeChanged() that gets called gets a height of 652 and a width of 480; the second one gets a height of 0, which causes createBitmap() to fail. If I reversed the order of the above invocation then graphView1 would fail that way. I'd like each bitmap to have about half the area.
Thanks in advance for explaining what's going on!

its difficult to answer your question without knowing further implementation details about your graphviews and the layout parameters of the LinearLayout.
But assuming your LinearLayout has a horizontal orientation try this:
GraphView1 graphView1 = new GraphView1(this, theEventArrayList);
GraphView2 graphView2 = new GraphView2(this, theEventArrayList);
myLayout.addView(graphView2, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0, 1));
myLayout.addView(graphView1, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0, 1));
this will tell the LinearLayout to arrange your views so that they equally divide the horizontal space between themselves.

Related

Position ImageViews with an offset programmatically

I have to create a stack of images programmatically (because they have to be dynamic).
I want to stack ImageViews like this:
I've tried this, but the images all land up on top of each other:
for(int i=0; i<limit; i++){
dynamicButtons[i] = new ImageView(contextSosFragment);
int offsetLeft = 15 * i;
int offsetTop = 15 * i;
layoutParamsDynamicButton.setMargins(offsetLeft, offsetTop, 0, 0);
dynamicButtons[i].setAdjustViewBounds(true);
dynamicButtons[i].setScaleType(ScaleType.FIT_CENTER);
dynamicButtons[i].setImageResource(R.drawable.img_badge_dynamic_loading);
dynamicButtons[i].setTag(id);
containerDynamicButtons.addView(dynamicButtons[i], layoutParamsDynamicButton);
}
I've even removed the android:gravity="center" from my xml layout file.
I've also tried to add the layout params on the ImageView after setting the margins (dynamicButtons[i].setLayoutParams(layoutParamsDynamicButton);), but I read that that this might not take effect, because the layout params are for the parent and not the child of the container to which I add the ImageViews, that's why I tried to use addView(view, layoutParams).
How can I position the ImageViews like this, programmatically?
SOLUTION:
The solution was that I had to create a new layout params instance for each image - just like Devunwired suggested. However, I also found that I had to change the LinearLayout.LayoutParams to be RelativeLayout.LayoutParams. Only then did the change take effect.
The final for loop looks like this:
for(int i=0; i<limit; i++){
RelativeLayout.LayoutParams layoutParamsDynamicButton = new RelativeLayout.LayoutParams(width, height);
layoutParamsDynamicButton.bottomMargin = (int) getActivity().getResources().getDimension(R.dimen.margin_badges);
int offsetLeft = AppConstants.dynamic_button_offset_multiplier * i;
int offsetTop = AppConstants.dynamic_button_offset_multiplier * i;
layoutParamsDynamicButton.setMargins(offsetLeft, offsetTop, 0, 0);
Log.d(TAG, "offset = "+offsetLeft);
dynamicButtons[i] = new ImageView(contextSosFragment);
dynamicButtons[i].setAdjustViewBounds(true);
dynamicButtons[i].setScaleType(ScaleType.FIT_CENTER);
dynamicButtons[i].setImageResource(R.drawable.img_badge_dynamic_loading);
dynamicButtons[i].setTag(id);
containerDynamicButtons.addView(dynamicButtons[i], layoutParamsDynamicButton);
}
Each view needs its own LayoutParams object. It looks like your code just updates the same LayoutParams instance each time and passes it to addView(). If this is the case, all your views are pointing to the same params when it comes time to do layout...and their margins will all be the last value set.
As a performance optimization, if you are just placing several static images on top of each other, you could achieve the same effect (including the offsets) with a LayerDrawable (docs link) inside a single ImageView. This is the object created by <layer-list> in XML, but since you need to dynamically set the offset you could create one in code as well. Fewer views typically leads to cleaner UI.

(ANDROID) ImageView won't position correctly

I have an Android related issue:
I am trying to centre a logo on the screen of my device, but it won't position correctly.
I am using the following function:
public void ImageCentered(int ID){
ImageView iv = (ImageView) findViewById(ID);
int x = 0;
int y = 0;
RelativeLayout.LayoutParams position = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
x = (screenWidth/2)-(iv.getWidth()/2);
y = (screenHeight/2)-(iv.getHeight()/2);
position.setMargins(x, y, 0, 0);
iv.setLayoutParams(position);
}
This could should work,but it won't. The image is set off slightly to the right and bottom like in this image:
https://www.dropbox.com/s/tf7r1u1xqcmb9t9/2014-08-16%2018.36.04.png
Now, the strange thing is, when I use the following code:
public void ImageCentered(int ID){
ImageView iv = (ImageView) findViewById(ID);
int x = 0;
int y = 0;
RelativeLayout.LayoutParams position = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
x = (screenWidth/2)-(iv.getWidth()/2);
y = (screenHeight/2)-(iv.getHeight()/2);
position.setMargins(x, y, 0, 0);
Message(IntToStr(x)+", "+IntToStr(y));
iv.setLayoutParams(position);
}
this is the result:
https://www.dropbox.com/s/mjw80zlzkav6dzs/2014-08-16%2018.41.16.png
Side note: The text in the Message() function does not matter, nor does its position within the ImageCentered() function.
I am not calling the function in my OnCreate(), as the width and height of the image would always return 0, so I looked something up and found this:
#Override
public void onWindowFocusChanged(boolean hasFocus){
ImageCentered(R.id.image);
}
This piece of code is in my MainActivity.java file, whereas the ImageCentered() function is in my UtilLib.java file.
So, I was wondering: What's going on here? Why does the code work when I pop in a Message() but not when I leave it out?
Sure, I can try hardcoding the data, but what about smaller/bigger screens?
I hope an Android guru can help me out here, as I've been struggling with this for quite some time now.
EDIT
Just noticed something interesting when pressing "OK" on my Message:
https://www.dropbox.com/s/a7lu6588hy1opw7/2014-08-16%2018.51.55.png
My guess is that my problem lies there, but after clicking the "OK" button once more, the data is "492, 207" again. scratches head
Assuming rom your code that the ImageView is inside a RelativeLayout, You could also do:
// get imageview layout params or create new ones
RelativeLayout.LayoutParams params = imageView.getLayoutParams();
params.addRule(RelativeLayout.CENTER_HORIZONTAL);
this way the image will be automatically centered without all those manual calculations!.
You can also specify it in the XML with
<ImageView .....
android:layout_centerHorizontal="true"/>
I've ultimately decided to just hardcode the x and y coordinates, and later on use some sort of scaling-conversion to position them properly, unless someone can provide me with a better method of fixing this.
UPDATE
So, after googling after a while (again), I have finally found the answer and created two functions:
public int GetImageHeight(int ID){
ImageView iv = (ImageView)findViewById(ID);
iv.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
iv.layout(0, 0, iv.getMeasuredWidth(), iv.getMeasuredHeight());
return iv.getMeasuredHeight();
}
public int GetImageWidth(int ID){
ImageView iv = (ImageView)findViewById(ID);
iv.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
iv.layout(0, 0, iv.getMeasuredWidth(), iv.getMeasuredHeight());
return iv.getMeasuredWidth();
}
All you have to do is pass the ID of the image you made in your xml file, like so:
GetImageHeight(R.id.logo)

Why I'm getting different results when running TextView.measure() in code, from what I see rendered on screen

I'm now trying to resolve an issue with somehow overlapping text in TextView.
I've posted a question about that , but I've also tried to solve it myself. I decided to count the amount of text which causes the textview to break the line. I came up with this unpolished code, which basically should inflate the view, set it's layout params according to the displayed size and then run onmeasure and return lineCount. I plan than to use probably binary search to find exact text length which fits into the textview, but even before I've just tried to run the code and see how it behaves. It's kind of weird, because it gives me different results, than what I see on screen than. I even tried to alter the textsize according to scaled density, because I wasn't sure whether it's been taken into account.
Here is the code. It returns three,but when I render the layout to screen the text takes up only two lines.
public int getCountOfLines(Context context, int widgetDp){
LayoutInflater mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout layout = (LinearLayout) mLayoutInflater.inflate(R.layout.event_basic_large ,null, false);
TextView titleTextView = (TextView) layout.findViewById(R.id.itemTitle);
titleTextView.setText(TEST_TEXT);
float density = context.getResources().getDisplayMetrics().density;
float textDensity = context.getResources().getDisplayMetrics().scaledDensity;
titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleTextView.getTextSize()/density*textDensity);
layout.setLayoutParams(
new LinearLayout.LayoutParams(
(int) (widgetDp*density),
ViewGroup.LayoutParams.WRAP_CONTENT)
);
layout.measure(View.MeasureSpec.makeMeasureSpec(
(int) (widgetDp*density), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
);
Log.d(TAG, titleTextView.getLineCount() + " lines, width "+titleTextView.getMeasuredWidth());
return titleTextView.getLineCount();
}
I ran into this a while back and after searching and trying finally got the following function to work:
public int getLineCount(String testString, float textSize,
float width) {
Rect bounds = new Rect();
Paint paint = new Paint();
paint.setTypeface(<font>);//set font that you are using for this
paint.setTextSize(textSize);
paint.getTextBounds(testString, 0, testString.length(), bounds);
return (int) Math.ceil(bounds.width() / width);
}
This function uses textSize and width to give number of lines.
This functions give number of line in a textview before it is displayed.

When to use setWidth, setHeight, setLayoutParams(new LinearLayout.LayoutParams(w,h))?

I am confused on when to use setWidth, and setHeight? It usually don't work.
What always work is setLayoutParams.
This will work.
sampleButton = new Button(this);
sampleButton.setLayoutParams(new LinearLayout.LayoutParams(65, 65));
This will not work.
sampleButton = new Button(this);
sampleButton.setHeight(65);
sampleButton.setWidth(65);
Or maybe there are some initialisation for this code to work?
So, just looked at the Button's source code (which is a subclass of TextView):
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.1_r2/android/widget/TextView.java#TextView.setHeight%28int%29
here is the method for setHeight
public void setHeight(int pixels) {
mMaximum = mMinimum = pixels;
mMaxMode = mMinMode = PIXELS;
requestLayout();
invalidate();
}
now in the onMeasure method, mMaximum and mMaxMode are used here
int unpaddedHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom();
if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) {
unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum));
}
It looks like the setheight doesn't really overwrite the internal height parameters, more just sets flags for layout.
Changing the layout params (which are what are actually referenced when the view is laying itself out) seem to inform the view that it actually needs to be that hight
TLDR; setHeight has more to do with the line height of the text than the height of the view

Android negative margin does not work

I have encountered a problem when i try to give a negative left margin to a LinearLayout.
The negative margin does not appear.
Here is my code
HorizontalScrollView hview = new HorizontalScrollView(context); // HorizontalScrollView is the outer view
RelativeLayout.LayoutParams hs_lot_params = new RelativeLayout.LayoutParams(164, 164);
hs_lot_params.setMargins(100, 100, 0, 0); // set the positions
ImageView image = new ImageView(context);
image.setBackgroundResource(R.drawable.leder);
LinearLayout.LayoutParams img_lot_params = new LinearLayout.LayoutParams(164, 164);
img_lot_params.setMargins(0, 0, 0, 0);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(164, 164);
layoutParams.setMargins(-132, 0, 0, 0);
ll.addView(image, img_lot_params);
hview.addView(ll, layoutParams);
Note: my plan is to scroll the image from left to right.
First, the left part of the image is hidden and can scroll to right to see the full image
ViewGroup.MarginLayoutParams params =
(ViewGroup.MarginLayoutParams)view.getLayoutParams(); params.topMargin = -100;
Negative margins should work in LinearLayout and RelativeLayout. What you probably need, is to scroll the HorizontalScrollView with scrollBy(int x, int y) or scrollTo(int x, int y) to achieve the "peek and scroll" effect you described.
Also keep in mind that using raw pixel units is generally a bad idea as the actual size will depend on the pixel density of the screen. Prefer dp measurements instead.

Categories

Resources