Difference in height of root Layout calculated from two methods - android

I am calculating the height of a root Layout ( RelativeLayout) with height and width as 'fill_parent' using this method and it returns 690
final RelativeLayout rootLayout=(RelativeLayout)findViewById(R.id.root_layout);
ViewTreeObserver vto = rootLayout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
mRootLayoutHeight=rootLayout.getHeight();
Toast.makeText(MyActivity.this,""+mRootLayoutHeight,Toast.LENGTH_LONG).show();
}
});
This layout has a Listview so i calculate the calculate the 'bottom' of individual rows using this
for(int i = 0; i <= month_listview.getLastVisiblePosition() - month_listview.getFirstVisiblePosition(); i++){
View v=month_listview.getChildAt(i);
if(v!=null) {
Rect rectf = new Rect();
v.getGlobalVisibleRect(rectf);
Log.d("bottom :", String.valueOf(rectf.bottom));
}
}
The bottom of the last row should come as 690 but its coming as 776. Why is there a difference?

Related

getLayoutParam returning width as -1

I am trying to set the layout width programatically .
ViewTreeObserver vtoRecyclerView = mMainLayout.getViewTreeObserver();
vtoRecyclerView.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mMainLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
ViewGroup.LayoutParams lpView = mMainLayout.getLayoutParams();
lpView.width = ViewGroup.LayoutParams.MATCH_PARENT-20;
mMainLayout.requestLayout();
}
});
but mMainLayout.getLayoutParams() is returning width as -1 .so when I set width as match_parent - 20 it becomes -21. I want to set the width as match_parent - 20.
What is wrong with the approach.
The root problem with your code here, is because you set the width with:
lpView.width = ViewGroup.LayoutParams.MATCH_PARENT-20;
while ViewGroup.LayoutParams.MATCH_PARENT is a constant.
You can find the constant on ViewGroup class
public static final int MATCH_PARENT = -1;
So that is obvious, because -1 - 20 is -21
What you can do here is, you can change the line to
lpView.width = mMainLayout.getWidth()-20;
try this.
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int height = displaymetrics.heightPixels;
int width = displaymetrics.widthPixels;
ViewTreeObserver vtoRecyclerView = mMainLayout.getViewTreeObserver();
vtoRecyclerView.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mMainLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
ViewGroup.LayoutParams lpView = mMainLayout.getLayoutParams();
lpView.width = width -20;
mMainLayout.requestLayout();
}
});
Try this.
ViewTreeObserver vtoRecyclerView = mMainLayout.getViewTreeObserver();
vtoRecyclerView.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if(mMainLayout.getWidth > 10 && mMainLayout.getHeight() > 10) // you can modify this value.
{
mMainLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
ViewGroup.LayoutParams lpView = mMainLayout.getLayoutParams();
lpView.width = ViewGroup.LayoutParams.MATCH_PARENT-20; // This seems to be wrong;
ViewParent parent = mMainLayout.getParent();
if(parent != null) {
lpView.width = (View)parent.getWidth();
}
mMainLayout.requestLayout();
}
}
});
I had the same problem while setting width as match_parent, I had resolved this by getting the phone screen width as follows:
Display display = ((Activity) context).getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int ActualWidth=width-(`margin you set for view`);
Hope it will help :)
As ViewGroup.LayoutParams.MATCH_PARENT constant predefined numeric value is -1 so you are getting -21 as result. and what you want can be achieved by defining margin to a layout rather than using that approach.

Anchoring SKAnnotation by customView at runtime

Running SDK 2.5.1, I'm trying to add my own SKAnnotations with my customView, whose size changes dynamically depending on the name displayed. To do this, I've attached an OnGlobalLayoutListener, to set the annotation's offset accordingly. However, it seems the global listener is not being called at all. I've tried attaching the it to both mapView.getAnnotationView().getView(), to mapView and to the mapHolder of the fragment, with no results. Any solution to allow me to anchor my annotations to the actual location would be appreciated.
final SKAnnotation newDelhi = new SKAnnotation(444);
newDelhi.setMininumZoomLevel(5);
newDelhi.setAnnotationType(SKAnnotation.SK_ANNOTATION_TYPE_MARKER);
SKAnnotationView newDelhiAnnotationView = new SKAnnotationView();
RelativeLayout newDelhiCustomView =
(RelativeLayout) ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
R.layout.annotation_layout, null, false);
newDelhiCustomView.setTag("new delhi");
newDelhiAnnotationView.setView(newDelhiCustomView);
newDelhi.setAnnotationView(newDelhiAnnotationView);
TextView newDelhiTextView = (TextView) newDelhiAnnotationView.getView().findViewById(R.id.annotation_textview);
newDelhiTextView.setText("New Delhi");
SKCoordinate newDelhiLocation = new SKCoordinate(77.179163, 28.619828);
newDelhi.setLocation(newDelhiLocation);
addRedPin(newDelhiLocation, 445);
mapView.addAnnotation(newDelhi, SKAnimationSettings.ANIMATION_NONE);
ViewTreeObserver vto = mapHolder.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mapHolder.getViewTreeObserver().removeGlobalOnLayoutListener(this);
float width = newDelhi.getAnnotationView().getView().getWidth();
float height = newDelhi.getAnnotationView().getView().getHeight();
newDelhi.setOffset(new SKScreenPoint(-width / 2, height / 2));
mapView.updateAnnotation(newDelhi);
}
});
final SKAnnotation chandigarh = new SKAnnotation(555);
chandigarh.setMininumZoomLevel(5);
chandigarh.setAnnotationType(SKAnnotation.SK_ANNOTATION_TYPE_MARKER);
SKAnnotationView chandigahrAnnotationView= new SKAnnotationView();
RelativeLayout chandigarhCustomView =
new RelativeLayout(getActivity());
chandigarhCustomView.setTag("chandigarh");
TextView chandigarhTextView = new TextView(getActivity());
chandigarhTextView.setText("Chandigarh");
chandigarhCustomView.addView(chandigarhTextView);
chandigahrAnnotationView.setView(chandigarhCustomView);
chandigarh.setAnnotationView(chandigahrAnnotationView);
SKCoordinate chandigarhLocation = new SKCoordinate(76.778867,30.736094);
chandigarh.setLocation(chandigarhLocation);
mapView.addAnnotation(chandigarh, SKAnimationSettings.ANIMATION_NONE);
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() { mapHolder.getViewTreeObserver().removeGlobalOnLayoutListener(this);
float width = chandigarh.getAnnotationView().getView().getWidth();
float height = chandigarh.getAnnotationView().getView().getHeight();
chandigarh.setOffset(new SKScreenPoint(-width / 2, height / 2));
mapView.updateAnnotation(newDelhi);
}
});
addRedPin(chandigarhLocation, 556);
Here is a screenshot of how the annotations wrongly appear (actual locations are red pins):

HorizontalScrollView.getMeasuredWidth() returns 0

I am adding horizontalScrollView programatically , but when I try to do horizontalScrollView.getMeasuredWidth() it keeps returning 0.
void addCategory(String catTitle) {
mVideos = mShows.get(catTitle);
LinearLayout theLayout = (LinearLayout)findViewById(R.id.activitymain);
TextView textview=(TextView)getLayoutInflater().inflate(R.layout.categorytitle,null);
textview.setTextColor(Color.CYAN);
textview.setTextSize(20);
textview.setText(catTitle);
HorizontalScrollView horizontalScroll = new HorizontalScrollView (this,null);
LinearLayout LL = new LinearLayout(this);
LL.setOrientation(LinearLayout.HORIZONTAL);
LayoutParams LLParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
LL.setLayoutParams(LLParams);
HorizontalGalleryAdapter adapter = new HorizontalGalleryAdapter(this,mVideos);
for (int i = 0; i < adapter.getCount(); i++) {
View item = adapter.getView(i, null, null);
LL.addView(item);
}
horizontalScroll.addView(LL);
int maxScrollX = horizontalScroll.getChildAt(0).getMeasuredWidth()-horizontalScroll.getMeasuredWidth();
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("Reset...");
String max= String.valueOf(maxScrollX);
Ok, I see the problem. You create a HorizontalScrollView, add a child to it, and then immediately try to get its measured width.
You cannot do this. You must add the horizontal scroll view to an existing already-drawn view in your activity first, because otherwise it doesn't have set dimensions yet.
Think about how would it know how many pixels WRAP_CONTENT will set the dimension to before its laid out in your view? If you add it to an existing, already-laid-out view in your activity, then that WRAP_CONTENT will actually get converted to some height.
It looks like you kind-of have a loop - horizontalScroll's dimensions depend on its content (WRAP_CONTENT), yet the content's (LinearLayout's) dimensions depend on the horizontalScroll's dimensions. This does not make sense. Perhaps try MATCH_PARENT for at least the width dimensions of your horizontal scroll view. Then, make sure to not look at dimensions until the view has been drawn.
Have a look into typical usage example for HorizontalScrollView:
// read a view's width
private int viewWidth(View view) {
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
return view.getMeasuredWidth();
}
....
void getTableRowHeaderCellWidth(){
int tableAChildCount = ((TableRow)this.tableA.getChildAt(0)).getChildCount();
int tableBChildCount = ((TableRow)this.tableB.getChildAt(0)).getChildCount();;
for(int x=0; x<(tableAChildCount+tableBChildCount); x++){
if(x==0){
this.headerCellsWidth[x] = this.viewWidth(((TableRow)this.tableA.getChildAt(0)).getChildAt(x));
}else{
this.headerCellsWidth[x] = this.viewWidth(((TableRow)this.tableB.getChildAt(0)).getChildAt(x-1));
}
}
}
You can also check full details from this nice tutorial: The code of a Ninja.

Best solution to draw responsive areas on image

I'm wondering what would be the best solution to get to the result shown below.
Here is what i've found so far:
an ImageView for the forest and a transparent surfaceView (to handle touch) on which I would draw the rectangles?
Or...
Just One SurfaceView with the image set as background and rectangles directly drawn on...?
For those 2 I've already chosen a RelativeLayout.
Which of those 2 would be the most efficient and easiest to do?
Or maybe there is another way which I haven't think about.
In any case thanks for your advice, here is what I tend to...
I've implemented this by placing the image in a RelativeLayout (FrameLayout would work too), and then adding each outlined view programatically. If you know the x and y origin (perhaps as a ratio to the image) and the size for each area, you can easily inflate each view/area (with a black border, transparent center), make it clickable and set a listener, and then set it's origin by adjusting it's margins. You may want to perform all of this after the image has finished laying out:
I put this in onActivityCreated of my Fragment, but other lifecycle methods would work too...
ViewTreeObserver vto = image.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (image.getMeasuredHeight() > 0) {
addHotSpots();
ViewTreeObserver obs = image.getViewTreeObserver();
obs.removeGlobalOnLayoutListener(this);
}
}
});
And this is how I actually place all the hotspots/areas:
protected void addHotSpots() {
HotSpot[] hotSpots = res.hotspots;
for (HotSpot hs : hotSpots) {
addHotSpotToImage(hs);
}
private void addHotSpotToImage(HotSpot hs) {
int height = image.getMeasuredHeight();
int width = image.getMeasuredWidth();
//this piece will probably be different for you
//depending on what you know about the area's intended size/position
double hsHeightRatio = hs.lr.y - hs.ul.y;
double hsWidthRatio = hs.lr.x - hs.ul.x;
double leftMargin = hs.ul.x * width;
double topMargin = hs.ul.y * height;
double hsHeight = height * hsHeightRatio;
double hsWidth = width * hsWidthRatio;
LayoutInflater vi = (LayoutInflater) image.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View newSpot = vi.inflate(R.layout.question_hotspot, null);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams((int) hsWidth, (int) hsHeight);
newSpot.setTag(hs.key);
newSpot.setFocusable(true);
newSpot.setClickable(true);
newSpot.setFocusableInTouchMode(true);
newSpot.setOnTouchListener(this);
params.topMargin = (int) topMargin;
params.leftMargin = (int) leftMargin;
image.addView(newSpot, params);
}

How to get height and width of Button

I have created an array of buttons. Now I want to find the height and width of the button, and for that, I have used getWidth() and getHeight(). But the thing is that it always returns 0. Why is this happening? I have send my code, please check if anything is wrong.
LinearLayout layoutVertical = (LinearLayout) findViewById(R.id.liVLayout);
LinearLayout rowLayout = null;
LayoutParams param = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, 1);
public static void main(String[] args)
{
DBFacade dbFacade = new DBFacade();
dbFacade.pick();
}
//Create Button
for(int i=0;i<6;i++)
{
rowLayout=new LinearLayout(this);
rowLayout.setWeightSum(7);
layoutVertical.addView(rowLayout,param);
for(int j=0;j<7;j++)
{
m_pBtnDay[i][j]=new Button(this);
rowLayout.addView(m_pBtnDay[i][j],param);
m_pBtnDay[i][j].setOnLongClickListener(this);
m_pBtnDay[i][j].setGravity(Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL);
m_pBtnDay[i][j].setTextSize(12);
}
}
x=m_pBtnDay[i][j].getWidth();
y=m_pBtnDay[i][j].getHeight();
Log.d("width",Integer.toString(x));
Log.d("Height",Integer.toString(y));
return true;
Probably you are calling getWidth() and getHeight() too early: I think the UI has not been sized and laid out on the screen yet...
You can try to put that code inside this:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
// Call here getWidth() and getHeight()
}
Another way
ViewTreeObserver vto = button.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
width = button.getWidth();
height = button.getHeight();
}
});
put this in your loop
x = m_pBtnDay[i][j].getWidth();
y = m_pBtnDay[i][j].getHeight();
Log.d("width", Integer.toString(x));
Log.d("Height", Integer.toString(y));
try it
You try to use the count-variable "i" and "j" to use outside from both for-loops. That should raise an exception because the are only availabil in each for-block.
Try to make the output in the second for-loop...
for (int i = 0; i<6; i++)
{
...
for(int j=0; j<7; j++)
{
....
x = m_pBtnDay[i][j].getWidth();
y = m_pBtnDay[i][j].getHeight();
Log.d("width", Integer.toString(x));
Log.d("Height", Integer.toString(y));
}
}
You can override the following View method, called during the layout phase.
protected void onSizeChanged (int w, int h, int oldw, int oldh)
This seems more appropriate, as it expressly accounts for the zero width and height you're observing:
This is called during layout when the size of this view has changed.
If you were just added to the view hierarchy, you're called with the
old values of 0.
Parameters w Current width of this view. h Current height of this
view. oldw Old width of this view. oldh Old height of this view.
See here.
Try this can also work:
btn.getDrawingCache().getHeight() and btn.getDrawingCache().getWidth()

Categories

Resources