Android: view layout resetting when adding/removing fragments - java

I am a bit new to android, but I know java fairly well.
As a simple means of scalability, i use these simple functions:
public void scaleMyView(float s) {
scaleFactor = scaleFactor + s;
// s will usually be like 0.1 or -0.1 = 10% size gain/loss
View myMainView = findViewById(R.id.MyMainView);
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int x = size.x;
int y = size.y;
myMainView.setScaleX(scaleFactor);
myMainView.setScaleY(scaleFactor);
myMainView.layout(0, 0, ((int)(x/scaleFactor)), ((int)(y/scaleFactor)))
myMainView.setPivotX(0);
myMainView.setPivotY(getActionBar().getHeight());
}
Which does exactly what I want, changing the main view and all within it in size and keeping it in place.
Now comes the problem:
Whenever I add a fragment to a sub-view of that main-view, the "layout" part is reset, and though scale and position remain, size shrinks back to default.
(The fragments are very simple, basically simple buttons.)
I tried quite a few things, and I still have no idea where or how to fix that.
Any help is highly appreciated!

Try to use "addOnLayoutChangeListener" method on your mainView:
myMainView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(
View view, int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8)
{
// set view properties here
}
});
myMainView.requestLayout();

Related

Android: getHolder().setFixedSize(1920,1080) causes Issue with screen Resolution

Im developing a Game. I want my screen to always be 1920x1080.
getHolder().setFixedSize(1920,1080);
setFixedSize on my SurfaceView achieves this. It also creates a problem, however: the screen is still in WQHD res instead of also being FHD. This leads to mouseclickposition being bigger than the canvas is visually, and thus clicking on buttons no longer works unless I press where they actually would be in the smaller resolution.
Is there a way to set Android's resolution to 1920x1080? Maybe setting the Layout to that? I also tried making my canvas equal to a bitmap thats the right dimensions but that doesnt seem to change Anything at all.
Bitmap bitmap = Bitmap.createBitmap(10,100,null);
Canvas c = new Canvas(bitmap);
An alternative way to solve this might be to calculate the corresponding mouseClick Position from the bigger screen to the smaller, I suppose, but that seems like the suboptimal solution.
Here is what solved it
public static float normalize(float value, float min, float max) {
return Math.abs((value - min) / (max - min));
}
public boolean onTouchEvent(MotionEvent event) {
int differenceInWidth = actualScreenwidth - screenwidth; //2560-1920
float xPercent = normalize(event.getX(),0,actualScreenwidth);
Log.d("mouse_P_xPercent", Float.toString(xPercent));
float yPercent = normalize(event.getY(),0,actualScreenheight);
Log.d("mouse_P_yPercent", Float.toString(yPercent));
mouseCurrentPositionX = (int) (screenwidth*xPercent);
mouseCurrentPositionY = (int) (screenheight*xPercent);

RecyclerView recalculate WRAP_CONTENT

With version 23.2 we can now use WRAP_CONTENT for recyclerView height, which is great. I am doing this, however I want to recalculate the height after an item is added (or removed) to the adapter (thus increasing or decreasing the height).
My particular RecyclerView is starting with 1 item, and then adding items as the user makes selection. So I need the RecyclerView layout to increase in height, up to a point. Ideally this would happen with a smooth animation when the list increases or decreases.
How can we make it WRAP_CONTENT after it has been laid out?
Tried:
recyclerview.requestLayout();
recyclerview.invalidate();
I would expect it to work with View.invalidate().
If that does not work, try to call either requestLayout or invalidate on the parent view.
How RecyclerView Resize itself based on with the new LayoutManger
The RecyclerView widget provides an advanced and flexible base for creating lists and grids as well as supporting animations. This release brings an exciting new feature to the LayoutManager API: auto-measurement! This allows a RecyclerView to size itself based on the size of its contents. This means that previously unavailable scenarios, such as using WRAP_CONTENT for a dimension of the RecyclerView, are now possible. You’ll find all built in LayoutManagers now support auto-measurement.
Due to this change, make sure to double check the layout parameters of your item views: previously ignored layout parameters (such as MATCH_PARENT in the scroll direction) will now be fully respected.
If you have a custom LayoutManager that does not extend one of the built in LayoutManagers, this is an opt-in API - you’ll be required to call setAutoMeasureEnabled(true) as well as make some minor changes as detailed in the Javadoc of the method.
Note that although RecyclerView animates its children, it does not animate its own bounds changes. If you would like to animate the RecyclerView bounds as they change, you can use the Transition APIs.
Please read this
Option I
Did you see this answer?
It's not using the recyclerView's WRAP_CONTENT, but it might work.
You can also create your own custom recyclerView (extends RecyclerView) and override the onMeasure() method there instead using the layoutManager in the link.
Option II
Try to set the layout params before drawing the view. I haven't checked if it is called when recyclerView layout changes, but if it does, then it will work. Something like this (in your Activity/Fragment onCreate()/onCreateView() method:
recyclerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
recyclerView.getViewTreeObserver().removeOnPreDrawListener(this);
YourParentLayoutType.LayoutParams params = (YourParentLayoutType.LayoutParams) recyclerView.getLayoutParams();
params.height = YourParentLayoutType.LayoutParams.WRAP_CONTENT;
recyclerView.setLayoutParams(params);
return true;
}
});
Use your recyclerView's parent layout type instead of YourParentLayoutType in the code.
I'm not sure this will work when layout refreshes, but maybe worth a try.
Use this class:
Please use 23.2.1 as 23.2 was way buggy.
Also have you tried to call notifyDataSetChanged on the recyclerview adapter , as far as i think it should expand without problem if you have given wrap_content as height of recyclerview
else u can use this class:
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
public class MyLinearLayoutManager extends LinearLayoutManager {
public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
private int[] mMeasuredDimension = new int[2];
#Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
int widthSpec, int heightSpec) {
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int width = 0;
int height = 0;
for (int i = 0; i < getItemCount(); i++) {
if (getOrientation() == HORIZONTAL) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
heightSpec,
mMeasuredDimension);
width = width + mMeasuredDimension[0];
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
measureScrapChild(recycler, i,
widthSpec,
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
height = height + mMeasuredDimension[1];
if (i == 0) {
width = mMeasuredDimension[0];
}
}
}
switch (widthMode) {
case View.MeasureSpec.EXACTLY:
width = widthSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
switch (heightMode) {
case View.MeasureSpec.EXACTLY:
height = heightSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
int widthDesired = Math.min(widthSize,width);
setMeasuredDimension(widthDesired, height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
View view = recycler.getViewForPosition(position);
// For adding Item Decor Insets to view
super.measureChildWithMargins(view, 0, 0);
RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(
widthSpec,
getPaddingLeft() + getPaddingRight() + getDecoratedLeft(view) + getDecoratedRight(view),
p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(
heightSpec,
getPaddingTop() + getPaddingBottom() + getDecoratedTop(view) + getDecoratedBottom(view) ,
p.height);
view.measure(childWidthSpec, childHeightSpec);
// Get decorated measurements
measuredDimension[0] = getDecoratedMeasuredWidth(view) + p.leftMargin + p.rightMargin;
measuredDimension[1] = getDecoratedMeasuredHeight(view) + p.bottomMargin + p.topMargin;
recycler.recycleView(view);
}
}

getLayoutParams().height returns -2 even after onGlobalLayout()

I have an android dialog which i want to position in a specific position in its window.
I'm using API 8
how come int a == -2 and int b == 153 are not positive?
what is the difference between
getLayoutParams().height;
mToolTipLayout.getHeight();
I have the following code
public void initViews(int orientation) {
mToolTipLayout = ((LinearLayout) findViewById(R.id.tooltip_layout));
ViewTreeObserver vto = mToolTipLayout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mToolTipLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
setPosition();
}
});
private void setPosition() {
int a = mToolTipLayout.getLayoutParams().height;
int b = mToolTipLayout.getHeight();
}
Layout params specify how the measure and layout process should work. They are not updated in the measure/layout process. -2 is the value for WRAP_CONTENT.
The measures themselves are available in the views themselves, not their layout params. 153 is the measured pixel height in your case, measured with WRAP_CONTENT spec.
Yes, -2 means WRAP_CONTENT. To get a height of a layout in this case you cannot use getLayoutParams().height or getHeight() (-2 and 0 respectively). You should get a height of inner view (for instance, with view.getLayoutParams().height). Probably add paddings.

translate canvas and offset actionbar

Please bear with me if this isn't clear, this is my first posting here.
I'm drawing a couple of lines on a canvas and trying to translate the canvas to centre the lines on the screen. The trouble is, I have an actionbar (using actionbarsherlock) which I want to exclude from the translation i.e. I want the top of the view to be under the action bar.
As it is, the data is centred vertically on the whole screen height, but I want it to be centred vertically only on the visible part of the canvas under the action bar.
Any ideas of the best way to achieve this?
#Override
protected void onDraw(Canvas canvas) {
Paint paint = mPaint;
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
int centrew = canvas.getWidth()/2;
int centreh = canvas.getHeight()/2;
canvas.translate(centrew, centreh);
canvas.drawLine(0, -5, 0, 5, mPaint);
canvas.drawLine(5, 0, -5, 0, mPaint);
}
if you know the exact size of the bar, you could apply it it to the overall canvas height to increase the shift:
int maxV = canvas.getHeight() + barHeight;
int centreh = maxV/2;
I am assuming, the bar is on top, covering apart of the canvas, so the shift (from the top left corner) has to be greater. If the bar is on the bottom, the shift should be reduced:
int maxV = canvas.getHeight() - barHeight;
int centreh = maxV/2;
EDIT: If the bar has a different size in pixels on different devices, you have to hack a bit to make it work. You can safely make assuptions about the bar and revise them in case they don't hold. You could assume a certain ratio reserved for the bar and adapt the absolute pixel count accordingly (the oneliner is rather for illustration):
int maxV = Math.round(canvas.getHeight()*(1f + barRatio));
You can further adapt the ratio depending on the aspect ratio of the screen to make it work even better.
Unfortunately there is no really clean solution as you cannot read the current layout and extract sizes.
The solution I used was as described here :
http://developer.android.com/resources/samples/HoneycombGallery/src/com/example/android/hcgallery/TitlesFragment.html
Basically my activity has the following layout listener defined:
ViewTreeObserver.OnGlobalLayoutListener layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mmv.setAbShift(MunroBag.this.actionBar.getHeight());
}
};
Then the view class has the following method defined:
public void setAbShift(int shift)
{
abShift = shift;
this.invalidate();
}
So onDraw gets called and the shift is applied to the view depending on the actionBar height.

execute code after Activity loads in Android

I'm trying my app format some images in the screen after the Activity loads. The problem is while inside onCreate(), onResume() methods my ImageView have width and height=0. How can I run some code after the views are resized?
I test onPostResume() but it dont work =(
Views in Android do not have fixed size/position like in Blackberry or iPhone; instead, they are layed out dynamically. Layout happens much later than onCreate/onResume, and theoretically can happen many times. Every view has methods onMeasure and onLayout which are responsible for that. Only after onLayout method returns you can tell the view's size and position. Before that the view's size is 0 and position is 0 (as you've noticed).
So it makes little sense trying to get ImageView's size in onCreate/onResume because onLayout hasn't yet been called at that point.
Instead, override onLayout like this and do your stuff there:
public class MyImageView extends ImageView {
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// at this point size and position are known
int h = getHeight();
int w = getWidth();
doSomethingCool(h,w);
}
}

Categories