Hi! I was trying to add an animation to my SwiftUI view with UIKit, but after the animation runs there's a delay before the view will accept touch interactions. I thought it was because of the frame size of the view controller, but even after fixing that I still get the delay. Could anyone point me to where I might be going wrong, or if maybe using a UIKit modifier for the animation just doesn't work?
Any help would be greatly appreciated!
UIView:
class BounceView: UIView {
required init() {
super.init(frame: .zero)
}
func bounceAnimation() {
guard let piece = self.subviews.first else { return }
UIView.animate(withDuration: 0.7, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0) {
piece.frame.origin.x += 10
}
}
func bounceBack() {
guard let piece = self.subviews.first else { return }
UIView.animate(withDuration: 0.7, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0) {
piece.frame.origin.x -= 10
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
UIView controller:
class BounceViewController: UIViewController {
init(controller: UIViewController) {
super.init(nibName: nil, bundle: nil)
view = BounceView()
addChild(controller)
controller.view.translatesAutoresizingMaskIntoConstraints = false
controller.view.backgroundColor = .clear
view.addSubview(controller.view)
controller.didMove(toParent: self)
}
// adjusts view to match bounds of child
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let subviewFrame = self.view.subviews.first?.bounds ?? .zero
view.frame = subviewFrame
print(subviewFrame)
self.updateViewConstraints()
}
func update(animated: Bool) {
let bounceView = view as? BounceView
if animated {
bounceView?.bounceAnimation()
} else {
bounceView?.bounceBack()
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
SwiftUI wrapper:
struct BounceUIViewController: UIViewControllerRepresentable {
private var controller: UIViewController
@Binding var animated: Bool
init(controller: UIViewController, animated: Binding<Bool>) {
self.controller = controller
self._animated = animated
}
func makeUIViewController(context: Context) -> BounceViewController {
BounceViewController(controller: controller)
}
func updateUIViewController(_ uiViewController: BounceViewController, context: Context) {
uiViewController.update(animated: animated)
}
}
View extension:
extension View {
func bounce(animated: Binding<Bool>) -> some View {
modifier(Bounce(animated: animated))
}
}
struct Bounce: ViewModifier {
@Binding var animated: Bool
init(animated: Binding<Bool>) {
self._animated = animated
}
func body(content: Content) -> some View {
BounceUIViewController(controller: content.uiViewController, animated: $animated)
}
}
Interaction Design
RSS for tagCreate engaging ways for users to interact with your software.
Posts under Interaction Design tag
9 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
This question came up, a customer wants to add payment, with gesture, to their app. This gesture is a swipe, from bottom to top (like when minimizing applications). The question immediately arose, will the application pass the review with such UI/UX ? Will there be any problems ? I'm not talking about problems when the user can minimize the application when paying, or pay (accidentally) when minimizing. I want to know if there will be any problems from Apple's rules when releasing the app ? I haven't found the exact information yet
This is a continuation of
https://developer.apple.com/forums/thread/760861
Still a mixed Qt/C++/ObjC app, developed with Qt Creator.
The gist ist that I can call Sign in With Apple and authorise, but once the Authorisation Window/Panel goes away, the app is blocked.
PBSigninWithApple:: PBSigninWithApple()
{
myImpl = [[PBSigninWithApple alloc] initWithOwner:this];
}
- (id)initWithOwner:(PBSigninWithApple *) owner {
self = [super init];
myOwnerSIWA = owner;
ASAuthorizationAppleIDProvider *appleIDProvider = [ASAuthorizationAppleIDProvider new];
ASAuthorizationAppleIDRequest *request = appleIDProvider.createRequest;
request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
ASAuthorizationController *controller = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
controller.presentationContextProvider = self;
controller.delegate = self;
[controller performRequests];
return self;
}
The code example above is obviously reduced, but the real things works. I get the Sign in With Apple window and can authorise by TouchId.
The didCompleteWithAuthorization and didCompleteWithError methods also work, emitting the the idendityToken to the calling superclass works, the authorisation window goes away - but not really. The calling QT app is semi-blocked. I can close windows ny using the Escape key, but any clicking just gives the dreaded beep and nothing happens. So I assume that we didn‘t tear down everything and that the anchor or whatever still has to focus.
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(macos(10.15)) {
if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
ASAuthorizationAppleIDCredential *appleIDCredential = authorization.credential;
NSString *user = appleIDCredential.user;
NSData *identityToken = appleIDCredential.identityToken;
NSData *authorizationCode = appleIDCredential.authorizationCode;
emit myOwnerSIWA->accessCodeReceived(identityToken);
}
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:ASAuthorizationAppleIDProviderCredentialRevokedNotification
object:nil];
[myAnker close];
[self release];
}
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(ASAuthorization *)authorization API_AVAILABLE(macos(10.15)) {
emit myOwnerSIWA->accessCodeReceived(QString(""));
[[NSNotificationCenter defaultCenter]
removeObserver:self name:ASAuthorizationAppleIDProviderCredentialRevokedNotification
object:nil];
}
-(ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller API_AVAILABLE(macos(10.15)) {
NSRect frame = NSMakeRect(30, 30, 230, 230);
NSUInteger windowStyle = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable | NSWindowStyleMaskFullSizeContentView;
NSWindow* window = [[[NSWindow alloc] initWithContentRect:frame
styleMask:windowStyle
backing:NSBackingStoreBuffered
defer:NO] autorelease];
window.minSize = CGSizeMake(200, 100);
window.releasedWhenClosed = TRUE;
myAnker = window;
return window;
}
I made an extension with a UIView that takes a SwiftUI view, gets its UIView, and then adds it as a subview. But now the subview isn't receiving any touches and idk how to fix that. I've already tried point(inside:with:) but it doesn't seem to work. I've also tried forwarding the touches from touchesBegan, touchesMoved, etc., but that didn't work either.
Any help or advice would be greatly appreciated!
Extension with the UIView:
// Add view modifier to View
extension View {
func transformable() -> some View {
modifier(Transformable())
}
}
// View modifier
struct Transformable: ViewModifier {
func body(content: Content) -> some View {
TransformableUIView(content: content)
}
}
// Wrap UIView
struct TransformableUIView<V>: UIViewRepresentable where V: View {
private var content: V
init(content: V) {
self.content = content
}
func makeUIView(context: Context) -> TransformableView<V> {
TransformableView(content: content)
}
func updateUIView(_ uiView: TransformableView<V>, context: Context) {}
}
// View that handles zoom, pan, and rotate gestures
class TransformableView<V>: UIView, UIGestureRecognizerDelegate where V: View {
private var content: V
private var initialCenter: CGPoint = .zero
private var totalScale: CGFloat = 1.0
private var boundsDidSet = false
required init(content: V) {
self.content = content
super.init(frame: .zero)
self.addSubview(content.uiView)
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panPiece(_:)))
panGesture.minimumNumberOfTouches = 2
panGesture.maximumNumberOfTouches = 2
panGesture.delegate = self
self.addGestureRecognizer(panGesture)
let scaleGesture = UIPinchGestureRecognizer(target: self, action: #selector(scalePiece(_:)))
scaleGesture.delegate = self
self.addGestureRecognizer(scaleGesture)
let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotatePiece(_:)))
rotateGesture.delegate = self
self.addGestureRecognizer(rotateGesture)
}
// Position content in center of view
override func layoutSubviews() {
super.layoutSubviews()
// Return if bounds are already set
if boundsDidSet {
return
}
guard let piece = self.subviews.first else { return }
piece.center = CGPoint(x: self.bounds.size.width / 2, y: self.bounds.size.height / 2)
boundsDidSet = true
}
// Function called when pan gesture is recognized
@objc private func panPiece(_ gestureRecognizer: UIPanGestureRecognizer) {
guard let piece = gestureRecognizer.view?.subviews.first else { return }
// Get the changes in the X and Y directions relative to
// the superview's coordinate space.
let translation = gestureRecognizer.translation(in: piece.superview)
if gestureRecognizer.state == .began {
// Save the view's original position.
self.initialCenter = piece.center
}
// Update the position for the .began, .changed, and .ended states
if gestureRecognizer.state != .cancelled {
// Add the X and Y translation to the view's original position.
var newCenter = CGPoint(x: initialCenter.x + translation.x, y: initialCenter.y + translation.y)
// Prevent content from leaving view
newCenter.x = clamp(value: newCenter.x, min: 0, max: self.bounds.width)
newCenter.y = clamp(value: newCenter.y, min: 0, max: self.bounds.height)
piece.center = newCenter
}
else {
// On cancellation, return the piece to its original location.
piece.center = initialCenter
}
}
// Function called when scale gesture is recognized
@objc private func scalePiece(_ gestureRecognizer : UIPinchGestureRecognizer) {
guard let piece = gestureRecognizer.view?.subviews.first else { return }
if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
// Set min/max zoom
let newScale = clamp(value: totalScale * gestureRecognizer.scale, min: 0.2, max: 20) / totalScale
piece.transform = (piece.transform.scaledBy(x: newScale, y: newScale))
gestureRecognizer.scale = 1.0
totalScale *= newScale
}
}
// Function called when rotate gesture is recognized
@objc private func rotatePiece(_ gestureRecognizer : UIRotationGestureRecognizer) {
guard let piece = gestureRecognizer.view?.subviews.first else { return }
if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
piece.transform = piece.transform.rotated(by: gestureRecognizer.rotation)
gestureRecognizer.rotation = 0
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func clamp(value: CGFloat, min: CGFloat, max: CGFloat) -> CGFloat {
if value < min {
return min
} else if value > max {
return max
} else {
return value
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Get UIView from SwiftUI View:
// Get UIView from SwiftUI View
extension View {
var uiView: UIView {
UIHostingController(rootView: self).view
}
}
ContentView:
struct ContentView: View {
var body: some View {
CanvasView()
.frame(width: 880, height: 608)
.transformable()
.background(Color.blue)
}
}
Hello,
I’m an aspiring full stack dev and I’m just wondering how the heck you get good UI AND UX. I’m currently moodboarding and seeing how things look in FigJam and then taking that and coding in Swift. I am struggling and my sanity is hanging on by a string 😂. So tell me, how do you get good UI and UX?
Hii apple!
What about zooming with 2 fingers without making a screenshot to zoom it!!
I will love to make a pattent about it!!!
Everywhere we ad on the iphone should we zoom in with 2 fingers!!!
love to hear from ya
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)
Hello everyone, My iPhone has still not working for 3 months because of Error 1110. I hope the Apple software team can see this message and support us in fixing this issue soon, we lost our data and in this way, most people will not trust iPhones again if they can't find any fix even if this fix is by charge. Thank you.
#1110 #error1110
Hello,
I've a team for developing game in my small company. And we've developed an Obstacle game in Unity from scratch. every single UI, logic & even sound is implemented by our own developers and musicians. It means, every single element is proprietory of our own.
I suggest you folks to try out the game in Android playstore by searching the game name as "Cherry Blossom Hills Obstacle" .
But once I submitted the same game in iOS App store, the reviewers continously saying, it's a 4.3.0 Design Spam without any to the point feedback basically :(
Could you anyone help me resolving this issue? A definitive but even single help/suggestion would be highly appreciated.
Regards,
Md. Rezoanul Alam.