My Activity layout has View, i have get Y position this view at the beginning of the program, but if i shall insert in bottom method onCreate , i get position value = 0. How i can know, when view is drawn and get her Y position. I try get Y position when i click on button, position get good, but i have get position without using the button.
I get position:
private float cardsStartPosition = 0;
if (cardsStartPosition == 0) {
cardsStartPosition = commonCardContainer.getY();
}
Thanks for answer.
Try this method..It works fine for me.
ViewTreeObserver vto = YourView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
//do your stuff here
}
});
Add a global layout listener to your view, you will get notified when layout is done and your view has dimensions ...
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
//Here you can get your dimensions
int width = view.getWidth();
//View.removeOnGlobalLayoutListener(this);
}
});
You mention just View. So if that means it's your custom view, you can override the onLayout():
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
...;
}
This way you can observe any layout changes of your view. If you're also interested in size changes, there's also the onSizeChanged():
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
...;
}
If it's not your custom view, I'd go with the Ketan Ahir's way.
Related
I want to animate View right after it was added to parent (something like DrawerLayout). The problem is that View has varying size, and animation target position depends on that size. Simplified sample code:
AnimatingView extends View {
public int offsetX;
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int screenWidth = MeasureSpec.getSize(widthMeasureSpec);
final int screenHeight = MeasureSpec.getSize(heightMeasureSpec);
offsetX = calculateOffset(screenWidth);
...
}
}
Code similar to this triggers the animation:
#Override
public void onClick(View v) {
AnimatingView animatingView = new AnimatingView(getContext());
parentLayout.addView(animatingView);
animatingView.animate().x(animatingView.offsetX).setDuration(500).start();
}
In this case onMeasure() happens after animate(), so animation fails. What is the correct way of doing stuff which depends on view measuring?
The simple & stupid way would be something like animateOnceAfterMeasuring() based on isInitialized flag, but I don't think it the correct way of doing this.
this should work:
AnimatingView animatingView = new AnimatingView(getContext());
parentLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
v.removeOnLayoutChangeListener(this);
animatingView.animate().x(animatingView.offsetX).setDuration(500).start();
}
});
You can use the ViewTreeObserver for this
#Override
public void onClick(View v) {
final AnimatingView animatingView = new AnimatingView(getContext());
parentLayout.addView(animatingView);
animatingView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT < 16) {
animatingView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
animatingView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
animatingView.animate().x(animatingView.offsetX).setDuration(500).start();
}
});
}
I have a BindingAdapter like
#BindingAdapter({ "onGlobalLayout" })
public static void setOnGlobalLayout(View view, ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener) {
ViewTreeObserver vto = view.getViewTreeObserver();
vto.addOnGlobalLayoutListener(onGlobalLayoutListener);
}
In XML I have a View like
<View
android:id="#+id/viewId"
bind:onGlobalLayout="#{viewModel.onLayoutListener}"
/>
In ViewModel I have
public ViewTreeObserver.OnGlobalLayoutListener onLayoutListener(View view){
return new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// get x,y,width, height of view
}
};
}
Now I want to send the current View to ViewModel so I add a parametter View view to onLayoutListener but in XML I don't know how to send it.
Any help or suggestion would be great appreciated
UPDATE
Thank #pskink for suggest a better way for checking layout change.
With android:onLayoutChange I don't need BindingAdapter
<View
android:id="#+id/viewId"
android:onLayoutChange="#{viewModel.onLayoutListener(viewId)}"
/>
Java
public View.OnLayoutChangeListener onLayoutUpdateWeightSuccessfulListener(final View v) {
return new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
// left, top
}
};
}
simply pass your View id, it should work
bind:onGlobalLayout="#{viewModel.onLayoutListener(viewId)}"
So I have an activity with a view pager that inflates about 7 Fragments, and each fragment has a ScrollView inside it, I want to synchronize the scroll of all 7 scrollviews, so if the user scrolls to a position on fragment 3 and moves on to fragment 5 they should be at the exact same position, the scrollviews inflate the same children so the total height of the scrollview is constant throughout all 7 fragments.
I go some kind of system working, but its kind of a hit or miss, i get the scroll position of a list and broadcast the position and the fragment that is idle consumes the broadcast, and I save the position on the activity too so that the position can be requested in onResume of fragments that have not been inflated yet. Here is my code:
#Override
public void onResume() {
super.onResume();
mParentScrollView.setScrollY(mParentActivity.getScrollPos());
}
#Override
public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldX, int oldY) {
mScrollListener.onScroll(y);
mParentActivity.setScrollPos(y);
if (callbackSwitch) {
Intent intent = new Intent("ACTION_SCROLL");
intent.putExtra("TRANSLATION", y);
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);
}
callbackSwitch = true; //Switch to stop recursive calls
}
private BroadcastReceiver mTranslationReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (!isVisible) {
int translation = intent.getIntExtra("TRANSLATION", 0);
mParentScrollView.setScrollY(translation);
callbackSwitch = false;
}
}
};
I wanted to know if there is a better and stable way of achieving something similar.
Thanks in Advance.
Not sure how elegant this solutions is, but it should do the trick. Extend ViewPager and override onMeasure(int, int) method.
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if (h > height) height = h;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
My custom ViewPager was inside of a NestedScrollView and both of child fragments did not contained any additional ScrollViews.
I have a custom View, in which I need to perform treatment that require that the size of the view is set (so onCreate doesn't works), but before displaying anything. So I wondered if there is a callback function tat I could override for that ?
Right now I'm using onLayout, but it seems to be called twice, so I'm assuming it's probably not the right use for this. I also tried doing it in onMeasure but it seems that getWidth() and getHeight still returns 0 in it.
Thkanks,
Robin.
Try to use OnGlobalLayoutListener inside onResume()
#Override
public void onResume(){
super.onResume();
ViewTreeObserver viewTreeObserver = yourView.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
viewWidth = yourView.getWidth();
viewHeight = yourView.getHeight();
yourView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
System.out.println(viewHeight + " on resume x" + yourView.getX());
}
});
}
}
You can use the callback OnSizeChanged.
use onSizeChanged,
#Override
protected void onSizeChanged(int width, int height, int oldwidth, int oldheight) {
super.onSizeChanged(width, height, oldwidth, oldheight);
// your code here.
}
Try those methods
1.
ViewTreeObserver vto2 = imageView.getViewTreeObserver();
vto2.addOnGlobalLayoutListener(new
OnGlobalLayoutListener() {
#Override
public void onGlobalLayout () {
imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int height = imageView.getHeight();
int width = imageView.getWidth();
textView.append("\n\n" + imageView.getHeight() + "," + imageView.getWidth());
}
}
);
2.
imageView.post(new Runnable() {
#Override
public void run () {
int h = imageView.getHeight();
int w = imageView.getWidth();
Log.i(TAG, "Height=" + h);
}
};
In my application i want display list view using adapter. But i want get the current height and width of the list view (means after generating the list using adapter). how to get it. can anybody help me.
thanks
Use getWidth() and getHeight() method of ListView in onWindowFocusChanged to get the width and height.
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
System.out.println("Width:" + listview.getWidth());
System.out.println("Height:" + listview.getHeight());
}
To get current width or height of any view, you need to set onLayoutChange listener
public class MainActivity extends Activity implements OnLayoutChangeListener {
private View newView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
newView = getLayoutInflater().inflate(R.layout.main_activity, null);
newView.addOnLayoutChangeListener(this);
setContentView(newView);
}
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
//Here you can get size of you ListView, e.g:
mylistView.getWidth();
}
#Override
protected void onDestroy() {
super.onDestroy();
newView.removeOnLayoutChangeListener(this);
}
}
27Nov15 - This is a good answer, I think you should release the resource too though. This might not matter so much for an Activity, but the same approach can be used by fragments where they may come and go more frequently.