Swift UI padding on Navigation "back" button - swiftui

How do I adjust the padding of a Swift UI "back" navigation button? i.e. the blue "Navigation" text in the image below (Image contributed by someone else on a different question). I want to add more space between the text and the leading edge of the screen.

You can use custom appearance for this purpose configured in the init of view holding NavigationView.
Here is a demo (with big offset for better visibility). Prepared with Xcode 13 / iOS 15.
init() {
let appearance = UINavigationBarAppearance()
appearance.backButtonAppearance.normal.titlePositionAdjustment =
UIOffset(horizontal: 40, vertical: 0)
UINavigationBar.appearance().standardAppearance = appearance
}

Related

SwiftUI border around dynamically shaped View

Sometimes a view's shape can be dynamic like when using the native .buttonStyle(.bordered) modifier. This modifier will apply different corner radius based on different button content sizes:
Question
How can we stroke around a custom view? (not a Shape)
Considerations after trials:
We can't use another button with bigger/smaller frame to create the border illusion, because the corner radius will be different and not matched with the original shape
The view has transparency, so using shadow effect may not be a good option to create the border illusion
Using scale effect not works as desired, because of the different sizes issue, and also the lack of precise border width
ContainerRelativeShape is not working (yet) except for widgets
Not found solutions to try:
Get the shape of a view to apply stroke on it
Get the path around the content of the view
apply some sort of stroke directly on a view
Sample Code:
VStack {
Button {
} label: {
Text("Hello World")
.frame(height: 164) // <- Difference
}
Button {
} label: {
Text("Hello World")
.frame(height: 64) // <- Difference
}
}
.buttonStyle(.bordered)
/* .stroke() // something like this, but for a view */
Unfortunately, borders are drawn around the frame of a view. If you want to add a border to a rounded view, you need to know the corner radius.
You can hardcode the corner radius of your buttons using the .buttonBorderShape() modifier, then overlay your buttons with a shape that matches the shape you choose in .buttonBorderShape()

Setting the font of SwiftUI's .searchable() with the appearance API of UITextField+UISearchBar doesn't work

I'm customizing the appearance of the .searchable() modifier of SwiftUI with the appearance API of UISearchBar.
Almost everything works, except the font of the text field, and I have no idea why (setting the font of the cancel button works, or setting the background color or text color of the text field also work, so the correct reference is there).
Talk is cheap, show me the code!
let textAttributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.systemBlue, // this works
.font: UIFont.boldSystemFont(ofSize: 15) // this doesnt
]
let placeholder = NSAttributedString(
string: "Search...", // this doesnt
attributes: [
.foregroundColor: UIColor.systemGray, // this works
.font: UIFont.boldSystemFont(ofSize: 15) // this doesnt
])
let textFieldAppearance = UITextField
.appearance(whenContainedInInstancesOf: [UISearchBar.self])
textFieldAppearance.backgroundColor = .red // this works
textFieldAppearance.defaultTextAttributes = textAttributes // color works, font not
textFieldAppearance.attributedPlaceholder = placeholder // color works, font or text not
I guess it's time to file a -radar- feedback?
I haven't found a reliable way of customizing this, with the solution posted below there's a glitch on the search bar that happens when SwiftUI re-renders the view (scrolling or just typing on the search bar), that is very obvious on a real device (not so much on the simulator).
Old answer:
Far from ideal, I found a way to make it work, which is introspecting the view searching for the UITextField and setting the font directly. The easiest way to do this is using a library like SwiftUI-Introspect (https://github.com/siteline/SwiftUI-Introspect).
Then on the View you're using .searchable() from just:
.introspectTextField { textField in
textField.font = UIFont.boldSystemFont(ofSize: 15)
}
Fixed! The perfect solution would be to use the appearance API, but I guess we'll have to wait till iOS 16...
Setting the .font and .foregroundColor modifiers after .searchable will do the desired result, but it still doesn't work with .background modifier (if you want it) as the time of this writing (iOS 16).

SwiftUI - ScrollView move content to be visible with KeyboardAwareSwiftUI

I found this answer great for views but for a scrollview it works with this half text view height effect:
Is this something I can do with this KeyboardAwareSwiftUI classes? I tried to play with magical numbers to increase this values here:
func body(content: Content) -> some View {
content
.padding(.bottom, self.keyboard.height + 100)
.edgesIgnoringSafeArea(self.keyboard.height > 0 ? .bottom : [])
.animation(.easeOut)
}
but this just increased some area above the keyboard but text view is still hidden a bit:
I would recommend using this library instead, and you never have to worry about view positioning when keyboard is shown: https://github.com/hackiftekhar/IQKeyboardManager
It's a non swiftui library, however, this issue here shows how to add it to your swiftui app seamlessly and only a few line of code:
https://github.com/hackiftekhar/IQKeyboardManager/issues/1606
hope this helps

displaying image in a toolbar in swift 3

i am trying to create a toolbar with buttons. and the button i want to have is an image rather title. The current non working code is:
let imageName = "yourImage.png"
self.myUIBarButtonBack = UIBarButtonItem(image: UIImage(named: imageName), style:.plain, target: self, action: #selector(onClickBarButton))
I have 2 questions:
1. where should i place the yourImage.png in my application
2. is this code sufficient to render image or i need to do things like putting it into imageView component and make it visible etc. ?
The best approach is to add images in xcassets. This is the best way you can organize images. The concept of App slicing applies here.
You don't need to put the image in image view in the case of bar button item.
Try changing the rendring option as Original Image instead of Default.
One way is create custom button and assign to toolbar like navigationbar
self.navigationItem.hidesBackButton = true
let button = UIButton.init(type: .custom)
button.setImage(UIImage.init(named: "back_icon"), for: UIControlState.normal)
button.addTarget(self, action:#selector(onClickBackBarItem), for: UIControlEvents.touchUpInside)
button.frame = CGRect.init(x: 0, y: 0, width: 25, height: 25)
let barButton = UIBarButtonItem.init(customView: button)
self.navigationItem.leftBarButtonItem = barButton

Add UINavigation Back button in UICollectionView with Swift 3

I add Left Navigation Back button in collection view controller with code.
//Add Navigation Bar
navbar.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin, .flexibleRightMargin]
navbar.delegate = self
UINavigationBar.appearance().barTintColor = UIColor(red: 0.0/255.0, green:49.0/255.0, blue:79.0/255.0, alpha:0.1)
UINavigationBar.appearance().tintColor = UIColor.white
UINavigationBar.appearance().isTranslucent = true
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white]
navItem.title = prefs.value(forKey: "PROVIDER_NAME") as! String?
let image = UIImage(named: "back_image")
navItem.leftBarButtonItem = UIBarButtonItem(image: image, style: .plain, target: self, action: #selector(addTapped))
navItem.leftBarButtonItem?.imageInsets = UIEdgeInsetsMake(0, 0, 0, 0)
Back button is so close to the left. I would like to add padding about 10px from the left. So, I changed the code into
navItem.leftBarButtonItem?.imageInsets = UIEdgeInsetsMake(0, 15, 0, 0)
but it is not working and image Back button looks smaller. How can I do to add space to the left of Back button?
I would recommend replacing UINavigationBar with a simple UIView. This way you would gain a full control over the layout of the navigation bar. It wouldn't be anything more than a transparent UIView with a back button and a title label inside. As simple as that.
The real UINavigationBar is more than that. It's meant to manage a stack of UINavigationItem objects. It adjusts itself depends on the current item and knows how to make an animated (and even interactive) transition from one state to another. That's why you can't change much about the bar's appearance. You shouldn't treat it as a regular view.
UPDATE
Another way to achieve this is a little tricky. You can implement it completely from a storyboard and you don't need mess with appearance.
Add UINavigationBar to a view controller.
Add a plain UIView to the left side of UINavigationBar and make its background color completely transparent.
Add UIButton to the view added in the previous step and set a back icon as its image.
Add constraints to the button to align it to the right side of its superview.
Adjust the width of the view so the back button position is exactly where you want it to be.
This is a view hierarchy in the storyboard:
This is how your UINavigationBar will look like (for you the background will be transparent):