I am trying to create this modifier:
struct CustomTextBorder: ViewModifier {
func body(content: Content) -> some View {
return content
.font(.largeTitle)
.padding()
.overlay(
RoundedRectangle(cornerRadius: 15)
.stroke(lineWidth: 2)
)
.foregroundColor(.blue)
}
}
When I do, I get Type 'CustomTextBorder' does not conform to protocol 'ViewModifier' error.
It seems like I have to add:
typealias Body = <#type#>
However, I see modifiers being created as I originally did here without having to provide the typealias Body...
This modifier works here:
https://www.simpleswiftguide.com/how-to-make-custom-view-modifiers-in-swiftui/
Why isn't it working for me?
How can I make this modifier work? Why does it work for some and not for others? Does it depend on what the project targets? I am targeting iOS 15.
Without seeing your implementation, it looks like your not initializing the modifier. Be sure you're using the braces at the end CustomTextBorder(). Remember, it's still a function that needs to be called.
Text("SwiftUI Tutorials")
.modifier(CustomTextBorder())
Same if you're making an extension of View
extension View {
func customTextBorder() -> some View {
return self.modifier(CustomTextBorder())
}
}
Your code works fine, but why ViewModifier? you do not need ViewModifier for this simple thing, you can use extension in this way:
struct ContentView: View {
var body: some View {
Text("Hello, World!").customTextBorder
}
}
extension Text {
var customTextBorder: some View {
return self
.font(.largeTitle)
.padding()
.overlay(
RoundedRectangle(cornerRadius: 15)
.stroke(lineWidth: 2)
)
.foregroundColor(.blue)
}
}
Related
I have a CameraView in my app that I'd like to bring up whenever a button is to be presssed. It's a custom view that looks like this
// The CameraView
struct Camera: View {
#StateObject var model = CameraViewModel()
#State var currentZoomFactor: CGFloat = 1.0
#Binding var showCameraView: Bool
// MARK: [main body starts here]
var body: some View {
GeometryReader { reader in
ZStack {
// This black background lies behind everything.
Color.black.edgesIgnoringSafeArea(.all)
CameraViewfinder(session: model.session)
.onAppear {
model.configure()
}
.alert(isPresented: $model.showAlertError, content: {
Alert(title: Text(model.alertError.title), message: Text(model.alertError.message), dismissButton: .default(Text(model.alertError.primaryButtonTitle), action: {
model.alertError.primaryAction?()
}))
})
.scaledToFill()
.ignoresSafeArea()
.frame(width: reader.size.width,height: reader.size.height )
// Buttons and controls on top of the CameraViewfinder
VStack {
HStack {
Button {
//
} label: {
Image(systemName: "xmark")
.resizable()
.frame(width: 20, height: 20)
.tint(.white)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing)
Spacer()
flashButton
}
HStack {
capturedPhotoThumbnail
Spacer()
captureButton
Spacer()
flipCameraButton
}
.padding([.horizontal, .bottom], 20)
.frame(maxHeight: .infinity, alignment: .bottom)
}
} // [ZStack Ends Here]
} // [Geometry Reader Ends here]
} // [Main Body Ends here]
// More view component code goes here but I've excluded it all for brevity (they don't add anything substantial to the question being asked.
} // [End of CameraView]
It contains a CameraViewfinder View which conforms to the UIViewRepresentable Protocol:
struct CameraViewfinder: UIViewRepresentable {
class VideoPreviewView: UIView {
override class var layerClass: AnyClass {
AVCaptureVideoPreviewLayer.self
}
var videoPreviewLayer: AVCaptureVideoPreviewLayer {
return layer as! AVCaptureVideoPreviewLayer
}
}
let session: AVCaptureSession
func makeUIView(context: Context) -> VideoPreviewView {
let view = VideoPreviewView()
view.backgroundColor = .black
view.videoPreviewLayer.cornerRadius = 0
view.videoPreviewLayer.session = session
view.videoPreviewLayer.connection?.videoOrientation = .portrait
return view
}
func updateUIView(_ uiView: VideoPreviewView, context: Context) {
}
}
I wish to add a binding property to this camera view that allows me to toggle this view in and out of my screen like any other social media app would allow. Here's an example
#State var showCamera: Bool = false
var body: some View {
mainTabView
.overlay {
CameraView(showCamera: $showCamera)
}
}
I understand that the code to achieve this must be written inside the updateUIView() method. Now, although I'm quite familiar with SwiftUI, I'm relatively inexperienced with UIKit, so any help on this and any helpful resources that could help me better code situations similar to this would be greatly appreciated.
Thank you.
EDIT: Made it clear that the first block of code is my CameraView.
EDIT2: Added Example of how I'd like to use the CameraView in my App.
Judging by the way you would like to use it in the app, the issue seems to not be with the CameraViewFinder but rather with the way in which you want to present it.
A proper SwiftUI way to achieve this would be to use a sheet like this:
#State var showCamera: Bool = false
var body: some View {
mainTabView
.sheet(isPresented: $showCamera) {
CameraView()
.interactiveDismissDisabled() // Disables swipe to dismiss
}
}
If you don't want to use the sheet presentation and would like to cover the whole screen instead, then you should use the .fullScreenCover() modifier like this.
#State var showCamera: Bool = false
var body: some View {
mainTabView
.overlay {
CameraView()
.fullScreenCover(isPresented: $showCamera)
}
}
Either way you would need to somehow pass the state to your CameraView to allow the presented screen to set the state to false and therefore dismiss itself, e.g. with a button press.
I have a TextField on a View. Getting below warning on tapping of a text field. Not sure Why? Below is the code used.
This is view where button is available to click. On click of this button, Bottom view will be displayed.
struct ContentView: View {
#State var cardShown = false
#State var cardDismissal = false
var body: some View {
NavigationView {
ZStack {
Button(action: {
cardShown.toggle()
cardDismissal.toggle()
}, label: {
Text("Show Card")
.bold()
.foregroundColor(Color.white)
.background(Color.blue)
.frame(width: 200, height: 50)
})
BottomCard(cardShown: $cardShown, cardDismissal: $cardDismissal, height: 400, content: {
CardContent()
.padding()
})
}
}
}
}
This is the bottom view where the text field exists. On this text field click, getting error.
struct CardContent: View {
#State private var text = ""
var body: some View {
VStack {
Text("Photo Collage")
.bold()
.font(.system(size: 30))
.padding()
Text("You can create awesome photo grids and share them with all of your friends")
.font(.system(size: 18))
.multilineTextAlignment(.center)
TextEditor(text: $text)
.frame(height: 100)
}
.padding()
}
}
Generic View.
struct BottomCard<Content: View>: View {
let content: Content
#Binding var cardShown: Bool
#Binding var cardDismissal: Bool
let height: CGFloat
init(cardShown: Binding<Bool>, cardDismissal: Binding<Bool>, height: CGFloat, #ViewBuilder content: () -> Content) {
_cardShown = cardShown
_cardDismissal = cardDismissal
self.height = height
self.content = content()
}
var body: some View {
ZStack {
// Dimmed
GeometryReader { _ in
EmptyView()
}
.background(Color.gray.opacity(0.5))
.opacity(cardShown ? 1: 0)
.animation(Animation.easeIn, value: 0.9)
.onTapGesture {
// Dismiss
dismiss()
}
// Card
VStack {
Spacer()
VStack {
content
Button(action: {
// Dismiss
dismiss()
}, label: {
Text("Dismiss")
.foregroundColor(Color.white)
.frame(width: UIScreen.main.bounds.width/2, height: 50)
.background(Color.pink)
.cornerRadius(8)
})
.padding()
}
//.background(Color(UIColor.secondarySystemBackground))
.background(Color.yellow)
.frame(height: height)
.offset(y: (cardShown && cardShown) ? 0 : 800)
.animation(Animation.default.delay(0.2), value: 0.2)
.padding(.bottom, 300)
}
}
.edgesIgnoringSafeArea(.all)
}
func dismiss() {
cardDismissal.toggle()
//self.view.endEditing(true)
DispatchQueue.main.asyncAfter(deadline: .now()+0.25){
cardShown.toggle()
}
}
}
Getting below error while tapping on textField.
objc[9303]: Class _PointQueue is implemented in both /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/UIKitCore.framework/UIKitCore (0x129df7a50) and /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/TextInputUI.framework/TextInputUI (0x13c7b68d8). One of the two will be used. Which one is undefined.
objc[9303]: Class _PathPoint is implemented in both /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/UIKitCore.framework/UIKitCore (0x129df7a78) and /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/TextInputUI.framework/TextInputUI (0x13c7b68b0). One of the two will be used. Which one is undefined.
I was also looking for an answer on this and it appears it could just be 'log noise'. I found the following in a different question.
Apple developer Quinn “The Eskimo!” # Developer Technical Support # Apple answered this question here:
This is not an error per se. Rather, it’s the Objective-C runtime
telling you that:
Two frameworks within your process implement the same class (well, in
this case classes, namely _PathPoint and _PointQueue).
The runtime will use one of them, choosing it in an unspecified way.
This can be bad but in this case it’s not. Both of the implementations
are coming from the system (well, the simulated system) and thus you’d
expect them to be in sync and thus it doesn’t matter which one the
runtime uses.
So, in this specific case, these log messages are just log noise.
So my problem is that I am trying to align text from different HStacks. Different sized SFSymbols are causing this problem.
I know that AlignmentGuide can solve my problem but I'm not sure how to implement. If anyone can lend any insight I would be greatly appreciative!
I have watched the WWDC talk on this.
And this is the main screen that relates to this problem,
Yet I need a little clarification of to put it together.
Here is relevant code
import SwiftUI
struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
Text("SOS Mayday!").bold()
.font(.largeTitle)
Rectangle()
.frame(height: 1)
HStack {
Image(systemName: "textformat.abc").imageScale(.large)
Text("Trying to figure out how to use alignment guide").bold()
}.padding(.vertical)
HStack {
//MARK:- FIX ALIGNMENT
Image(systemName: "aqi.low").imageScale(.large)
Text("This text should align with the text above").bold()
}
Spacer()
}.padding(.horizontal)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I was able to produce the output you want using these steps:
Create a custom alignment enum based on AlignmentID and a
static instance of it as shown in the slide you linked.
Add a new VStack around just the part you want to custom align. Otherwise it can affect the alignment of the other components.
Add an alignmentGuide() on the two Text's that you want to align at their
leading edge.
Here is the updated code:
extension HorizontalAlignment {
private enum LeadingAlignment: AlignmentID {
static func defaultValue(in context: ViewDimensions) -> CGFloat {
return context[.leading]
}
}
static let leadingAlign = HorizontalAlignment(LeadingAlignment.self)
}
struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
Text("SOS Mayday!").bold()
.font(.largeTitle)
Rectangle()
.frame(height: 1)
// The new VStack using the custom alignment.
VStack(alignment: .leadingAlign) {
HStack {
Image(systemName: "textformat.abc").imageScale(.large)
Text("Trying to figure out how to use alignment guide")
.bold()
.alignmentGuide(.leadingAlign) { d in
d[.leading]
}
}.padding(.vertical)
HStack {
//MARK:- FIX ALIGNMENT
Image(systemName: "aqi.low").imageScale(.large)
Text("This text should align with the text above")
.bold()
.alignmentGuide(.leadingAlign) { d in
d[.leading]
}
}
Spacer()
}
}.padding(.horizontal)
}
}
I am trying to do this view with swiftui but i am stuck.
I want the text("Mes évènements") to be centered and I want it to take all the place it can.
The two horizontal line should only take the place left.
I tried with HStack but I couldn't make it work as i would like to.
Here is a possible solution.
struct ContentView: View {
var body: some View {
HStack{
VStack{
OrangeLine()
}
Text("Mes évènements")
.font(.subheadline)
.fontWeight(.bold)
.foregroundColor(Color.orange)
VStack{
OrangeLine()
}
}
}
}
struct OrangeLine: View {
var body: some View {
Rectangle()
.fill(Color.orange)
.frame(height: 2)
.edgesIgnoringSafeArea(.horizontal)
}
}
Is there a way to set up the background of the whole app (same default background for each view) in one place? For example in the SceneDelegate?
Create a custom ViewModifier, throw in your color, and add it to your views. For instance, if you want all your views to be orange, do this:
struct BackgroundColorStyle: ViewModifier {
func body(content: Content) -> some View {
return content
.background(Color.orange)
}
}
And usage is:
Text("Hello world!").modifier(BackgroundColorStyle())
Now, you can - and probably should - expand on this for light/dark mode. In this case, you can use the environment variable ColorSchmem:
struct BackgroundColorStyle: ViewModifier {
#Environment (\.colorScheme) var colorScheme:ColorScheme
func body(content: Content) -> some View {
if colorScheme == .light {
return content
.background(Color.darkGrey)
} else {
return content
.background(Color.white)
}
}
}
Either way, every View using this modifier has their background color defined in one place. If you wish to define a border along with a background color, same thing.
import SwiftUI
struct TestView: View {
var body: some View {
ZStack {
Rectangle()
.foregroundColor(.blue)
.edgesIgnoringSafeArea(.all)
Text("Hello World!")
.foregroundColor(.white)
}
}
}
ZStack and Rectangle(), Setting foregroundColor and edgesIgnoringSafeArea