Is there a way to have lazy pickers similar to a lazyvstack? - swift

Currently, I have a popup menu that contains two wheel pickers. I have create a drag gesture to allow swiping the popup menu away. However, as I add more entries to the picker wheels, the drag gesture becomes more and more laggy. The animation is fluid if I remove one of the pickers, or if I have less entries. How can I keep the animation fluid while having a lot of entries in both pickers? I have tried using a drawingGroup, however it doesn't work with a picker. Is there something along the lines of lazy loading for pickers?
Here are the pickers on the popup:
GeometryReader { geo in
HStack(spacing: 0) {
Picker(selection: $selection1) {
ForEach(0 ..< array1.count) { index in
...
}
} label: {
}
.labelsHidden()
.pickerStyle(.wheel)
.frame(width: geo.size.width / 2)
.compositingGroup()
.clipped()
Picker(selection: $selection2) {
ForEach(0 ..< array2.count) { index in
...
}
} label: {
}
.labelsHidden()
.pickerStyle(.wheel)
.frame(width: geo.size.width / 2)
.compositingGroup()
.clipped()
}
}
Here is the popup menu containing the pickers:
VStack {
ZStack {
ZStack {
Color("whiteblack")
VStack {
Capsule()
.frame(width: 40, height: 5)
.foregroundColor(.gray)
.padding(.top, 5)
Spacer()
}
}
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .global)
.onChanged({ value in
let amt = prevDragHeight - value.translation.height
if slideOffset >= 0 {
slideOffset -= amt
}
if slideOffset < 0 {
slideOffset = 0
}
prevDragHeight = value.translation.height
})
.onEnded({ _ in
if slideOffset > 70 {
withAnimation(.interactiveSpring()) {
slideOffset = 0
isShowing = false
}
slideOffset = 0
} else {
withAnimation(.interactiveSpring()) {
slideOffset = 0
}
}
prevDragHeight = 0
})
)
DoublePicker()
}
}
.frame(height: 400)
.frame(maxWidth: .infinity)
.background(.white)
.cornerRadius(20)
.padding()
.padding(.bottom)
.offset(x: 0, y: slideOffset)
.transition(.move(edge: .bottom))

Related

The element inside of the SwiftUIPager is hidden when the screen border is touched

In my code I have HStack with Buttons inside of Pager. Button's label is Text view with RoundedRectangle as it's overlay.
Pager(page: vm.selectedWeekPage, data: vm.deltaWeeksArray, id: \.self) { deltaWeek in
HStack{
ForEach (vm.fetchWeek(vm.deltaWeek(delta: deltaWeek)), id: \.self){
day in
Button {
vm.selectedDay = day
} label: {
Text("\(vm.extractDate(date: day, format: "dd"))")
.font(.custom("Unbounded", size: 20))
.fontWeight(.bold)
.foregroundColor(Color(tm.getTheme().foregroundColor))
.frame(width: 42, height: 42)
.overlay(content: {
RoundedRectangle(cornerRadius: 15, style: .continuous)
.stroke(lineWidth: 2)
.foregroundColor(Color(tm.getTheme().foregroundColor))
.frame(width: 46, height: 46)
.fixedSize()
})
.frame(maxWidth: .infinity)
}
}
}
.padding(.horizontal, 18)
}
.singlePagination()
.pagingPriority(.simultaneous)
.onPageChanged({ page in
if page >= vm.deltaWeeksArray.count - 2 {
(1..<4).forEach { _ in
vm.deltaWeeksArray.append((vm.deltaWeeksArray.last ?? 0) + 1)
vm.deltaWeeksArray.removeFirst()
vm.selectedWeekPage.index -= 1
}
} else if page <= 1 {
(1..<4).forEach { _ in
vm.deltaWeeksArray.insert((vm.deltaWeeksArray.last ?? 0) + 1, at: 0)
vm.deltaWeeksArray.removeLast()
vm.selectedWeekPage.index += 1
}
}
})
.itemSpacing(50)
.frame(maxHeight: 48)
.padding(.horizontal, -18)
Bug happens when I transition to different page. .stroke() hides when Button touches the edge of screen.
Recording of bug:
Link
Actually I don't really know what to do... I tried using ZStack instead of .overlay(),extracting text from the label on the button. That didn't work

How to set max width of searchview inside toolbar [SwiftUI]

I am new to SwiftUI and I trying to set maxwidth of my searchbar inside of my toolbar but the .frame(maxWidth: .infinity) won't work on my case. How can I fix this?
You can see the problem by bellow attached image, Screenshot
// this is my toolbar
My ToolbarView
NavigationView {
VStack {
contentView
}
.padding(.top, 10)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
if (hideTitleAndSearchButton) {
SearchBarView(
searchText: $viewModel.personViewModel.searchText,
hideTitleAndSearchButton: Binding(projectedValue: $hideTitleAndSearchButton),
viewModel: viewModel.personViewModel
)
.frame(maxWidth: .infinity)
.animationDisable()
}
else {
Text(title)
.font(.system(size: 32))
.bold()
}
}
ToolbarItem(placement: .navigationBarTrailing) {
if (!hideTitleAndSearchButton) {
if (viewModel.setSearchButtonVisibility) {
Image(systemName: "magnifyingglass")
.onTapGesture {
self.hideTitleAndSearchButton = true
}
.frame(width: 45, height: 45)
.foregroundColor(Color.white)
.background(Color.mPurple)
.clipShape(Circle())
.animationDisable()
}
}
}
}
}
.frame(maxWidth: .infinity)
// this is my searchview
My Searchview
var body: some View {
HStack {
Image("back_icon")
.resizable()
.renderingMode(.template)
.foregroundColor(.mPurple)
.onTapGesture {
self.isEditing = false
self.searchText = ""
self.hideTitleAndSearchButton = false
viewModel.isSearchMode = false
viewModel.isLoading = true
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
viewModel.personPopularList.removeAll()
viewModel.getPersonPopular()
}
}
.frame(width: 40, height: 40)
.animationDisable()
TextField("Search ...", text: $searchText)
.padding(7)
.padding(.horizontal, 20)
.background(Color(.systemGray6))
.cornerRadius(8)
.accentColor(.mPurple)
.frame(maxWidth: .infinity)
.onTapGesture {
self.isEditing = true
viewModel.isSearchMode = true
}.onChange(of: searchText) { searchItem in
if (!searchItem.isEmpty) {
viewModel.searchText = searchItem.lowercased()
let _ = print("searchItem true")
} else {
viewModel.isSearchMode = false
viewModel.personPopularList.removeAll()
viewModel.getPersonPopular()
let _ = print("searchItem false")
}
let _ = print("searchItemX: \(searchText)")
}
.animationDisable()
.padding(.trailing, 10)
}
}
thanks for anyone can help.
Add your SearchView in principal placement and don't need to set any width.
ToolbarItem(placement: hideTitleAndSearchButton ? .principal : .navigationBarLeading) {
if (hideTitleAndSearchButton) {
SearchBarView(
searchText: $viewModel.personViewModel.searchText,
hideTitleAndSearchButton: Binding(projectedValue: $hideTitleAndSearchButton),
viewModel: viewModel.personViewModel
)
.animationDisable()
}
else {
Text(title)
.font(.system(size: 32))
.bold()
}
}

Image movement & animation

How can I take a image on SplashView() and make it go to the top right hand corner on Home() view during the animation between the two?
SplashView()
struct SplashView: View {
// 1.
#State var isActive:Bool = false
var body: some View {
VStack {
// 2.
if self.isActive {
// 3.
Home()
.onAppear {
print("IsVerificationSent: \(RequestedVerification)")
}
} else {
// 4.
Image("logo")
.resizable()
.scaledToFill()
.frame(width: 200, height: 200)
.overlay {
RoundedRectangle(cornerRadius: 30)
.stroke(.white, lineWidth: 1)
}
.shadow(color: Color.black.opacity(0.5), radius: 7)
}
}
// 5.
.onAppear {
// 6.
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
// 7.
withAnimation {
self.isActive = true
}
}
}
}
}
Home()
struct Home: View {
var body: some View {
VStack {
Image("logo")
.resizable()
.scaledToFill()
.offset(y: 25)
.frame(width: 50, height: 50)
.overlay {
RoundedRectangle(cornerRadius: 10)
.stroke(.white, lineWidth: 1)
.offset(y: 25)
}
.shadow(radius: 2)
Spacer(minLength: 0)
}
}
}
And since I can't put the full Home() view on here, how can I go about adjusting to make it look the best possible?

I'd like to use the navigation link.Newbie Wang is in the process of hair loss

I want to use Navigationlink. I've been a novice for 2 weeks since I started.I am currently learning SwiftUi.
I created "OnboredView" after watching YouTube, but I don't know how to connect "OnboredView" to "CountentView".
NavigationView(){
NavigationLink(destination: OnboardView())
I learned how to make it like this through YouTube, but I don't know what to do now. I put it here and there, but the red errors bother me.
Tell me how to connect "NavigationLink" by pressing the button on "CountentView".
I'd like to click "Chevron.Light" to move on to "OnboredView."And if possible, please let me know how I can get rid of the "onboard screen" on the second run?
I am not good at English.I'm sorry. I'm experiencing hair loss again.
import SwiftUI
struct ContentView: View {
#State private var animate: Bool = false
var body: some View {
ZStack{
ZStack{
Image("rogo1")
.resizable()
.frame(width: 75, height: 75)
.offset(y: animate ? -100 : 0)
}
ZStack{
Image("rogo2")
.resizable()
.frame(width: 75, height: 75)
.offset(y: animate ? -100 : 0)
}
VStack {
HStack {
Spacer()
Image("images (1)")
.resizable()
.frame(width: 300, height: 300)
.offset(x: animate ? 300 : 150, y: animate ? -300 : -150)
}
Spacer()
HStack {
Image("images (1)")
.resizable()
.frame(width: 400, height: 400)
.offset(x: animate ? -500 : -150, y: animate ? 500 : 150)
Spacer()
}
}
ZStack(alignment: .bottom){
GeometryReader { g in
VStack (alignment: .leading, spacing: 20){
Text("안녕하세요!")
.font(.title)
.fontWeight(.semibold)
.padding(.top, 20)
//인삿말과 회원가입
Text("기분 좋은 매일습관을 만들기 위한 앱 ( ) 입니다! 시간표와 더불어 루틴을 함께 할수
있도록 설계 되었습니다.저희 ( )와 함께 계획해봐요!")
.fontWeight(.medium)
.multilineTextAlignment(.center)//중앙으로 결집
.padding(5)
ZStack {
Button(action: {},label: {
Image(systemName: "chevron.right")
.font(.system(size:20, weight: .semibold))
.frame(width: 60, height: 60)
.foregroundColor(.black)
.background(Color.white)
.clipShape(Circle())
.overlay(
ZStack {
Circle()
.stroke(Color.black.opacity(0.04),lineWidth: 4)
Circle()
.trim(from: 0, to: 0.03)
.stroke(Color.white,lineWidth: 4)
.rotationEffect(.init(degrees: -40))
})
})
.padding(-10)
}
Spacer()
}
.frame(maxWidth: .infinity)
.padding(.horizontal, 30)
.background(Color.green)
.clipShape(CustomShape(leftCorner: .topLeft, rightCorner: .topRight,
radii: 20))
.offset(y: animate ? g.size.height : UIScreen.main.bounds.height)
}
}.frame(height: 275)
//여기까지 짤라도 됨 온보드
}
.frame(maxWidth: .infinity)
.edgesIgnoringSafeArea(.all)
.onAppear(perform: {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
withAnimation(Animation.easeOut(duration: 0.45)){
animate.toggle()
}
}
})
}
{
struct CustomShape: Shape {
var leftCorner: UIRectCorner
var rightCorner: UIRectCorner
var radii: CGFloat
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(roundedRect: rect, byRoundingCorners:
[leftCorner,rightCorner], cornerRadii: CGSize(width: radii, height: radii))
return Path(path.cgPath)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
Group {
}
}
}
}
import SwiftUI
struct OnboardView: View {
#AppStorage("currentPage") var currentPage = 1
var body: some View {
if currentPage > totalPages {
Home()
}else{
WalkthroughScreen()
}
}
}
struct OnboardView_Previews: PreviewProvider {
static var previews: some View {
OnboardView()
}
}
struct Home: View {
var body: some View{
Text("welcome To Home!!!")
.font(.title)
.fontWeight(.heavy)
}
}
//..Walkthrough Screen..
struct WalkthroughScreen: View {
#AppStorage("currentPage") var currentPage = 1
var body: some View {
//For Slide Animation
ZStack{
//Changing Between Views..
if currentPage == 1 {
ScreenView(image: "image1", title: "Step1", detail: "", bgColor:
Color(.white))
//transition(.scale)영상에서는 넣었으나 오류가나서 사용하지 못함
}
if currentPage == 2 {
ScreenView(image: "image2", title: "Step2", detail: "", bgColor:
Color(.white))
}
if currentPage == 3 {
ScreenView(image: "image3", title: "Step3", detail: "아니 ㅡㅡ 이런 방법이 유레카",
bgColor: Color(.white))
}
}
.overlay(
Button(action: {
//changing views
withAnimation(.easeInOut){
if currentPage < totalPages {
currentPage += 1
}else{
currentPage = 1
//For app testing ONly
}
}
}, label: {
Image(systemName: "chevron.right")
.font(.system(size: 20, weight: .semibold))
.foregroundColor(.black)
.frame(width: 60, height: 60)
.clipShape(Circle())
//strclulat Slider
.overlay(
ZStack{
Circle()
.stroke(Color.black.opacity(0.04),lineWidth: 4
Circle()
.trim(from: 0, to: CGFloat(currentPage) /
CGFloat(totalPages))
.stroke(Color.green,lineWidth: 4)
.rotationEffect(.init(degrees: -99))
}
.padding(-15)
)
})
.padding(.bottom,20)
,alignment: .bottom
)
}
}
struct ScreenView: View {
var image: String
var title: String
var detail: String
var bgColor: Color
#AppStorage("currentPage") var currentPage = 1
var body: some View {
VStack(spacing:20){
HStack {
//Showing it only for first page..
if currentPage == 1{
Text("Hello Members!")
.font(.title)
.fontWeight(.semibold)
//Letter Spacing
.kerning(1.4)
}else{
//Back Butten..
Button(action: {
withAnimation(.easeInOut){
currentPage -= 1
}
}, label: {
Image(systemName: "chevron.left")
.foregroundColor(.white)
.padding(.vertical,10)
.padding(.horizontal)
.background(Color.black.opacity(0.4))
.cornerRadius(10)
})
}
Spacer()
Button(action: {
withAnimation(.easeInOut){
currentPage = 4
}
}, label: {
Text("Skip")//글자입력
.fontWeight(.semibold)//글자 폰트변경
.kerning(1.2)//글자간 간격 조정
})
}
.foregroundColor(.black)//그라운드 컬러 변경
.padding()
Spacer(minLength: 0)//수평,수직 줄바꿈
Image(image)//이미지 삽입
.resizable()//크기 확대
.aspectRatio(contentMode: .fit)//이미지 크기
Text(title)
.font(.title)//폰트 크기변경
.fontWeight(.bold)//폰트 두께 변경
.foregroundColor(.black)//색깔 변경
.padding(.top)
//Change with your Own Thing..
Text(detail)
.fontWeight(.semibold)
.kerning(1.3)//자간조정
.multilineTextAlignment(.center)//텍스트를 중앙으로 결집
Spacer(minLength: 220)//minimun Spacing When phone is reducing수직위치 조정
}
.background(bgColor.cornerRadius(10).ignoresSafeArea())
}
}
var totalPages = 3

SwiftUI - NavigationLink nested within a button

I'm working on a onboarding screen:
VStack {
if #available(iOS 14.0, *) {
TabView(selection: $currentStep) {
ForEach(0..<OnBoardingSteps.count) { it in
VStack {
Text(OnBoardingSteps[it].title)
Image(OnBoardingSteps[it].image).resizable().frame(width: 200, height: 200)
Text(OnBoardingSteps[it].description)
}.tag(it)
}
}.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
} else {
// Fallback on earlier versions
}
HStack {
Spacer()
Spacer()
HStack{
ForEach(0..<OnBoardingSteps.count) { it in
if it == currentStep {
Rectangle()
.frame(width: 10, height: 10)
.cornerRadius(10)
.foregroundColor(.purple)
} else {
Circle()
.frame(width: 10, height: 10)
.foregroundColor(.gray)
}
}
}
Spacer()
Button(action: {
if self.currentStep < OnBoardingSteps.count - 1 {
self.currentStep += 1
} else {
// now when i click 'Done' it should take me to Signup screen
}
}){
HStack {
Text(currentStep < OnBoardingSteps.count - 1 ? "Next" : "Done")
.foregroundColor(.blue)
Image(systemName: currentStep < OnBoardingSteps.count - 1 ? "arrow.right" : "checkmark")
}
}
}
}
In my button I have some logic to change text based on if I'm on the last onBoarding step.
What im trying to achieve is, when im on the last step, when i click 'Done' i should navigate to the Signup screen.