Skip to content

Commit 4d2c5b9

Browse files
authored
Merge pull request #8 from PureSwift/feature/layout-fixes
Fix stack alignment and Spacer expansion
2 parents ca16a26 + ad2ad64 commit 4d2c5b9

2 files changed

Lines changed: 34 additions & 6 deletions

File tree

‎Sources/AndroidSwiftUI/AndroidRenderer.swift‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ final class AndroidRenderer: Renderer {
7373
return nil
7474
}
7575
let viewObject = anyView.createAndroidView(context)
76+
applyStackLayoutParams(for: host.view, to: viewObject, in: parentView)
7677
// TODO: Determine order
7778
viewGroup.addView(viewObject)
7879
if let transitioning = mapAnyView(host.view, transform: { (view: AndroidTransitioningView) in view }) {
@@ -233,6 +234,28 @@ final class AndroidRenderer: Renderer {
233234

234235
private extension AndroidRenderer {
235236

237+
/// Assigns layout parameters to a child added to a stack's `LinearLayout`.
238+
///
239+
/// Children without their own parameters hug their content, so the stack's alignment
240+
/// gravity can position them — Android's default of stretching children to match the
241+
/// parent's width would leave gravity with no room to act. Views conforming to
242+
/// `AndroidExpandingView` (such as `Spacer`) instead receive weighted parameters and
243+
/// grow to fill the remaining space along the stack's axis.
244+
func applyStackLayoutParams(for view: AnyView, to viewObject: AndroidView.View, in parentView: AndroidView.View) {
245+
guard let linearLayout = parentView.as(AndroidWidget.LinearLayout.self) else { return }
246+
let wrapContent = try! JavaClass<ViewGroup.LayoutParams>().WRAP_CONTENT
247+
let isVertical = linearLayout.orientation == .vertical
248+
if mapAnyView(view, transform: { (view: AndroidExpandingView) in view }) != nil {
249+
let params = isVertical
250+
? AndroidWidget.LinearLayout.LayoutParams(wrapContent, 0, Float(1))
251+
: AndroidWidget.LinearLayout.LayoutParams(0, wrapContent, Float(1))
252+
viewObject.setLayoutParams(params.as(ViewGroup.LayoutParams.self))
253+
} else if viewObject.getLayoutParams() == nil {
254+
let params = AndroidWidget.LinearLayout.LayoutParams(wrapContent, wrapContent)
255+
viewObject.setLayoutParams(params.as(ViewGroup.LayoutParams.self))
256+
}
257+
}
258+
236259
/// Handler bound to the Android main looper, used to schedule reconciler updates.
237260
static let mainHandler = AndroidOS.Handler(try! JavaClass<AndroidOS.Looper>().getMainLooper())
238261

‎Sources/AndroidSwiftUI/AndroidSpacer.swift‎

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,21 @@
77

88
import AndroidKit
99

10-
extension Spacer: AnyAndroidView {
10+
/// An Android view that expands to fill the remaining space along its parent stack's axis.
11+
///
12+
/// The renderer assigns weighted layout parameters when a conforming view is added to a
13+
/// `LinearLayout`, so the view grows to absorb the leftover space.
14+
protocol AndroidExpandingView { }
15+
16+
extension Spacer: AnyAndroidView, AndroidExpandingView {
1117

12-
// NOTE: does not yet flex-grow to fill remaining space in its parent stack (that would require
13-
// AndroidRenderer's generic `addView` mounting to apply per-child LayoutParams, e.g. `layout_weight`,
14-
// which it doesn't do today). Rendered as a minimal-size placeholder so layouts that include a
15-
// `Spacer()` (e.g. List's internal row padding) still mount without crashing.
1618
public func createAndroidView(_ context: AndroidContent.Context) -> AndroidView.View {
1719
let view = AndroidView.View(context)
20+
// the renderer applies weighted layout parameters inside stacks; the minimum
21+
// dimensions preserve `minLength` in either axis
1822
let length = Int32(minLength ?? 0)
19-
view.setLayoutParams(ViewGroup.LayoutParams(length, length))
23+
view.setMinimumWidth(length)
24+
view.setMinimumHeight(length)
2025
return view
2126
}
2227

0 commit comments

Comments
 (0)