I'm working on a family-tree like app. I use a force-directed layout algorithm to calculate the positions on which the nodes will be placed. The nodes are a custom view that I created myself called PersonCard
. Here's a snippet from my PersonCard
:
private void init(AttributeSet attrs) {
// Initialize anchors
rightAnchor = new View(getContext());
int anchorColor = ContextCompat.getColor(getContext(), R.color.tea_rose);
int anchorSize = 10;
rightAnchor.setBackgroundColor(anchorColor);
FrameLayout.LayoutParams rightAnchorParams = new FrameLayout.LayoutParams(anchorSize, anchorSize);
rightAnchorParams.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT;
rightAnchorParams.rightMargin = -padding;
rightAnchor.setLayoutParams(rightAnchorParams);
addView(rightAnchor);
}
Because I will need to connect these different PersonCards
, I created different anchors
(one on each side of a PersonCard
) so that there are unified spots where I can connect my PersonCards
with a Line
view.
After the algorithm has calculated the positions for each PersonCard
, I get the x and y coordinates like this and place the PersonCards
accordingly:
Node 1: (489.70685469968083, 1534.7124300016587)
Node 2: (995.1782137460826, 731.7942097127028)
Node 3: (58.578329522505925, 716.785942983157)
Node 4: (534.2392750542016, 996.037653894383)
Node 5: (43.46557962124075, 1243.6774403463626)
Node 6: (530.856915894992, 454.41864708395013)
Node 7: (978.3108846322139, 1287.7832880796614)
In my PersonCard
, I created methods to get the position of the anchors:
private int[] getAnchorPosition(ViewGroup parent, View anchor) {
int[] anchorPosition = new int[2];
int[] parentPosition = new int[2];
anchor.getLocationOnScreen(anchorPosition);
parent.getLocationOnScreen(parentPosition);
anchorPosition[0] -= parentPosition[0];
anchorPosition[1] -= parentPosition[1];
Log.d("AnchorPosition", "Anchor X: " + anchorPosition[0] + ", Y: " + anchorPosition[1]);
return anchorPosition;
}
public int[] getRightAnchorPosition(ViewGroup parent) {
return getAnchorPosition(parent, rightAnchor);
}
However, how can it be that this method gives me completely wrong coordinates? When I call it, it gives me something like this for the rightAnchor
of Node 1
:
Node 1: X is: 200, Y is: 203
As you can see, this doesn't match the real coordinates of Node 1
at all. And for some strange reason, all the other rightAnchors
of the PersonCards
have the same coordinates?
Node 2: X is: 200, Y is: 203
Node 3: X is: 200, Y is: 203
Node 4: X is: 200, Y is: 203
and so on...
I'm not sure where this weird behaviour stems from. As for my layout, I just add my PersonCards
to a FrameLayout
, which is the child of another FrameLayout
.
In order not to fall for some layout computing shenanigans, I used .post
to make sure my layout has finished computing before I call getRightAnchorPosition
:
personCard.post(new Runnable() {
@Override
public void run() {
int[] rightAnchorPos = personCard.getRightAnchorPosition(origin_frameLayout);
Log.d("RightAnchor", "X is: " + rightAnchorPos[0] + ", Y is: " + rightAnchorPos[1]);
}
});
However, this still gives me the same coordinates that I showed above.
Why exactly do I get this weird behaviour, and how can I possibly fix it?
Of course it was a problem with the lifecycle of my activity. When I use ViewTreeObserver.OnGlobalLayoutListener
instead of .post
, the coordinates are returned perfectly.