Is possible to get button itself in action closure with SwiftUI ?
struct ContentView: View {
var body: some View {
Button("test") {
// change the color of button when user is tapping on it
}
}
}
If you want to access the properties of your button you can create a custom ButtonStyle.
Use its configuration to set the desired behaviour.
struct CustomButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.frame(minWidth: 0, maxWidth: .infinity)
.padding()
.foregroundColor(.white)
.background(LinearGradient(gradient: Gradient(colors: [.red, .orange]), startPoint: .leading, endPoint: .trailing))
.cornerRadius(40)
.scaleEffect(configuration.isPressed ? 0.9 : 1)
}
}
The above example was taken from here: SwiftUI Tip: ButtonStyle and Animated Buttons
In your case you can adapt it to set a custom background:
.background(configuration.isPressed ? Color.red : Color.blue)
Here's how:
struct ContentView: View {
#State var color = Color.red
var body: some View {
Button("test") {
self.color = Color.green
}.background(color)
}
}
Ya... I just figure out by myself too
struct ContentView: View {
#State var buttonColor: Color = Color.clear
var body: some View {
Button(action: {
self.buttonColor = Color(red: Double.random(in: 0...1),
green: Double.random(in: 0...1),
blue: Double.random(in: 0...1))
}, label: {
Text("Button").background(buttonColor)
})
}
}
Related
How can I add a button next to the searchbar when it is currently selected in SwiftUI? An example of what I am talking about is below:
This is the code I have currently:
struct ContentView: View {
#State private var searchText = ""
var body: some View {
NavigationView {
VStack {
Text("Hello")
}
.searchable(text: $searchText)
.navigationTitle("Hello")
}
}
}
If this is not possible to do in SwiftUI, is there a way I can accomplish this by utilizing UIKit in my SwiftUI view?
You can achieve this very easily with #FocusState. here is complete code, you can change it according to your requirements.
struct CustomSearchBar: View {
#Binding var text: String
#State private var isEditing = false
#FocusState private var isSearchFocused: Bool
var body: some View {
HStack {
Image(systemName: "magnifyingglass")
.foregroundColor(.white)
.padding([.leading])
TextField("Search ...", text: $text)
.padding([.trailing,. top, .bottom],7)
.foregroundColor(.white)
.opacity(isEditing ? 1 : 0.7)
.focused($isSearchFocused)
if isSearchFocused {
Button(action: {
// do you option event
}) {
Image("option")
.resizable()
.frame(width: 25, height: 25)
}
.padding(.trailing, 10)
.transition(.move(edge: .trailing))
}
Button(action: {
// do you cancle event
isSearchFocused = false
}) {
Text("Cancel")
}
.padding(.trailing, 10)
.transition(.move(edge: .trailing))
}
.padding()
.background(.gray.opacity(0.3))
.onChange(of: isSearchFocused) { newValue in
text = ""
}
}
}
So I'm trying to animate a gradient background and instead it animates a complete different view
Can't really find what causes SingleEventView to animate instead of the background of the VStack, really appreciate your help
animationGradient
Here is a video of how it actually looks like on simulator, it also looks like this on my phone
https://streamable.com/5xa13g
var events: [Event]
#State var colors: [Color] = []
#State private var animationGradient = true
var body: some View {
NavigationView {
VStack {
Spacer()
List {
ForEach(events) { event in
NavigationLink(destination: DetailEventView(event: event)) {
SingleEventView(event: event)
}
.listRowBackground(Color.clear)
}
}
.listStyle(.plain)
.frame(height: 500)
}
.background(LinearGradient(gradient: Gradient(colors: colors), startPoint: animationGradient ? .topLeading : .bottomLeading , endPoint: animationGradient ? .bottomTrailing : .topTrailing))
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("New") {
}
.padding(.horizontal, 4.0)
.padding(.trailing, 7.0)
.background(.indigo)
.foregroundColor(Color.white)
.containerShape(RoundedRectangle(cornerRadius: 16))
}
}
.onAppear() {
colors.removeAll()
withAnimation(.linear(duration: 5).repeatForever(autoreverses: true)) {
animationGradient.toggle()
}
for event in events {
colors.append(event.backgroundColor)
}
}
}
.ignoresSafeArea()
}
}```
I'm trying to create a View for the bottom sheet. It will have some view with a button when we tap on the button a bottom sheet has to appear.
I can modify the bottom sheet's colour, height, corner radius, how much the background view has to blur.
struct BottomSheetView: View {
#Binding var showBottomSheet: Bool
#Binding var bgColor: Color
#Binding var cornerRadius: CGFloat
#Binding var bottomSheetRatio: CGFloat
#Binding var blurPoint: CGFloat
var body: some View {
GeometryReader { geometry in
ZStack {
VStack {
Button(action: {
self.showBottomSheet.toggle()
}){
Text("click here")
.padding()
}
Spacer()
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.blur(radius: self.showBottomSheet ? self.blurPoint : 0)
.onTapGesture {
if self.showBottomSheet {
self.showBottomSheet = false
}
}
Rectangle()
.fill(self.bgColor)
.cornerRadius(self.cornerRadius)
.offset(y: self.showBottomSheet ? geometry.size.height * self.bottomSheetRatio : geometry.size.height + 200)
.animation(.spring())
}
}
}
}
In the above code
VStack {
Button(action: {
self.showBottomSheet.toggle()
}){
Text("click here")
.padding()
}
Spacer()
}
This VStack should replace with some other View, from that View I want to pass the Binding values.
Is there a way to achieve that? Thanks in advance.
I have achieved the requirement with ViewModifier
First I have created a ViewModifier struct. which will have all the required values in init()
struct BottomSheetModifier: ViewModifier {
var showBottomSheet: Bool
var blurPoint: CGFloat
var bgColor: Color
var cornerRadius: CGFloat
var bottomSheetRatio: CGFloat
init(showBottomSheet: Bool, blurPoint: CGFloat, bgColor: Color, cornerRadius: CGFloat, bottomSheetRatio: CGFloat) {
self.showBottomSheet = showBottomSheet
self.blurPoint = blurPoint
self.bgColor = bgColor
self.cornerRadius = cornerRadius
self.bottomSheetRatio = bottomSheetRatio
}
func body(content: Content) -> some View {
GeometryReader { geometry in
ZStack {
content
.blur(radius: self.showBottomSheet ? self.blurPoint : 0)
RoundedRectangle(cornerRadius: self.cornerRadius)
.fill(self.bgColor)
.offset(y: self.showBottomSheet ? geometry.size.height * self.bottomSheetRatio : geometry.size.height + 200)
.animation(.spring())
}
}
}
}
Second I've created an extension for View which will have a function with all the values as arguments and initialized the modifier in it.
extension View {
func bottomSheet(showBottomSheet: Bool, blurPoint: CGFloat, bgColor: Color, cornerRadius: CGFloat, bottomSheetRatio: CGFloat) -> some View {
modifier(BottomSheetModifier(showBottomSheet: showBottomSheet, blurPoint: blurPoint, bgColor: bgColor, cornerRadius: cornerRadius, bottomSheetRatio: bottomSheetRatio))
}
}
Third I've created a View. In that I have added some elements and simply call the modifier here with my required bottomsheet size, colour and other values.
struct DemoBottomSheetView: View {
#Binding var showBottomSheet: Bool
var body: some View {
VStack(spacing: 20) {
Text("welcome to bottom sheet")
Button(action: {
self.showBottomSheet.toggle()
}){
Text("Click Me")
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
Spacer()
}
.onTapGesture {
if self.showBottomSheet {
self.showBottomSheet = false
}
}
.bottomSheet(showBottomSheet: self.showBottomSheet, blurPoint: 4, bgColor: .red, cornerRadius: 25, bottomSheetRatio: 0.5)
}
}
Final output
struct BottomSheetView<Content: View>: View {
var content: Content
...
var body: some View {
content //do anything you want with content
}
}
and you need to pass your content in your View Ininit
like
BottomSheetView(content: Text("test"),
showBottomSheet: $test1,
bgColor: $test2,
cornerRadius: $test3,
bottomSheetRatio: $ctest4,
blurPoint: $test5)
So I was reading about the Navigation in the Apple UI guidlines. In SwiftUI, for hierarchical navigation we use the NavigationLink-View. Flat navigation is for example the view for each song in apple music.
My questions:
I have a solution but I wonder what is the best practice solution.
Furthermore, I have to add the animation myself, whereas with NavigationLink I get it for "free". Why does the transition not work? I'm trying to get a similar animation as in apple music when skipping a song.
import SwiftUI
struct Song:Identifiable{
var id = UUID()
var name:String
var cover = Color(red: Double.random(in: 0...1), green: Double.random(in: 0...1), blue: Double.random(in: 0...1))
}
struct ContentView: View {
var songs:[Song] = []
init(){
for i in 0...1000{
self.songs.append(Song(name: "Song \(i)"))
}
}
#State var index = 0
var body: some View {
VStack{
DetailView(song:songs[index])
.transition(.asymmetric(insertion: .move(edge: .leading), removal: .move(edge: .trailing)))
SongNavigation(index:$index, totalSongs: songs.count)
}.padding()
}
}
struct DetailView: View{
var song:Song
var body: some View{
VStack{
Text(song.name)
}.frame(minWidth:0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity).background(song.cover)
}
}
struct SongNavigation:View{
#Binding var index:Int
var totalSongs:Int
var body: some View{
HStack{
Button("previous"){
withAnimation(){
if self.index > 0{
self.index -= 1
}
}
}
Spacer()
Button("next"){
withAnimation(){
if self.index != self.totalSongs-1 {
self.index += 1
}
}
}
}
}
}
I want to make a simple form and change the background color of a text field, but Xcode provide me .background(background: View), etc option but not .background(Color()).
Color is conformed to View. So you can use it like any other View. The issue with your code is you add cornerRadius inside the background modifier. It should be out like this:
TextField("Title", text: .constant("text"))
.background(Color.red)
.cornerRadius(5)
Try below code.
struct ContentView: View {
#State var name: String = ""
var body: some View {
VStack(alignment: .leading, spacing: 10) {
Text("NAME").font(.headline)
TextField("Enter some text", text: $name)
.padding(.horizontal , 15)
.frame(height: 40.0)
.background(Color(red: 239/255, green: 243/255, blue: 244/255))
.overlay(
RoundedRectangle(cornerRadius: 5)
.stroke(Color.gray.opacity(0.3), lineWidth: 1)
)
}.padding(.horizontal , 15)
}
}
import SwiftUI
struct ContentView: View {
#State var name: String = ""
var body: some View {
VStack {
TextField("Enter some text", text: $name)
.background(Color.red)
}
}
}