Recently I tried to apply a custom transition to a custom contextMenu.
However, I want to make sure that during the transition process (which is not over yet), my contextMenu elements such as buttons can be tapped.
But I tried a lot of things without success. I know you have a lot of experience, so I would like to ask you about how to implement the transition and be able to interact before it is over.
I know that a UIView can be tapped during animation, but I haven't tried the button in a UIView.
I've been trying to transition ViewControllers. For example, in a transition from fromViewController to toViewController, I wanted to be able to tap on a tableView in toViewController during the transition, but I was frustrated and found it very difficult to implement. I would like to ask you about the possibilities of interaction during the Viewcontrollers transition.
(PS: In Github Issues, I uploaded a GIF example of the plus button on the left of the input box in iMessage. After tapping the plus button, you can tap the "Apple Cash" button before the transition is finished.)
Your advice would be incredibly valuable to me. Thank you in advance for your time and assistance.
[GithubLink]https://github.com/Juhnkerg/DemoForInteractionDuringTransition)
Visual Design
RSS for tagDiscuss animation, branding, color, layout, typography, and other elements of great looking apps.
Posts under Visual Design tag
33 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hi,
I'm having some trouble when animating my chart with a custom AxisValueLabel. Specifically, as soon as I set its init parameter centered to true, the x axis' leftmost value of the previous dataset sticks around during the animation to the next dataset.
Here's a GIF of a screen recording from a minimum reproducible example I built. Keep a close eye on the x axis of the third BarMark, and notice how the 0 from the first BarMark sticks around longer than necessary / intended. While it isn't visible in the GIF, the extra 0 eventually does disappear, but only after the transition if fully complete, making the animation feel distracting and amateur-ish, rather than smooth.
This is my code for the x axis. If I turn centered to false, this problem immediately goes away.
.chartXAxis {
AxisMarks(
preset: .aligned,
values: .stride(
by: .day,
count: 1,
calendar: .current
)
) { value in
AxisValueLabel(centered: true) {
Text("\(value.index)")
}
}
}
As you might be able to tell, my x axis is date based, and I'm working on showing one BarMark per day of the week.
I have a ZIP of my minimum reproducible example that I can provide for anyone interested, although I don't know how to share it here.
Any advice on what I can do to fix this?
I've defined a custom layout container by having a struct conform to Layout and implementing the appropriate methods, and it works as expected.
The problem comes when trying to display Image, as they are shown squished when just using the .resizable() view modifier, not filling the container when using .scaledToFit() or extending outside of the expected bounds when using .scaledToFill().
I understand that this is the intended behaviour of these modifiers, but I would like to replicate UIImageView's scaledAspectFill.
I know that this can usually be achieved by doing:
Image("adriana-wide")
.resizable()
.scaledToFill()
.frame(width: 200, height: 200)
.clipped()
But hardcoding the frame like that defeats the purpose of using the Layout, plus I wouldn't have direct access to the correct sizes, either.
The only way I've managed to make it work is by having a GeometryReader per image, so that the expected frame size is known and can bet set, but this is cumbersome and not really reusable.
GalleryGridLayout() {
GeometryReader { geometry in
Image("adriana-wide")
.resizable()
.scaledToFill()
.frame(width: geometry.size.width, height: geometry.size.height)
.clipped()
}
[...]
}
Is there a more elegant, and presumably efficient as well as reusable, way of achieving the desired behaviour?
Here's the code of the Layout.
Hi, I'm product designer and I'm looking for HIG for layout recomendations, currently I can't find anything about recommended numbers for spacing/paddings etc.. Did Apple remove this and why?
Hi, I have pretty much finished my app's layout but realized I needed to scale it for different devices. I have read online that hardcoding values (esp in frames) is a big no-no, and GeometryReader should be heavily utilized. Also was recommended ViewThatFits. The problem is, I want the app to look the exact same across all devices. What is the best way to get started?
Also, when testing, do I only have to test on an iPad and iPhone or are the dimensions significantly different amongst each class of devices?
I need to create an animation for previous and next questions. The current question should move out and next/prev question should come in.
If you run the app and keep pressing next, it works well.
Current question moves out towards left
Next question appears from right to left.
But if I switch the direction to previous,
Current question moves out towards left( should move out towards right)
next question comes in from left to right( which is correct).
Similar discrepancy happens when I switch direction from prev to next.
Why is this so?
import SwiftUI
struct Question {
let id: Int
let text: String
}
extension AnyTransition {
static var slideRight: AnyTransition {
let insertion = AnyTransition.move(edge: .trailing)
let removal = AnyTransition.move(edge: .leading)
return .asymmetric(insertion: insertion, removal: removal)
}
static var slideLeft: AnyTransition {
let insertion = AnyTransition.move(edge: .leading)
let removal = AnyTransition.move(edge: .trailing)
return .asymmetric(insertion: insertion, removal: removal)
}
}
struct QuizView: View {
let questions = [
Question(id: 1, text: "11111111111"),
Question(id: 2, text: "222222222222222222222222"),
Question(id: 3, text: "3333333333333333333"),
Question(id: 4, text: "444444444444444444444444"),
Question(id: 5, text: "55555555555555555555"),
Question(id: 6, text: "6666666666666666666666666")
]
@State private var currentQuestionIndex = 0
@State private var navigationDirection: NavigationDirection = .forward
var body: some View {
VStack(spacing: 20) {
Text(questions[currentQuestionIndex].text)
.id(questions[currentQuestionIndex].id) // Important for transition
.transition(navigationDirection == .forward ? .slideRight : .slideLeft)
.frame(maxWidth: .infinity, maxHeight: .infinity)
HStack {
Button("Previous") {
moveToPreviousQuestion()
}
.disabled(currentQuestionIndex == 0)
Spacer()
Button("Next") {
moveToNextQuestion()
}
.disabled(currentQuestionIndex == questions.count - 1)
}
}
.padding()
.animation(.easeInOut(duration: 1.0), value: currentQuestionIndex)
}
private func moveToNextQuestion() {
if currentQuestionIndex < questions.count - 1 {
navigationDirection = .forward
currentQuestionIndex += 1
}
}
private func moveToPreviousQuestion() {
if currentQuestionIndex > 0 {
navigationDirection = .backward
currentQuestionIndex -= 1
}
}
}
enum NavigationDirection {
case forward, backward
}
If you run the app and keep pressing next, it works well.
current question moves out towards left, next question appears from right to left.
But if I switch the direction to previous,
current question moves out towards left( should move out towards right) next question comes in from left to right( which is correct).
Similar discrepancy happens when I switch direction from prev to next.
Why is this so?
import SwiftUI
struct Question {
let id: Int
let text: String
}
extension AnyTransition {
static var slideRight: AnyTransition {
let insertion = AnyTransition.move(edge: .trailing)
let removal = AnyTransition.move(edge: .leading)
return .asymmetric(insertion: insertion, removal: removal)
}
static var slideLeft: AnyTransition {
let insertion = AnyTransition.move(edge: .leading)
let removal = AnyTransition.move(edge: .trailing)
return .asymmetric(insertion: insertion, removal: removal)
}
}
struct QuizView: View {
let questions = [
Question(id: 1, text: "11111111111"),
Question(id: 2, text: "222222222222222222222222"),
Question(id: 3, text: "3333333333333333333"),
Question(id: 4, text: "444444444444444444444444"),
Question(id: 5, text: "55555555555555555555"),
Question(id: 6, text: "6666666666666666666666666")
]
@State private var currentQuestionIndex = 0
@State private var navigationDirection: NavigationDirection = .forward
var body: some View {
VStack(spacing: 20) {
Text(questions[currentQuestionIndex].text)
.id(questions[currentQuestionIndex].id) // Important for transition
.transition(navigationDirection == .forward ? .slideRight : .slideLeft)
.frame(maxWidth: .infinity, maxHeight: .infinity)
HStack {
Button("Previous") {
moveToPreviousQuestion()
}
.disabled(currentQuestionIndex == 0)
Spacer()
Button("Next") {
moveToNextQuestion()
}
.disabled(currentQuestionIndex == questions.count - 1)
}
}
.padding()
.animation(.easeInOut(duration: 1.0), value: currentQuestionIndex)
}
private func moveToNextQuestion() {
if currentQuestionIndex < questions.count - 1 {
navigationDirection = .forward
currentQuestionIndex += 1
}
}
private func moveToPreviousQuestion() {
if currentQuestionIndex > 0 {
navigationDirection = .backward
currentQuestionIndex -= 1
}
}
}
enum NavigationDirection {
case forward, backward
}
Hi. Can anyone who's into cosmology give hints as to how I might depict and animate dark matter for the VisionPro?
Hi, I am currently working through a SwiftUI tutorial where I am adding words entered into a text field to be displayed in a list beneath it. While doing so, I noticed that when trying to animate the insertion of the word into the text field, it wasn't working.
private func addNewWord(){
let answer = newWord.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)
guard answer.count > 0, !usedWords.contains(answer) else {return}
newWord = ""
withAnimation {
usedWords.insert(answer, at: 0)
}
}
But, when I switched around those last 2 statements, the following code works properly:
private func addNewWord(){
let answer = newWord.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)
guard answer.count > 0, !usedWords.contains(answer) else {return}
withAnimation {
usedWords.insert(answer, at: 0)
}
newWord = ""
}
Does anyone know why this is ? Is there something that has to do with the withAnimation call not being the final part in the function call ? Does it have to do with altering different State variables before or after the withAnimation call ? Is this expected behavior or some type of bug?
Please let me know, here is the entire SwiftUI Struct in case you want to run this and see for yourselves. Thank you
(Currently using xcode 15.0 on OS Sonoma 14.3.1)
struct ContentView: View {
@State private var newWord : String = ""
@State private var usedWords : [String] = [String]()
@State private var rootWord : String = ""
var body: some View {
NavigationStack {
List {
Section {
TextField("Enter your word", text: $newWord).textInputAutocapitalization(.never)
}
Section{
ForEach(usedWords, id: \.self){ word in
HStack {
Image(systemName: "\(word.count).circle")
Text(word)
}
}
}
}
.navigationTitle(rootWord)
}
.padding()
.onSubmit() {
addNewWord()
}
}
private func addNewWord(){
let answer = newWord.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)
guard answer.count > 0, !usedWords.contains(answer) else {return}
// newWord = ""
withAnimation {
usedWords.insert(answer, at: 0)
}
newWord = ""
}
}
HI,
We need to rebrand our app name and app logo only for one country, for other regions/ countries. the existing branding should be shown.
Is it possible to achieve this?
The app name, logo need to be set from the code wise based on the region selected in the device settings.
Please share me the options to implement on this.
Dear all,
I am using SwiftUI 15.2 and I have created a donut chart using SectorMark.
Now, I have three values to show in the chart. When I set up the foregroundstyle, it returns orange, blu and green colors, whereas I'd like to have different colors (e.g. red, yellow and green).
Chart(data, id: \.risultato) { dataItem in
SectorMark(angle: .value("Type", dataItem.partite),
innerRadius: .ratio(0.7),
angularInset: 1.5)
.foregroundStyle(by: .value("Type", dataItem.risultato))
.annotation(position: .overlay){
Text("\(dataItem.partite)")
.font(.caption)
}
}
.frame(height: 150)
I'm reporting the final result here below.
Do you know how I can customize them?
Thanks in advance for your support,
Andrea
Dear All,
I want to maximise an Image above a Form. That should be easy enough but with the naive code, the Form is pushed out of the screen. I don't want to allow scrolling.
This is my code:
Image(systemName: "gear")
.resizable()
.scaledToFit()
Form {
Section("section 1") {
Text("text 1")
Text("text 2")
Text("text 3")
}
Section("section 2") {
Text("text 1")
Text("text 2")
Text("text 3")
}
}
.scrollDisabled(true)
Any hint on how to achieve that the Form is fully displayed and the Image dynamically maximised in the space that is left?
Thanks in advance!
Cheers
F
Hello. How to achieve these gradients along with this beautiful translucent text (marked as green) in SwiftUI?
I'm designing panoramic screenshots and would like to know the pixel width between images in the app store so I can adjust my assets accordingly.
Specs for iPhone 5.5 and 6.5 and 12.9'' iPads, horizontal and vertical, would be welcome.
Thank you.
I want to add a small play button to play a song preview on my site. I don't want to use the embedded player because I want to style it custom. If I use the MusicKit Web library, do I need to add Apple branding legally? I don't see anywhere that says its required and I want to confirm.
Customers are reporting after the update to mac OS Sonoma 14.2 bitmap images have a black background! When we run the same application on Sonoma 14.1.1 the bitmap images appear as expected
Like I said at the beginning, it happened after upgrading to Sonoma 14.2 so it introduced the issue.
Hi Folks, I am reaching out for an iOS A11y color contrast issue, which I have also fired a bug report 12525894 but does not get any reply.
The UIAlertAction in destructive style has a poor color contrast ratio of less than 4.5: 1 between text color and background color. This applies to any system/third party app which uses UIAlertViewController from UIKit and Alert from SwiftUI (Take the system Photos app as an example). Given that the "titleTextColor" property from UIAlertAction class is private, developers have no ways to modify the alert action to make it WCAG compatible.
Here is an example of the Photo app alert.
The text "Delete Photo" (#EB4E3D) should have a contrast ratio of at least 4.5 to 1 against its background(#EAEBE7) to comply to the Web Content Accessibility Guidelines (WCAG).
Actual result: The text "Delete Photo" (#EB4E3D) has a contrast ratio of 3.08 to 1 against its background(#EAEBE7), which does not match 4.5:1 Web Content Accessibility Guidelines (WCAG).
We're working on new UX designs and we're wondering if iPhone SE compatibility is required for App Store approval as it will impact our work. Appreciate any insight here!
I'm working on a SwiftUI project where I use a .sheet modifier to present a bottom drawer with two detent sizes: .medium and .large. The drawer contains a button that toggles its size between these two states. This part works as expected. However, I'm facing an animation issue when I set a non-default background color to the sheet.
Here's the simplified code for context:
struct ContentView: View {
@State private var selectedDetent: PresentationDetent = .medium
var body: some View {
VStack {}
.sheet(isPresented: .constant(true)) {
Button("Press Me") {
selectedDetent = selectedDetent == .medium ? .large : .medium
}
.presentationBackground(.gray)
.presentationDetents([.medium, .large], selection: $selectedDetent)
}
}
}
The issue arises when I try to set a background color using .presentationBackground(.gray) (or any color, even white). Instead of the expected behavior when pressing the button (where the upper part of the sheet closes, and the bottom part stays attached to the screen bottom), the sheet momentarily turns into a square in the middle of the screen before moving down to the .medium position.
As soon as I remove the.presentationBackground(.gray) line, it works as expected:
I tried several approaches, such as:
Using a custom background view.
Explicitly specifying animations.
Adjusting view hierarchy and layering.
Unfortunately, none of these solutions worked. The issue persists with any color. It seems like a bug or limitation in SwiftUI's handling of sheet animations with custom backgrounds.
Has anyone else encountered this issue, or does anyone have a workaround or solution?
Hey there! 👋🏻
I'm currently localizing my app and came across the interesting fact that in China (I'm not aware of other countries) the color red is associated with something positive, whereas in Germany (where I come from) the color green evokes a positive association.
I then tried out whether this is taken into account in Apple's native apps. For example, in the Stocks app, a price gain with German localization is shown in green, whereas a price gain with Chinese localization is shown in red.
Now I'm wondering whether there is a static property of the Color or UIColor class where I can retrieve a positive or negative color depending on the localization.
Does anyone have experience with this?
Thanks in advance! 😊