How do I style Text in SwiftUI Picker View? - swiftui

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
}
}

Related

move content by scroll when overlay is presented

I created some MRE:
struct ContentView: View {
#State private var presentOverlay: Bool = false
var body: some View {
GeometryReader { geo in
List {
Section {
VStack(alignment: .center) {
Spacer()
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
.onTapGesture {
presentOverlay.toggle()
}
Text("Hello, world!")
}
.frame(height: geo.size.height * 0.8)
} header: {
Text("Header")
} footer: {
Text("Footer")
}
}
.overlay(alignment: .bottom) {
if presentOverlay {
Text("Some overlay")
.frame(width: geo.size.width, height: geo.size.height * 0.2)
.background(.yellow)
.transition(.move(edge: .bottom))
}
}
}
.animation(.default, value: presentOverlay)
}
}
Goal is to, when overlay appears, move content of list, so Image can be presented and clickable (currently overlay is going above it).
Is it possible to move content like it is scrolled using List component?

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 :

Cannot remove unwanted space from this VStack

I really cannot figure out what is pushing my Detail HStack View down to the bottom of the page. I've tried adding spacers and other tweaks but no success. You'll find the entire code below, its compile-ready as is.
import SwiftUI
struct ContentView: View {
var body: some View {
GeometryReader { geo in
VStack() {
VideoPlayerView()
.frame(width: geo.size.width, alignment: .center)
CategoryScrollView()
Spacer()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct CategoryScrollView: View {
var body: some View {
HStack {
VStack {
Text("Category")
.font(.system(size: 30))
}
Divider()
VStack {
Text("Chapter")
.font(.system(size: 30))
}
Divider()
VStack {
Text("Lesson")
.font(.system(size: 30))
}
}.frame(height: 100)
}
}
struct CategoryScrollView_Previews: PreviewProvider {
static var previews: some View {
CategoryScrollView()
}
}
struct VideoPlayerView: View {
var body: some View {
GeometryReader { geo in
ZStack(alignment: .center) {
Rectangle()
.frame(height: geo.size.width / 1.4)
.cornerRadius(50)
Image(systemName: "play.fill")
.resizable()
.foregroundColor(.blue)
.frame(width: geo.size.width / 5,height: geo.size.width / 4)
}
}
}
}
struct VideoPlayerView_Previews: PreviewProvider {
static var previews: some View {
VideoPlayerView()
}
}
If unconstrained, the GeometryReader takes all available space.
You need to set the height of the VideoPlayerView as well:
struct ContentView: View {
var body: some View {
GeometryReader { geo in
VStack {
VideoPlayerView()
.frame(width: geo.size.width, height: geo.size.height / 4, alignment: .center)
CategoryScrollView()
Spacer()
}
}
}
}
Also, you can remove frame(height: 100) from the CategoryScrollView:
struct CategoryScrollView: View {
var body: some View {
HStack {
VStack {
Text("Category")
.font(.system(size: 30))
}
Divider()
VStack {
Text("Chapter")
.font(.system(size: 30))
}
Divider()
VStack {
Text("Lesson")
.font(.system(size: 30))
}
}
// .frame(height: 100) // remove this
}
}
If necessary, you can specify this in the parent view using GeometryReader instead of hardcoding values.
I would add this frame to the GeometryReader.
GeometryReader { geo in
VStack() {
VideoPlayerView()
.frame(width: geo.size.width, alignment: .center)
CategoryScrollView()
Spacer()
}.frame(maxHeight:geo.size.height/2)
}

Animated shutter button like in the camera app in SwiftUI

How can you build something like the animated shutter button in the camera app in SwiftUI?
// SwiftUIPlayground
// https://github.com/ralfebert/SwiftUIPlayground/
import SwiftUI
struct CameraButtonView: View {
#State var recording = false
var action: ((_ recording: Bool) -> Void)?
var body: some View {
ZStack {
Circle()
.stroke(lineWidth: 6)
.foregroundColor(.white)
.frame(width: 65, height: 65)
RoundedRectangle(cornerRadius: recording ? 8 : self.innerCircleWidth / 2)
.foregroundColor(.white)
.frame(width: self.innerCircleWidth, height: self.innerCircleWidth)
}
.animation(.linear(duration: 0.2))
.padding(20)
.onTapGesture {
withAnimation {
self.recording.toggle()
self.action?(self.recording)
}
}
}
var innerCircleWidth: CGFloat {
self.recording ? 32 : 55
}
}
struct CameraButtonView_Previews: PreviewProvider {
static var previews: some View {
Group {
CameraButtonView(recording: false)
.previewLayout(PreviewLayout.sizeThatFits)
.previewDisplayName("not recording")
.background(Color.gray)
CameraButtonView(recording: true)
.previewLayout(PreviewLayout.sizeThatFits)
.previewDisplayName("recording")
.background(Color.gray)
ZStack {
Image("turtlerock")
.resizable()
.aspectRatio(contentMode: .fit)
HStack {
Spacer()
CameraButtonView()
}
}
}
}
}

SwiftUI - How to resize PickerView?

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)
}
}
}