getLocationOnScreen of a child of GridLayout - android

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

Related

Increase LinearLayout width from either right or left

I have a LinearLayout which is centered on the screen. It has a width less than the screen width. There are two buttons: Right-Arrow and Left-Arrow.
When the user presses the relevant button, the layout should increase its width from the relevant side. The other side should keep its position there.
Right now setting the width increases the layout from both sides equally. The layout needs to be initially centered and it has to expand from either side by user's input. (Use case is to find the width of relevant part of an image whose right and left sides have unequal borders, so the user has to mark them using my technique).
I am using following to increase width but it has the behaviour described above.
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)
llCropOverlay.getLayoutParams();
params.width = params.width + 1;
PS: This functionality was implemented in Tasker app since its early days; so it is possible.
EDIT:
Here is the layout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:gravity="top"
android:layout_gravity="top"
android:id="#+id/iv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible" />
<LinearLayout
android:id="#+id/llRightLeft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<Button
android:id="#+id/bLeft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LEFT" />
<Button
android:id="#+id/bRight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RIGHT" />
</LinearLayout>
<LinearLayout
android:layout_gravity="center_horizontal"
android:id="#+id/llCropOverlay"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="#color/colorCropOverlay"
android:orientation="vertical" />
</FrameLayout>
</LinearLayout>
The last LinearLayout (llCropOverlay) should be resized. Note that I am programatically changing the width to 300 before using resizing the buttons so I can test if the buttons are working.
I have found an almost perfect solution (there is sometimes a problem with one pixel which is annoying - any suggestions will be appreciated).
For this, we need some variables set up. Firstly, the LinearLayout called llCropOverlay must be found and identified.
Here is its xml:
<LinearLayout
android:layout_gravity="center_horizontal"
android:id="#+id/llCropOverlay"
android:layout_width="200dp"
android:layout_height="150dp"
android:background="#color/colorCropOverlay"
android:orientation="vertical" />
Now before allowing user to interact we need to find the original position of the llCropOverlay. So use this in OnCreate():
llCropOverlay.post(new Runnable() {
#Override
public void run() {
orgX = llCropOverlay.getX();
}
});
Now set up all the buttons and set a setOnTouchListener() on these buttons. Then when the listener is called, pass the touched button in the following method. Use a Handler and postDelayed() to keep calling this method till the button is pressed. Or call it once to resize by one pixel row/column.
void handleTouchOrClick(View view) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)
llCropOverlay.getLayoutParams();
switch (view.getId()) {
case R.id.bUp:
params.height = params.height - 1;
break;
case R.id.bDown:
params.height = params.height + 1;
break;
case R.id.bRight:
params.width = params.width + 1;
llCropOverlay.post(new Runnable() {
#Override
public void run() {
llCropOverlay.setX(orgX);
}
});
break;
case R.id.bRightContract:
params.width = params.width - 1;
llCropOverlay.post(new Runnable() {
#Override
public void run() {
llCropOverlay.setX(orgX);
}
});
break;
case R.id.bLeft:
params.width = params.width + 1;
orgX--;
llCropOverlay.post(new Runnable() {
#Override
public void run() {
llCropOverlay.setX(orgX);
}
});
break;
case R.id.bLeftContract:
params.width = params.width - 1;
orgX++;
llCropOverlay.post(new Runnable() {
#Override
public void run() {
llCropOverlay.setX(orgX);
}
});
break;
}
llCropOverlay.setLayoutParams(params);
}
Now here's how we actually resize the image:
For ease of users I am cropping it in two steps.
Crop from sides:
ViewGroup.MarginLayoutParams params =
(ViewGroup.MarginLayoutParams) llCropOverlay.getLayoutParams();
float eventX = params.width;
float eventY = 0;
float[] eventXY = new float[]{eventX, eventY};
Matrix invertMatrix = new Matrix();
imageView.getImageMatrix().invert(invertMatrix);
invertMatrix.mapPoints(eventXY);
int x = Integer.valueOf((int) eventXY[0]);
int y = Integer.valueOf((int) eventXY[1]);
int height = params.height;
while (height * 3 > originalBitmap.getHeight()) {
height = height - 10;
}
croppedBitmapByWidth = Bitmap.createBitmap(originalBitmap, (int) orgX, 0,
x, height);
imageView.setImageBitmap(croppedBitmapByWidth);
crop from bottom:
float eventX2 = 0;
float eventY2 = params.height;
float[] eventXY2 = new float[]{eventX2, eventY2};
Matrix invertMatrix2 = new Matrix();
imageView.getImageMatrix().invert(invertMatrix2);
invertMatrix2.mapPoints(eventXY2);
int x2 = Integer.valueOf((int) eventXY2[0]);
int y2 = Integer.valueOf((int) eventXY2[1]);
croppedBitmapByHeight = Bitmap.createBitmap(croppedBitmapByWidth, 0, 0,
croppedBitmapByWidth.getWidth(), y2);
imageView.setImageBitmap(croppedBitmapByHeight);

Different values of width returned in fragment

I'm trying to determine the screen's width and height to use them in a fragment.
My fragment's layout has the id background.
If inside onViewCreated I use:
background = (RelativeLayout) view.findViewById(R.id.background);
background.post(new Runnable() {
#Override
public void run() {
int width = background.getMeasuredWidth();
int height = background.getMeasuredHeight();
Log.d("askj", width + "+" + height);
}
});
I get 1440+2276
but if I use:
WindowManager windowManager = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
int height = displayMetrics.heightPixels;
Log.d("askj", width + "+" + height);
or other related methods I get:
1440+2560
I'm using those parameters to set a background and I can clearly see that the whole screen size is not taken if I use the second approach. I don't really want to use that Runnable() so is there any way in which I can solve this ?
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/background"
tools:context="com.example.home.background.HomeScreen">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/img"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textStyle="bold"
android:layout_centerInParent="true"
android:textSize="22sp"
/>
</RelativeLayout>
You can measure the background View before your activity has added it to its view hierarchy by yourself using measure method.
background = (RelativeLayout) view.findViewById(R.id.background);
background.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
int backgroundHeight = background.getMeasuredHeight();
int backgroundWidth = background.getMeasuredWidth();
In my case I measured an inflated View but it had the width and height set to match_paent.
View view = inflater.inflate(R.layout.table_field_text, null, false);
view.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
int viewHeight = view.getMeasuredHeight();
Use ViewTreeObserver like Below:
background = (RelativeLayout) view.findViewById(R.id.background);
final ViewTreeObserver vto = background.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
//get View Width and height here
int width = background.getWidth();
int height = background.getHeight();
//Call anyfunction which uses width and height here
function(width,height);
//Then remove layoutChange Listener
ViewTreeObserver vto = background.getViewTreeObserver();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
vto.removeOnGlobalLayoutListener(this);
} else {
vto.removeGlobalOnLayoutListener(this);
}
}
});

RelativeLayout getWidth returns zero

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

how to animate listview expand and collapse

Having a text displayed initially at screen bottom. When clicking on it, the list view below it should sliding up. Clicking on the text again the list view sliding down.
Made it work with the snippet below except the first time clicking on the text the list does not do the animation sliding up. After that it will animate sliding up/down as expected.
It is because in the first clicking and call of showListView(true); since the list view’s visibility was “gone”, so it has not had height. The “y” == 0 translate does not do anything. It is just the list view’s visibility change to “visible”, which push the titleRow change its position.
But if to begin with the list view’s visibility to “visible”, the initial showListView(false); in setupListViewAdapter() does not push the list view down to initial state (outside of screen bottom) since it does not have the height until the list row are filled in from the adapter by mListView.setAdapter(mListAdapter).
Is there better way to do sidling up/down the list view?
<TextView
android:id="#+id/titleRow”
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=“title row”
/>
<ListView
android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility=“gone”
>
</ListView>
initial state list view collapsed(outside screen bottom)
+++++++++++++++++++++++++++
+ mTitleRow + ^ +
+++++ screen bottom +++++
listview expanded
+++++++++++++++++++++++++++
+ mTitleRow + ^ +
+++++++++++++++++++++++++++
+ +
+ mListView +
+ +
+++++ screen bottom +++++
void setupListViewAdapter(){
mTitleRow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mTitleRow.getTag() == STATE_COLLAPSED)
{
mListView.setVisibility(View.VISIBLE);
showListView(true);
} else {
showListView(false);
}
}
});
mListView.setAdapter(mListAdapter);
showListView(false);
}
private static final int STATE_EXPANDED = 1;
private static final int STATE_COLLAPSED = 2;
boolean mListInAnimation = false;
public void showListView(final boolean show) {
if (mListView != null && !mListInAnimation) {
mListInAnimation = true;
mTitleRow.setTag(show ? STATE_EXPANDED : STATE_COLLAPSED);
int translateY = show ? 0 : (listHeight);
mTitleRow.animate().translationY(translateY).setDuration(300).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mListInAnimation = false;
}
});
}
}
You can do this very easily using API 16's LayoutTransition.CHANGING.
Set animateLayoutChanges to true on the parent ViewGroup:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parent"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
android:animateLayoutChanges="true">
<TextView
android:id="#+id/titleRow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="title row"/>
<ListView
android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="0dp"/>
</LinearLayout>
Enable LayoutTransition.CHANGING; on click of the title, set the height of the list view:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.parent);
linearLayout.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
final View listView = findViewById(R.id.list_view);
View titleRow = findViewById(R.id.titleRow);
titleRow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = params.height == 0 ? ViewGroup.LayoutParams.WRAP_CONTENT : 0;
listView.setLayoutParams(params);
}
});
}

button with image is not responding to onclick listener when scrolling

I am a android beginner, I have added images dynamically inside the linear layout, which will scroll from right to left. The problem is that the images are moving / scrolling properly but when I click on it the on-click listener is not called.
Actually when moving the images the image button is moving but the onclick position is not changed according to the image scrolling.
public class ImageLayoutsActivity extends Activity {
int ImageInt, fromXDelta, toXDelta;
int PosInt, myHarizantalLayoutInt, aDisplayInt, aDisplayDiv = 0;
AnimationSet myAnimation = new AnimationSet(true);
LinearLayout myHarizantalLayout;
HorizontalScrollView myHorizontalScroll;
View myView;
Intent myIntent;
private Button clickedButton = null;
public int currentimageindex = 0;
TranslateAnimation myTranslateAnimation = null;
private String[] imgArr = { "icn01", "icn02" };
private String[] URLArray = { "http://www.google.co.in/",
"http://in.yahoo.com/?p=us" };
LinearLayout.LayoutParams Parems;
Display aDisplay;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View aView = LayoutInflater.from(GroupActivity.myGroup).inflate(
R.layout.horizantal, null);
setContentView(aView);
GroupActivity.myGroup.setTitle("---CII---");
aDisplay = getWindowManager().getDefaultDisplay();
aDisplayInt = aDisplay.getWidth();
aDisplayDiv = aDisplayInt / 5;
Log.i("value##########################", String.valueOf(aDisplayDiv));
Log.i("aDisplayInt##########################",
String.valueOf(aDisplayInt));
// define xml layout here
myHarizantalLayout = (LinearLayout) findViewById(R.id.horiztonal_outer_layout_id);
myHorizontalScroll = (HorizontalScrollView) findViewById(R.id.horiztonal_scrollview_id);
// Button aBtnOne = (Button) findViewById(R.id.BtnOneId);
// Hide HorizantalLayout scroll bar
myHorizontalScroll.setHorizontalScrollBarEnabled(false);
myHorizontalScroll.isSmoothScrollingEnabled();
myHarizantalLayout.measure(aDisplay.getWidth(), aDisplay.getHeight());
Log.v("EmailActivity#########", myHarizantalLayout.getMeasuredHeight()
+ ", " + myHarizantalLayout.getMeasuredWidth());
int aLayoutInt = myHarizantalLayout.getMeasuredWidth();
Log.i("aLayoutInt###########", String.valueOf(aLayoutInt));
// Add images in for loop
for (int i = 0; i < imgArr.length; i++) {
// int aVal=myHarizantalLayout.getChildCount();
Log.i("ImageInt############################", "=====Inside the loop======");
// create button instance
final Button aImgBtn = new Button(this);
// myButton.setOnClickListener(null);
// add background image resource files
ImageInt = getResources().getIdentifier(imgArr[i], "drawable",
getPackageName());
Log.i("ImageInt############################", "ImageInt");
// add integer image values to drawable control
Drawable aDrawable = this.getResources().getDrawable(ImageInt);
Log.i("aDrawable$$$$$$$$$$$$$$$$$$$$$$$$$", "aDrawable");
// add drawable file to button instance
aImgBtn.setBackgroundDrawable(aDrawable);
aImgBtn.measure(aDisplay.getHeight(), aDisplay.getWidth());
Log.i("aButton#############################", "aButton");
Parems = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
Parems.setMargins(10, 0, 5, 0);
Log.i("Parems%%%%%%%%%%%%%%%%%%%%%%%%%%", "Parems");
// int aParemIn = Parems.width;
// Log.i("aparemIn$$$$$$$$$$$$", String.valueOf(aParemIn));
myHarizantalLayout.measure(aDisplay.getHeight(),
aDisplay.getWidth());
int myHarizantalLayoutInt = myHarizantalLayout.getMeasuredWidth();
Log.i("myHarizantalLayoutInt$$$$$$$$$$$$",
String.valueOf(myHarizantalLayoutInt));
myTranslateAnimation = new TranslateAnimation(aDisplayInt - 300,
-myHarizantalLayoutInt - aDisplayDiv, 0, 0);
myTranslateAnimation.setDuration(20000);
myTranslateAnimation.setRepeatCount(-1);
myTranslateAnimation.setRepeatMode(1);
myAnimation.addAnimation(myTranslateAnimation);
Log.i("myAnimation###########################", "myAnimation");
aImgBtn.setLayoutParams(Parems);
myHarizantalLayout.addView(aImgBtn);
Log.i("myHarizantalLayout&&&&&&&&&&&&&&&&&&&&&&&&&",
"myHarizantalLayout");
// add animation to HarizantalLayout
myHarizantalLayout.startAnimation(myTranslateAnimation);
// Call webview based on image button click event
aImgBtn.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
Log.i("view$$$$$$$$$$$$#############", "---btn clicked -----");
int aVal = myHarizantalLayout.indexOfChild(view);
Log.i("indexOfChild*************************",
"indexOfChild");
if (view == aImgBtn) {
Log.i("aButton%%%%%%%%%%%%%%%%%%%%%%%%", "aButton");
aImgBtn.setId(aVal);
String aUrlStr = URLArray[aVal];
Log.i("aUrlStr$$$$$$$$$$$$#############", aUrlStr);
}
// Log.i("aUrlStr$$$$$$$$$$$$#############", aUrlStr);
// Pass values to webview activity
}
}
}
xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:gravity="bottom" android:background="#00f">
<LinearLayout android:layout_below="#+id/RelativeLayout"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="horizontal" android:gravity="bottom">
<ImageView android:id="#+id/barImageId"
android:layout_width="150dp" android:layout_height="58dp"
android:background="#drawable/cii" android:layout_alignParentRight="true" />
<HorizontalScrollView android:layout_width="fill_parent"
android:layout_height="58dp" android:id="#+id/horiztonal_scrollview_id"
android:fadingEdge="none" android:background="#000" >
<LinearLayout android:id="#+id/horiztonal_outer_layout_id"
android:fadingEdge="none" android:layout_height="fill_parent" android:gravity="center_vertical"
android:layout_width="fill_parent" android:background="#f00">
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
</RelativeLayout>
Try to Use Pager instead of HorizontalScrollView,
This link may be helpful https://github.com/nostra13/Android-Universal-Image-Loader

Categories

Resources