我有一个像这样的 JSON:
{
"name": "view",
"attributes": {
"style": {
"backgroundColor": "yellow",
}
},
"children": [
{
"name": "view",
"attributes": {
"style": {
"backgroundColor": "red",
"width": 400,
"height": 400,
}
}
},
{
"name": "view",
"attributes": {
"style": {
"backgroundColor": "yellow",
"top": 150,
"left": 100,
"width": 200,
"height": 200,
}
}
}
]
}
我正在使用递归来显示基于该 JSON 的布局。
我的 CustomLayout 扩展自 ViewGroup。它类似于 LinearLayout。
public static class CustomLayout extends ViewGroup {
private int orientation; // 0 for horizontal, 1 for vertical
public CustomLayout(Context context) {
super(context);
}
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
// Set the orientation (horizontal or vertical)
public void setOrientation(int orientation) {
this.orientation = orientation;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Measure the size of your layout and its children here
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width = 0;
int height = 0;
// Measure each child view
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
if (orientation == 0) { // Horizontal layout
width += child.getMeasuredWidth();
height = Math.max(height, child.getMeasuredHeight());
} else { // Vertical layout
width = Math.max(width, child.getMeasuredWidth());
height += child.getMeasuredHeight();
}
}
// Take padding into account
width += getPaddingLeft() + getPaddingRight();
height += getPaddingTop() + getPaddingBottom();
// Respect the given measure spec
width = resolveSizeAndState(width, widthMeasureSpec, 0);
height = resolveSizeAndState(height, heightMeasureSpec, 0);
setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : width,
heightMode == MeasureSpec.EXACTLY ? heightSize : height);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// Position child views within your layout here
int childLeft = getPaddingLeft();
int childTop = getPaddingTop();
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (orientation == 0) { // Horizontal layout
child.layout(childLeft, childTop,
childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight());
childLeft += child.getMeasuredWidth();
} else { // Vertical layout
child.layout(childLeft, childTop,
childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight());
childTop += child.getMeasuredHeight();
}
}
}
}
递归最终的结果是这样的:
LinearLayout rootView = activity.findViewById(R.id.root);
CustomLayout view = new CustomLayout(activity);
view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
view.setOrientation(1);
view.setBackgroundColor(Color.parseColor("yellow"));
View child1 = new CustomLayout(activity);
View child2 = new CustomLayout(activity);
child1.setLayoutParams(new LayoutParams(400, 400));
child1.setBackgroundColor(Color.parseColor("red"));
child2.setLayoutParams(new LayoutParams(200, 200));
child2.setBackgroundColor(Color.parseColor("green"));
view.addView(child1);
view.addView(child2);
rootView.addView(view);
我的问题是,如何申请
top
和left
?
这就是我想要实现的目标:
使用 React Native 得到了想要的结果。这是代码:
function App(): React.JSX.Element {
return (
<View style={{backgroundColor: 'yellow'}}>
<View style={{backgroundColor: 'red', width: 200, height: 200}}></View>
<View
style={{
backgroundColor: 'green',
top: 100,
left: 50,
width: 150,
height: 150,
}}></View>
</View>
);
}
如您所见,黄色包装器根据其子级获得正确的宽度和高度,并且绿色视图被移到包装器之外而不会被剪切。
React Native 也使用自己的布局扩展 ViewGroup,所以一定有办法。
解决方案是将这些行添加到每个父级:
setClipChildren(false);
setClipToPadding(false);
大概是这样的:
public CustomLayout(Context context) {
super(context);
setClipChildren(false);
setClipToPadding(false);
}
在 onLayout 中我们有类似的东西:
int x = 30; // 30 to the left
int y = 0;
child.layout(x, y, x + childWidth, y + childHeight);