SwiftUI - How to resize PickerView? - swiftui

How do you resize the picker view in SwiftUI? I need to change the width that it takes up. My code below is just a simple view with a picker inside it. Changing the width parameter does not change the width of the picker view.
struct CalibrationBar: View {
#State var tone = Int()
var body: some View{
HStack{
Button(action: {
playTone(tone: self.tone, amp: 50, stop: true)
}) {
Text("50 dB")
}
.frame(width: 60.0)
Picker(selection: .constant(1), label: Text("")) {
Text("+0").tag(1)
Text("+2").tag(2)
Text("+4").tag(3)
}
.clipped()
.frame(minWidth: 0, maxWidth: 100)
.labelsHidden()
}
}
}

struct ContentView: View {
var body: some View{
HStack{
Button(action: {
}) {
Text("50 dB")
}
.frame(width: 60.0)
VStack {
Picker(selection: .constant(1), label: Text("")) {
Text("+0").tag(1)
Text("+2").tag(2)
Text("+4").tag(3)
}
//.clipped()
.frame(width: 50)
.clipped()
}.border(Color.red)
}
}
}

Related

Keep VStack in center of the screen in SwiftUI

I'm new on SwiftUI and I don't know how to manage my views.
I have this code:
import SwiftUI
struct ContentView: View {
#State private var email: String = ""
#State private var passord: String = ""
var body: some View {
ZStack {
Image("corner")
.resizable()
.scaledToFill()
VStack {
VStack { //VStack1
TextField("Email", text: $email)
.frame(width: 300, height: 40)
.textFieldStyle(.roundedBorder)
.bold(true)
SecureField("Password", text: $passord)
.frame(width: 300, height: 40)
.textFieldStyle(.roundedBorder)
.bold(true)
Button {
//Do something
} label: {
Text("Forgot your password ?")
.underline()
.foregroundColor(.white)
}
}
VStack { // VStack2
Text("Not registered ?")
.font(.title2)
.foregroundColor(.white)
Button("Sign up") {}
.frame(width: 200, height: 37)
.foregroundColor(.white)
.background(Color(.orange))
.cornerRadius(20)
}
}
}
}
}
I want to place the VStack2 in the bottom of the screen and keep the VStack1 on the center of the screen.
How I can do that. I've try to search but I don't find the solution on StackOverflow.
I tried to play with Spacer() and padding() but I have not a good result.
Screen
A simple way to do this would be to add VStack1 to the ZStack which will place it in the centre of the screen. Then add wrap VStack2 in another VStack with a Spacer to push it to the bottom of the screen, e.g.
ZStack {
Image("corner")
VStack { //VStack1
// etc
}
VStack {
Spacer()
VStack { // VStack2
// etc
}
}
}
Simple put
HStack {
Spacer()
VStack {
Text("Centered")
}
Spacer()
}
import SwiftUI
struct ContentView: View {
#State private var email: String = ""
#State private var passord: String = ""
var body: some View {
VStack {
Spacer()
middleView()
Spacer()
bottomView()
.paddind(.bottom, 12)
}
.ignoresSafeArea()
.background {
Image("corner")
.resizable()
.scaledToFill()
}
}
func middleView() -> some View {
VStack(spacing: 20) {
TextField("Email", text: $email)
.frame(width: 300, height: 40)
.textFieldStyle(.roundedBorder)
.bold(true)
SecureField("Password", text: $passord)
.frame(width: 300, height: 40)
.textFieldStyle(.roundedBorder)
.bold(true)
Button {
//Do something
} label: {
Text("Forgot your password ?")
.underline()
.foregroundColor(.white)
}
}
}
func bottomView() -> some View() {
VStack {
Text("Not registered ?")
.font(.title2)
.foregroundColor(.white)
Button("Sign up") {}
.frame(width: 200, height: 37)
.foregroundColor(.white)
.background(Color(.orange))
.cornerRadius(20)
}
}
}

On appear doesn't trigger every time

I have problem because on appear modifier doesn't call every time when I enter the screen and it calls randomly (when on appear is applied to navigation view). When I put it on some view inside navigation view it never calls. What is the problem, I can't solve it, this is very strange behaviour. This is the view:
struct CheckListView: View {
#EnvironmentObject var appState: AppState
#StateObject var checkListViewModel = CheckListViewModel()
//#State var didSelectCreateNewList = false
#State var didSelectShareList = false
var body: some View {
NavigationView {
GeometryReader { reader in
VStack {
Spacer()
.frame(height: 30)
Text("\(appState.hikingTypeModel.name)/\(appState.lengthOfStayType.name)")
.foregroundColor(Color("rectBackground"))
.multilineTextAlignment(.center)
.font(.largeTitle)
Spacer()
.frame(height: 40)
List {
ForEach(checkListViewModel.checkListModel.sections) { section in
CheckListSection(model: section)
.listRowBackground(Color("background"))
}
}
.listStyle(.plain)
.clearListBackground()
.clipped()
Spacer()
.frame(height: 40)
HStack {
FilledRectangleBorderButtonView(titleLabel: "Share", backgroundColor: Color("rectBackground"),foregroundColor: .white, height: 55, didActionOnButtonHappened: $didSelectShareList)
Spacer()
FilledRectangleBorderButtonView(titleLabel: "Create new list", backgroundColor: .clear, foregroundColor: Color("rectBackground"), height: 55, didActionOnButtonHappened: $checkListViewModel.didSelectNewList)
.onChange(of: checkListViewModel.didSelectNewList) { _ in
UserDefaultsHelper().emptyUserDefaults()
appState.moveToRootView = .createNewList
}
}
.padding([.leading, .trailing], 20)
.frame(width: reader.size.width)
Spacer()
}
.frame(width: reader.size.width, height: reader.size.height)
.background(Color("background"))
.navigationBarStyle()
}
}
.onAppear {
self.checkListViewModel.loadJSON(hikingTypeId: appState.hikingTypeModel.id, lengthStayId: appState.lengthOfStayType.id)
}
}
}

SwiftUI: Double picker wheels with system behavioral

I want to recreate system picker behavioral with two options in wheels with SwiftUI and faced ton of problem. Some of this I solved but some still unsolved. I have pop-ups with different views inside. One of the view it's a DatePicker with displayedComponents: .hourAndMinute. And other one is two Pickers inside HStack. My question is how to make Pickers make look like in system: without white spacing between?
struct MultyPicker: View {
#State var value = 1
#State var value2 = 1
var body: some View {
ZStack(alignment: .bottom) {
Color.black.opacity(0.5)
ZStack {
VStack {
Text("Header")
.font(.title3)
.fontWeight(.bold)
HStack(spacing: 0) {
Picker(selection: $value, label: Text("")) {
ForEach(1..<26) { number in
Text("\(number)")
.tag("\(number)")
}
}
.pickerStyle(WheelPickerStyle())
.compositingGroup()
.clipped(antialiased: true)
Picker(selection: $value2, label: Text("")) {
ForEach(25..<76) { number in
Text("\(number)")
.tag("\(number)")
}
}
.pickerStyle(WheelPickerStyle())
.compositingGroup()
.clipped(antialiased: true)
}
}
.padding()
.background(
RoundedRectangle(cornerRadius: 34)
.foregroundColor(.white)
)
}
.padding(.horizontal)
.padding(.bottom, 50)
}
.edgesIgnoringSafeArea([.top, .horizontal])
}
}
// This extension for correct touching area
extension UIPickerView {
open override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: super.intrinsicContentSize.height)
}
}
Want to achive looks like that with one grey line in selected value
//
// Test2.swift
// Test
//
// Created by Serdar Onur KARADAĞ on 26.08.2022.
//
import SwiftUI
struct Test2: View {
#State var choice1 = 0
#State var choice2 = 0
var body: some View {
ZStack {
Rectangle()
.fill(.gray.opacity(0.2))
.cornerRadius(30)
.frame(width: 350, height: 400)
Rectangle()
.fill(.white.opacity(1))
.cornerRadius(30)
.frame(width: 300, height: 350)
VStack {
Text("HEADER")
HStack(spacing: 0) {
Picker(selection: $choice1, label: Text("C1")) {
ForEach(0..<10) { n in
Text("\(n)").tag(n)
}
}
.pickerStyle(.wheel)
.frame(minWidth: 0)
.clipped()
Picker(selection: $choice2, label: Text("C1")) {
ForEach(0..<10) { n in
Text("\(n)").tag(n)
}
}
.pickerStyle(.wheel)
.frame(minWidth: 0)
.clipped()
}
}
}
}
}
struct Test2_Previews: PreviewProvider {
static var previews: some View {
Test2()
}
}
SwiftUI multi-component Picker basically consists of several individual Picker views arranged horizontally. Therefore, we start by creating an ordinary Picker view for our first component. I am using Xcode version 13.4.1(iOS 15.0).
import SwiftUI
struct ContentView: View {
#State var hourSelect = 0
#State var minuteSelect = 0
var hours = [Int](0..<24)
var minutes = [Int](0..<60)
var body: some View {
ZStack {
Color.black
.opacity(0.5)
.ignoresSafeArea()
.preferredColorScheme(.light)
Rectangle()
.fill(.white.opacity(1))
.cornerRadius(30)
.frame(width: 300, height: 350)
VStack {
Text("Header")
HStack(spacing: 0) {
Picker(selection: $hourSelect, label: Text("")) {
ForEach(0..<self.hours.count) { index in
Text("\(self.hours[index])").tag(index)
}
}
.pickerStyle(.wheel)
.frame(minWidth: 0)
.compositingGroup()
.clipped()
Picker(selection: $minuteSelect, label: Text("")) {
ForEach(0..<self.minutes.count) { index in
Text("\(self.minutes[index])").tag(index)
}
}
.pickerStyle(.wheel)
.frame(minWidth: 0)
.compositingGroup()
.clipped()
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Output :

No fullScreenCover animation on close button

I have a strange behavior.
When I close my fullScreenCover, I have no animation on it. On the other hand, I have the animation at the opening. I don't understand why I have no close animation.
Example codes
import SwiftUI
struct ContentView: View {
#EnvironmentObject var myViewModel: MyViewModel
private var gridItemLayout = [GridItem(.flexible()), GridItem(.flexible())]
var body: some View {
ScrollView {
LazyVGrid(columns: gridItemLayout, spacing: 10) {
ForEach(myViewModel.data, id: \.self) { data in
ChildView(data: data)
}
}
}
.onAppear() {
self.myViewModel.getData()
}
.navigationBarTitle("My ContentView")
}
}
import SwiftUI
struct ChildView: View {
#State var data: Data
#State var showModal = false
var body: some View {
Button(action: {
self.showModal.toggle()
}, label: {
VStack {
Text("\(data.name)")
.font(.body)
.frame(width: 180, height: 150/2, alignment: .bottom)
VStack {
Text("\(Image(systemName: "checkmark.bubble")) 15")
Text("\(Image(systemName: "clock")) 20'")
}
.frame(width: 180, height: 150/2, alignment: .bottomTrailing)
}
.cornerRadius(10)
.frame(minWidth: 0, maxWidth: 180, minHeight: 150, maxHeight: 150, alignment: .center)
})
.fullScreenCover(isPresented: $showModal) {
OtherView()
}
}
}
import SwiftUI
struct OtherView: View {
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
VStack {
Button {
presentationMode.wrappedValue.dismiss()
} label: {
HStack {
Text("CLOSE")
Spacer()
Image(systemName: "checkmark")
.resizable()
.frame(width: 30, height: 30)
.padding()
}
}
}
.navigationBarTitle("My Modal", displayMode: .inline)
}
}
}
Thanks.

How do I style Text in SwiftUI Picker View?

I have a time picker in SwiftUI and any modification that I apply to the Text values in the picker are ignored. How do I do this correctly? I am using Xcode 13 on Big Sur.
Here is the result without any modification:
I want the times to be larger and white so I added .font() and .foregroundColor() modifiers. Here is my code:
struct TimerPicker: View {
#Binding var customTime: CustomTime
var body: some View {
GeometryReader { geometry in
HStack (spacing: 0.0){
VStack {
Picker(selection: self.$customTime.selectedHour, label: Text("Hrs")) {
ForEach(0..<24) { hour in
Text("\(hour) hrs")
.foregroundColor(.white)
.font(.title3)
}
}
}
.frame(width: geometry.size.width * 0.33)
.clipped()
VStack {
Picker(selection: self.$customTime.selectedMin, label: Text("Min")) {
ForEach(0..<61) { min in
Text("\(min) min")
.foregroundColor(.white)
.font(.title3)
}
}
}
.frame(width: geometry.size.width * 0.33)
.clipped()
VStack {
Picker(selection: self.$customTime.selectedSecond, label: Text("Sec")) {
ForEach(0..<61) { sec in
Text("\(sec) sec")
.foregroundColor(.white)
.font(.title3)
}
}
}
.frame(width: geometry.size.width * 0.33)
.clipped()
.transition(.scale)
}
} //: Geometry
}
}
There is no change in the styling of the picker values. What is the correct way to do this?
Your code seems to work for me, although I made the following small modifications.
This is the code that works for me:
(note there is no 60 min or 60 sec)
import SwiftUI
#main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
#State var customTime = CustomTime()
var body: some View {
Spacer()
TimerPicker(customTime: $customTime)
Spacer()
}
}
struct CustomTime: Identifiable, Hashable {
let id = UUID()
var selectedHour = 0
var selectedMin = 0
var selectedSecond = 0
}
struct TimerPicker: View {
#Binding var customTime: CustomTime
var body: some View {
GeometryReader { geometry in
HStack (spacing: 0.0){
VStack {
Picker(selection: $customTime.selectedHour, label: Text("Hrs")) {
ForEach(0..<24) { hour in
Text("\(hour) hrs").tag(hour) // <--- tag
.foregroundColor(.white)
.font(.title3)
}
}
}
.frame(width: geometry.size.width * 0.33)
.clipped()
VStack {
Picker(selection: $customTime.selectedMin, label: Text("Min")) {
ForEach(0..<60) { min in // <--- only to 59
Text("\(min) min").tag(min) // <--- tag
.foregroundColor(.white)
.font(.title3)
}
}
}
.frame(width: geometry.size.width * 0.33)
.clipped()
VStack {
Picker(selection: $customTime.selectedSecond, label: Text("Sec")) {
ForEach(0..<60) { sec in // <--- only to 59
Text("\(sec) sec").tag(sec) // <--- tag
.foregroundColor(.white)
.font(.title3)
}
}
}
.frame(width: geometry.size.width * 0.33)
.clipped()
.transition(.scale)
}
.pickerStyle(.wheel) // <--- here
.background(Color.red) // <--- here
} //: Geometry
}
}