I am trying to animate text to make it scroll across the screen, (using it to make a stock app), I am unable to get it to go completely off the screen can someone please help...
This is what I have so far
let text = "Some text to animate"
private var is = true
var body: some View {
VStack {
Text(text)
.fixedSize()
.frame(width: 100, alignment: is ? .trailing : .leading)
.animation(Animation.linear(duration: 5).repeatForever())
}
A possible solution is to use single Text with .move asymmetric transition.
Here is a simplified demo. Tested with Xcode 13.4 / iOS 15.5
Main part:
var body: some View {
GeometryReader { gp in
VStack {
Text(text)
.fixedSize()
.frame(width: gp.size.width + textWidth, alignment: .trailing)
.id(go)
.transition(transition)
.onAppear{ go.toggle() }
.animation(animation, value: go)
}
}.fixedSize(horizontal: false, vertical: true)
}
Test module on GitHub
like this? It shifts the text using .offset if go is true.
let text = "Some text to animate"
#State private var go = false
var body: some View {
VStack {
Text(text)
.fixedSize()
.frame(width: 100)
.offset(x: go ? 300 : 0, y: 0)
.animation(Animation.linear(duration: 3).repeatForever(), value: go)
.onAppear{self.go.toggle()}
}
}
I'm an utter and complete beginner to Xcode. I've joined this app developer internship, but they are implementing a self directed learning approach for our assignments and I am completely swamped. I have never done any kind of coding before, so I was hoping to get some answers here.
Here's the code:
import SwiftUI
struct ContentView: View {
#State private var didTap:Bool = false
var body: some View {
VStack {
HStack(spacing:320){
Button(action: {
didTap = !didTap
}
){
VStack {
Text("12").font(.largeTitle)
.foregroundColor(didTap ? Color.white : Color.black)
.fontWeight(.bold)
Text("Monday").font(.system(size: 11))
.foregroundColor(didTap ? Color.white : Color.black)
}.frame(width: 70, height: 80, alignment: .center)
.background(didTap ? Color.gray: Color.white)
.cornerRadius(20)
.shadow(color: .gray, radius: 5, x: 0, y: 6)
}
Text("")
}.background(.red)
Button {
self.didTap = true
} label: {
VStack {
Text("12").font(.largeTitle)
.foregroundColor(.black)
.fontWeight(.bold)
Text("Monday").font(.system(size: 11))
.foregroundColor(.black)
}.frame(width: 70, height: 85, alignment: .center)
.background(.white)
.background(didTap ? Color.blue : Color.yellow)
.cornerRadius(20)
.shadow(color: .gray, radius: 5, x: 0, y: 6)
}
ColorPicker(/*#START_MENU_TOKEN#*/"Title"/*#END_MENU_TOKEN#*/, selection: /*#START_MENU_TOKEN#*/.constant(.red)/*#END_MENU_TOKEN#*/)
.padding(.trailing,180)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
This is my app's home page design
Home page
And this is what I've got so far
After hours of trying and reading
My app is a simple reminder app. There are a lot to work on but I'm trying to make a collection view comprised of buttons that show the dates in a user's current week. If you click the buttons, the date along with the reminders will change to reflect the selected date. You are also supposed to be able to swipe left or right to change into the previous / next weeks.
Appreciate any kind of feedback since I am such a moron when it comes to these kinds of tech-y stuff.
I am developing an App that supports multiple Profiles. I really like the way Apple displays the Profile Icon next to the Large Navigation Bar Title in all their Apps. See the Screenshot below:
My Question is the following:
Is it possible to achieve this in SwiftUI? And if so, how?
If it's not possible in pure SwiftUI, how can I achieve it including UIKit Code?
Thanks for your help.
I solved this by using SwiftUI-Introspect, to "Introspect underlying UIKit components from SwiftUI".
Here is an example of a view:
struct ContentView: View {
#State private var lastHostingView: UIView!
var body: some View {
NavigationView {
ScrollView {
ForEach(1 ... 50, id: \.self) { index in
Text("Index: \(index)")
}
.frame(maxWidth: .infinity)
}
.navigationTitle("Large title")
.introspectNavigationController { navController in
let bar = navController.navigationBar
let hosting = UIHostingController(rootView: BarContent())
guard let hostingView = hosting.view else { return }
// bar.addSubview(hostingView) // <--- OPTION 1
// bar.subviews.first(where: \.clipsToBounds)?.addSubview(hostingView) // <--- OPTION 2
hostingView.backgroundColor = .clear
lastHostingView?.removeFromSuperview()
lastHostingView = hostingView
hostingView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostingView.trailingAnchor.constraint(equalTo: bar.trailingAnchor),
hostingView.bottomAnchor.constraint(equalTo: bar.bottomAnchor, constant: -8)
])
}
}
}
}
Bar content & profile picture views:
struct BarContent: View {
var body: some View {
Button {
print("Profile tapped")
} label: {
ProfilePicture()
}
}
}
struct ProfilePicture: View {
var body: some View {
Circle()
.fill(
LinearGradient(
gradient: Gradient(colors: [.red, .blue]),
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
.frame(width: 40, height: 40)
.padding(.horizontal)
}
}
The .frame(width: 40, height: 40) & hostingView.bottomAnchor constant will need to be adjusted to your needs.
And the results for each option (commented in the code):
Option 1
Option 2
View sticks when scrolled
View disappearing underneath on scroll
Without NavigationView
I done this with pure SwiftUI. You have to replace the Image("Profile") line with your own image (maybe from Assets or from base64 data with UIImage).
HStack {
Text("Apps")
.font(.largeTitle)
.fontWeight(.bold)
Spacer()
Image("Profile")
.resizable()
.scaledToFit()
.frame(width: 40, height: 40)
.clipShape(Circle())
}
.padding(.all, 30)
This products following result:
With NavigationView
Let's assume that you have NavigationView and inside that there's only ScrollView and .navigationTitle. You can add that profile image there by using overlay.
NavigationView {
ScrollView {
//your content here
}
.overlay(
ProfileView()
.padding(.trailing, 20)
.offset(x: 0, y: -50)
, alignment: .topTrailing)
.navigationTitle(Text("Apps"))
}
Where ProfileView could be something like this:
struct ProfileView: View {
var body: some View {
Image("Profile")
.resizable()
.scaledToFit()
.frame(width: 40, height: 40)
.clipShape(Circle())
}
}
The result will be like this...
...which is pretty close to the App Store:
I'm trying to get an activity indicator to rotate during download. For some reason, when I try to get the animation to repeat forever, it throws an error way at the bottom of the VStack code.
This works:
struct AddView: View {
#State var showActivitySpinner: Bool = false
#State var urlText: String = ""
var body: some View {
VStack{
Image(systemName: "arrow.2.circlepath.circle")
.resizable()
.frame(width: 80, height: 80)
.opacity(showActivitySpinner ? 1 : 0)
.rotationEffect(.degrees(showActivitySpinner ? 360 : 0))
.animation(.easeIn(duration: 1.0))
Spacer()
.frame(maxHeight: 100)
TextField("placeholder text", text: $urlText)
.textFieldStyle(RoundedBorderTextFieldStyle())
.font(Font.system(size: 16, design: .default))
.offset(y: -50)
Button(
action:{self.myFunction()},
label: {
HStack{
Image(systemName: "plus.circle.fill")
Text("Add")
.font(.title)
}
}
)
}
.padding()
.offset(y: -100)
}
But then when I add .repeatForever(), xcode has a problem with the VStack offset.
What is going on?
You must write Animation before .easeIn
Correct your modifier to this:
.animation(Animation.easeIn(duration: 1.0).repeatForever(autoreverses: true))
As you probably already know, SwiftUI (at the moment) doesn't point to the correct line of error. Thats why it points to the offset.
I don’t think this is related to the .repeatsForever() code.
From the documentation, there are two methods for changing VStack offset:
func offset(CGSize) -> View
func offset(x: CGFloat, y: CGFloat) -> View
Neither of these have only a y label. XCode thinks you mean the first one and assumes you have incorrectly added a y argument when it expects a CGSize. Try using the offset(x: CGFloat, y: CGFloat) method (with x = 0).
I reckon there was just a delay in processing your code before the error appeared.
I'm trying to set a rounded border to a button but the border of the button is not correct.
Code:
Button(action: {
print("sign up bin tapped")
}) {
Text("SIGN UP")
.frame(minWidth: 0, maxWidth: .infinity)
.font(.system(size: 18))
.padding()
.foregroundColor(.white)
}
.border(Color.white, width: 2)
.cornerRadius(25)
Output:
As you can see the border at corner are cut-off.
Any suggestion what am I doing wrong?
Instead of setting the cornerRadius to the Button use an overlay for the inside View:
Edit: If you have a background for the button you also need to apply the cornerRadius to the background.
Button(action: {
print("sign up bin tapped")
}) {
Text("SIGN UP")
.frame(minWidth: 0, maxWidth: .infinity)
.font(.system(size: 18))
.padding()
.foregroundColor(.white)
.overlay(
RoundedRectangle(cornerRadius: 25)
.stroke(Color.white, lineWidth: 2)
)
}
.background(Color.yellow) // If you have this
.cornerRadius(25) // You also need the cornerRadius here
Updated for Swift 5 & iOS 13.4+ with Press States!
None of the examples worked for buttons with both dark and white background colors as well as none of them had press state updates, so I built this LargeButton view that you can see below. Hope this helps, should be pretty simple to use!
Example Photos
Example Use
// White button with green border.
LargeButton(title: "Invite a Friend",
backgroundColor: Color.white,
foregroundColor: Color.green) {
print("Hello World")
}
// Yellow button without a border
LargeButton(title: "Invite a Friend",
backgroundColor: Color.yellow) {
print("Hello World")
}
Code
struct LargeButtonStyle: ButtonStyle {
let backgroundColor: Color
let foregroundColor: Color
let isDisabled: Bool
func makeBody(configuration: Self.Configuration) -> some View {
let currentForegroundColor = isDisabled || configuration.isPressed ? foregroundColor.opacity(0.3) : foregroundColor
return configuration.label
.padding()
.foregroundColor(currentForegroundColor)
.background(isDisabled || configuration.isPressed ? backgroundColor.opacity(0.3) : backgroundColor)
// This is the key part, we are using both an overlay as well as cornerRadius
.cornerRadius(6)
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(currentForegroundColor, lineWidth: 1)
)
.padding([.top, .bottom], 10)
.font(Font.system(size: 19, weight: .semibold))
}
}
struct LargeButton: View {
private static let buttonHorizontalMargins: CGFloat = 20
var backgroundColor: Color
var foregroundColor: Color
private let title: String
private let action: () -> Void
// It would be nice to make this into a binding.
private let disabled: Bool
init(title: String,
disabled: Bool = false,
backgroundColor: Color = Color.green,
foregroundColor: Color = Color.white,
action: #escaping () -> Void) {
self.backgroundColor = backgroundColor
self.foregroundColor = foregroundColor
self.title = title
self.action = action
self.disabled = disabled
}
var body: some View {
HStack {
Spacer(minLength: LargeButton.buttonHorizontalMargins)
Button(action:self.action) {
Text(self.title)
.frame(maxWidth:.infinity)
}
.buttonStyle(LargeButtonStyle(backgroundColor: backgroundColor,
foregroundColor: foregroundColor,
isDisabled: disabled))
.disabled(self.disabled)
Spacer(minLength: LargeButton.buttonHorizontalMargins)
}
.frame(maxWidth:.infinity)
}
}
Official .bordered modifier support in iOS 15+
Buttons now have baked in border styling support using the .buttonStyle(.bordered) modifier. I would suggest using the corner radius Apple provides for these buttons for the best platform-specific styling. We can change the color to be consistent with the system styles for buttons and tint the background as well as text using the .tint modifier:
Button("Add") { ... }
.buttonStyle(.bordered)
.tint(.green)
You can make the tint color more prominent (bolder) using .borderedProminent and control the size using .controlSize:
Button("food") { ... }
.tint(.red)
.controlSize(.small) // .large, .medium or .small
.buttonStyle(.borderedProminent)
You can also use this modifier on parent Views of Buttons and toggle lighter color schemes using .accentColor in child Buttons:
ScrollView {
LazyVStack {
Button("Test Button 1") { ... }
.buttonStyle(.borderedProminent)
.keyboardShortcut(.defaultAction) // Tapping `Return` key actions this button
Button("Test Button 2") { ... }
.tint(.accentColor)
}
}
.buttonStyle(.bordered)
.controlSize(.large)
Advice
Apple for some reason doesn't like single-line bordered buttons which is why the .border() modifier was deprecated in Xcode 12. With this change, I suggest developers avoid creating single-line bordered buttons because they now are not preferred in Apple's Human Interface Guidelines. Using prominent buttons everywhere also violates HIG.
Extra NOTE: Apple's .bordered style provides the standard platform style across device types. In addition, the Button responds to Dark Mode dynamically and scales its size with Dynamic Type (native accessibility support).
Swift 5 & iOS 14 – Borders also react when pressed
struct PrimaryButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding(5)
.foregroundColor(configuration.isPressed ? Color.red.opacity(0.5) : .red)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(configuration.isPressed ? Color.red.opacity(0.5) : .red, lineWidth: 1.5)
)
}
}
How to use
Button("Hide") {
print("tapped")
}.buttonStyle(PrimaryButtonStyle())
borders also react when pressed
Xcode 11.4.1
Button(action: self.action) {
Text("Button Name")
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(.white)
.padding(10)
.background(Color.darkGray)
.cornerRadius(10)
}
.buttonStyle(PlainButtonStyle())
There isn't a need to add an overlay. You can substitute padding modifier with frame modifier. The action is a non return method outside of the body variable.
Right specifically for #MinonWeerasinghe:
Button(action: self.action) {
Text("Button Name")
.font(.system(size: 15))
.fontWeight(.bold)
.foregroundColor(.black)
.padding(10)
.background(RoundedRectangle(cornerRadius: 10).stroke().foregroundColor(Color.red))
.cornerRadius(10)
}
.buttonStyle(PlainButtonStyle())
Just add the cornerRadius argument:
.border(Color.white, width: 2, cornerRadius: 25)
using this simple extension:
extension View {
func border(_ color: Color, width: CGFloat, cornerRadius: CGFloat) -> some View {
overlay(RoundedRectangle(cornerRadius: cornerRadius).stroke(color, lineWidth: width))
}
}
You can try this:
var body: some View {
ZStack {
Color.green
.edgesIgnoringSafeArea(.all)
HStack {
Button(action: {
print("sign up bin tapped")
}){
HStack {
Text("SIGN UP")
.font(.system(size: 18))
}
.frame(minWidth: 0, maxWidth: 300)
.padding()
.foregroundColor(.white)
.overlay(
RoundedRectangle(cornerRadius: 40)
.stroke(Color.white, lineWidth: 2)
)
}
}
}
}
I also did not set the maxWidth to .infinity because it means the button will fill the width of your container view.
The result will be :
Hope it helps :)
Swift version 5.6
You can use Button properties for example
Button(action: {
//define action
}) {
Image(systemName: "arrow.triangle.2.circlepath.circle.fill")
.imageScale(.large)
Text("Restart")
.font(.system(.title2))
}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.capsule)
.controlSize(.large)
.buttonBorderShape(.roundedRectangle) //change bordershape see below
.buttonBorderShape(.roundedRectangle(radius: 4)) // see below
similarly you can change the buttonSytle and controlSize
This worked for me
Button(action: {
print("Exit the onboarding")
}) {
HStack (spacing: 8) {
Text("NEXT")
.foregroundColor(Color("ColorAccentOppBlack"))
}
.padding(.horizontal, 16)
.padding(.vertical, 10)
.foregroundColor(Color("ColorYellowButton"))
.background(
Capsule().strokeBorder(Color("ColorYellowButton"), lineWidth: 1.25)
)
}
.accentColor(Color("ColorYellowButton"))
You should use Capsule. This is built-in into SwiftUI. It takes care of rounded corners. Full implementation is here https://redflowerinc.com/how-to-implement-rounded-corners-for-buttons-in-swiftui/
public struct ButtonStyling : ButtonStyle {
public var type: ButtonType
public init(type: ButtonType = .light) {
self.type = type
}
public func makeBody(configuration: Configuration) -> some View {
configuration.label.foregroundColor(Color.white)
.padding(EdgeInsets(top: 12,
leading: 12,
bottom: 12,
trailing: 12))
.background(AnyView(Capsule().fill(Color.purple)))
.overlay(RoundedRectangle(cornerRadius: 0).stroke(Color.gray, lineWidth: 0))
}
}
🔴 To create a border with rounded corners, you can draw a rounded rectangle and overlay on the button like this:
Button(action: {
print("Hello button tapped!")
}) {
Text("Hello World")
.fontWeight(.bold)
.font(.title)
.foregroundColor(.purple)
.padding()
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(Color.purple, lineWidth: 5)
)
}
Wonder how to add button border with color gradient and corner radius
Here's how..
Button(action: {self.isCreateAccountTapped = true},label: {Text("Create an Account")
.foregroundColor(Color("TextThemeColor36"))}
)
.frame(height: 44)
.frame(width: 166)
.background(Color.clear)
.cornerRadius(8)
.overlay(RoundedRectangle(cornerRadius: 10)
.stroke(LinearGradient(gradient: Gradient(colors: [Color("BtnGradientClr1"),Color("BtnGradientClr2"),Color("BtnGradientClr3")]), startPoint: .leading, endPoint: .trailing)))