Center Item Inside Horizontal Stack

Center Item Inside Horizontal Stack

I would propose the following start point (simplest case... read below why)

Center horizontally one element

As it's seen it really gives centred w/o frame shift with correctly aligned side elements, but ... there is drawback - it will work in such simplest variant only if it is known in advance that those three text elements should never overlap in user run-time. If it is the case (really there are such) then this approach just goes. However if left/right text might grow in run-time, then more calculations will be needed to limit their width by .frame(maxWidth:) depending on the width of centred element... that variant is more complicated, but it is feasible.

var body: some View {
ZStack {
HStack {
Text("Longer side")
Spacer()
Text("One")
}
item2()
}
}

private func item2() -> some View {
Text("CENTER")
.background(Color.yellow)
.border(Color.red)
}

Update: here is possible approach to limit one of the side to not overlap centred one (contains async updates, so should be tested in Live Preview or Simulator)

So... if left text is dynamic and the requirement to cut trailing symbols, here is how it could go ...

Sample Image

and it automatically fit well on device orientation change

Sample Image

struct TestHorizontalPinCenter: View {

@State var centerFrame: CGRect = .zero

private let kSpacing: CGFloat = 4.0
var body: some View {
ZStack {
HStack {
Text("Longer side very long text to fit")
.lineLimit(1)
.frame(maxWidth: (centerFrame == .zero ? .infinity : centerFrame.minX - kSpacing), alignment: .leading)

Spacer()

Text("One")
}
item2()
.background(rectReader($centerFrame))
}
}

private func item2() -> some View {
Text("CENTER")
.background(Color.yellow)
.border(Color.red)
}

func rectReader(_ binding: Binding<CGRect>) -> some View {
return GeometryReader { (geometry) -> AnyView in
let rect = geometry.frame(in: .global)
DispatchQueue.main.async {
binding.wrappedValue = rect
}
return AnyView(Rectangle().fill(Color.clear))
}
}
}

And if it is needed to wrap left side, then .lineLimit(nil) and additional layout will be needed, and solution growth, but the idea is the same. Hope this will be helpful for someone.

Align items in horizontal UIStackView from the center

Set parent UIStackView (vertical stackView) alignment to center.Sample Image

Align only one object to the centre in an HStack

You can make use of alignment guides. This answer also centers the vs to the screen, not just relative to each other.

Code:

struct ContentView: View {
private let games: [Game] = [
Game("Manchester United", vs: "Arsenal"),
Game("Liverpool", vs: "Newcastle United")
]

var body: some View {
ZStack(alignment: .centerVs) {
Color.clear
.frame(height: 0)
.frame(maxWidth: .infinity)
.alignmentGuide(.centerVs) { d in
d[HorizontalAlignment.center]
}

VStack(alignment: .centerVs) {
ForEach(games) { game in
HStack {
Text(game.team1)

Text("vs")
.alignmentGuide(.centerVs) { d in
d[HorizontalAlignment.center]
}

Text(game.team2)
}
}
}
}
}
}
struct Game: Identifiable {
let id = UUID()
let team1: String
let team2: String

init(_ team1: String, vs team2: String) {
self.team1 = team1
self.team2 = team2
}
}
extension HorizontalAlignment {
private struct CenterVsAlignment: AlignmentID {
static func defaultValue(in context: ViewDimensions) -> CGFloat {
context[HorizontalAlignment.center]
}
}

static let centerVs = HorizontalAlignment(CenterVsAlignment.self)
}

extension Alignment {
static let centerVs = Alignment(horizontal: .centerVs, vertical: .center)
}

Result:

Result

How to vertically or horizontally center a Widget in a Stack?

Use Align Widget

 Align(
alignment: Alignment.topCenter, // This will horizontally center from the top
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black87, width: 10)),
child: Stack(
children: [
Container(color: Colors.amber, width: 50, height: 50),
],
),
),
)

1. For Top Center use alignment: Alignment.topCenter

Sample Image

2. For Center Left use alignment: Alignment.centerLeft

Sample Image

3. For Center right use alignment: Alignment.centerRight

Sample Image

3. For Bottom center use alignment: Alignment.bottomCenter

Sample Image

How to Center a Positioned() horizontally in Flutter

For placing the widget exactly in the center, you should use the alignment property of Stack widget.

Suppose you have a Text widget inside Positioned widget that you want to be in the exact center. Then, just remove the Positioned widget & use the alignment property & set it to Alignment.center as show below:

Previous widget:

Stack(
children: [
Positioned( // This widget needs to be exactly in the center
child: Text('Some text'),
),

// Other widgets
],
),

Placing widgets in the center

Stack(
alignment: Alignment.center, // <---------
children: [
Text('Some text'),
// Other widgets
],
),

This way any widget inside the Stack will be centered by default. If you want to change the position of other widgets, then you should use Positioned widget.

Horizontal UIStackView - how to align items inside so that one is floated left and the other sticks in center?

You have a few options...


The simplest, and closest to your CSS description:

Sample Image

Button is constrained 0 from top, 8 from leading (adjust as desired); label is constrained centered vertically to button, centered horizontally to view.

The drawback: if label gets too much text, it will overlap the button.


Second option:

Sample Image

Same as above, but add a "spacer" UIView to upper right... constrain it 0 to top, 8 to trailing, centered vertically to button, and constrain it equal width and equal height to button. Then, add >= 8 constraints to the label leading to button trailing, and label trailing to spacer view leading. That will allow the label to expand horizontally based on its text, but will prevent overlap (text will be ... truncated if there is too much to fit).


Third option - using stack view:

Sample Image

Stack view settings:

Axis: Horizontal
Alignment: Fill
Distribution: Fill
Spacing: 8

Constrain the stack view 0 to top, 8 leading and trailing (just for a little padding on the sides), add a button, label and UIView. Constrain the
"spacer" view equal width to the button. Set the Horizontal Content Hugging Priority = 1000 for the button (will keep it the width of its title).

There are other approaches, partially depending on if you want to do anything else you haven't shown here, but all three of these will do the job.

How can I horizontally center an element?

You can apply this CSS to the inner <div>:

#inner {
width: 50%;
margin: 0 auto;
}

Of course, you don't have to set the width to 50%. Any width less than the containing <div> will work. The margin: 0 auto is what does the actual centering.

If you are targeting Internet Explorer 8 (and later), it might be better to have this instead:

#inner {
display: table;
margin: 0 auto;
}

It will make the inner element center horizontally and it works without setting a specific width.

Working example here:

#inner {
display: table;
margin: 0 auto;
border: 1px solid black;
}

#outer {
border: 1px solid red;
width:100%
}
<div id="outer">
<div id="inner">Foo foo</div>
</div>

Center views horizontally in iOS stack view

Just center your stack view horizontally in its superview.

Examples below are using UIKitPlus library (it is pure UIKit but declarative and support LivePreview, iOS9+)

UView {
UHStack {
UView {
UText("Yes")
.color(.green)
.edgesToSuperview(h: 8, v: 4)
}
.border(1, .green)
.circle()
UView {
UText("No")
.color(.red)
.edgesToSuperview(h: 8, v: 4)
}
.border(1, .red)
.circle()
UView {
UText("I don't know")
.color(.darkGray)
.edgesToSuperview(h: 8, v: 4)
}
.border(1, .darkGray)
.circle()
}
.alignment(.center)
.distribution(.equalSpacing)
.spacing(10)
.edgesToSuperview(v: 0)
.centerXInSuperview() // this will center your stack view
}
.edgesToSuperview(h: 0)
.centerYInSuperview()

First solution

Or use a little hack by adding two views with equal width, one in the beginning of stack and one as the last view in stack.

let v1 = UView()
UHStack {
v1
UView {
UText("Yes")
.color(.green)
.edgesToSuperview(h: 8, v: 4)
}
.border(1, .green)
.circle()
UView {
UText("No")
.color(.red)
.edgesToSuperview(h: 8, v: 4)
}
.border(1, .red)
.circle()
UView {
UText("I don't know")
.color(.darkGray)
.edgesToSuperview(h: 8, v: 4)
}
.border(1, .darkGray)
.circle()
UView().width(to: v1)
}
.alignment(.center)
.spacing(10)
.edgesToSuperview(h: 0)
.centerYInSuperview()

Second solution

The stack view itself can't center inner views automatically unfortunately, so you have to help it to do that.



Related Topics



Leave a reply



Submit