对 UIImageView 高度和宽度更改进行动画处理

Animate UIImageView height and width changes

提问人:Philipp 提问时间:9/13/2023 最后编辑:Philipp 更新时间:9/15/2023 访问量:47

问:

我的目标是对从左上角到视图中心的 UIImageView 过渡进行动画处理。它还必须将其宽度和高度更改为屏幕宽度,并将角半径更改为零。

如何修改以下代码,以便 UIImageView 更改其宽度和高度:

    private func imageAnimates() {
        UIView.animate(
            withDuration: 0.5,
            delay: 0.0,
            options: .curveLinear
        ) {
            self.userImage.layer.cornerRadius = 0
            self.userImage.center = CGPoint(x: self.view.center.x, y: self.view.center.y)
        } completion: { finished in
            print("Image animated")
        }
    }

UPD:在 vaibhav sharma 的回答之后,我将代码更新为:

        UIView.animate(
            withDuration: 0.5,
            delay: 0.0,
            options: .curveLinear
        ) {
            self.userImage.alpha = 1.0
            self.userImage.layer.cornerRadius = 0
            self.userImage.frame = CGRect(
                 x: (screenWidth - finalWidth) / 2,
                 y: (self.view.frame.size.height - finalHeight) / 2,
                 width: finalWidth,
                 height: finalHeight
             )
        } completion: { finished in
            print("Image animated")
        } 

但我得到的结果不是我所期望的。这是一段屏幕录像:https://sendvid.com/i1fxbf0y。现在,图像似乎从左上角的小图片变为原始帧和位置。它甚至没有移动到中心。

swift uiview uikit uianimation

评论

0赞 DonMag 9/14/2023
您是否在 Storyboard 中添加图像视图?如果是这样,那就是你的问题。您不能“混合和匹配”约束和直接帧设置。

答:

0赞 vaibhav sharma 9/13/2023 #1

根据我的理解,可能是我错了,请尝试

   private func imageAnimates() {
    // Calculate the final width and height to match the screen width
    let screenWidth = self.view.frame.size.width
    let finalWidth = screenWidth
    let finalHeight = screenWidth * (self.userImage.frame.size.height / self.userImage.frame.size.width)
    
    UIView.animate(
        withDuration: 0.5,
        delay: 0.0,
        options: .curveLinear
    ) {
        self.userImage.alpha = 1.0
        self.userImage.layer.cornerRadius = 0
        self.userImage.frame = CGRect(
            x: (self.view.frame.size.width - finalWidth) / 2,
            y: (self.view.frame.size.height - finalHeight) / 2,
            width: finalWidth,
            height: finalHeight
        )
    } completion: { finished in
        print("Image animated")
    }
}
  • 请看以下几点:
    1. 根据屏幕宽度计算 finalWidth 和 finalHeight,同时保持原始图像的纵横比。

    2. 将 UIImageView 的 frame 属性设置为计算出的 finalWidth 和 finalHeight,并将其置于屏幕的中心。

评论

0赞 Philipp 9/13/2023
尝试使用代码,但结果与我预期的不同。看看我的问题更新。
0赞 Philipp 9/13/2023
如果有帮助,这是我的完整项目: github.com/lord-anonymoose/social-media-app/tree/feature-8
0赞 Philipp 9/13/2023
动画在 ProfileViewController 中使用
1赞 DonMag 9/15/2023 #2

你需要从*简单开始 - 只处理这个图像视图动画,直到你让它正常工作。然后将其添加到复杂的控制器中。

您不能“混合搭配”约束和直接帧设置。UIKit 将自动重置框架以匹配约束。

相反,请仅对视图使用框架设置...您可以将自动布局约束用于其他所有内容。userImage

所以,看看这个 - 点击任意位置以显示和增长或缩小和隐藏图像视图:

class ProfileViewController: UIViewController {
    
    private lazy var userImage: UIImageView = {
        
        //let imageView = UIImageView(image: UIImage(named: me.login))
        
        // I don't have your "me.login" so let's use SF Symbol
        let imageView = UIImageView()
        if let img = UIImage(systemName: "person.fill") {
            imageView.image = img
        }
        
        imageView.layer.cornerRadius = 45
        imageView.clipsToBounds = true

        // we're going to set the frame directly, so
        //  use true (it's the default so we don't really need to set it)
        imageView.translatesAutoresizingMaskIntoConstraints = true
        
        imageView.alpha = 0.0
        
        // while we're designing this,
        //  use a backgroundColor so we can see the framing
        imageView.backgroundColor = .red
        
        return imageView
    }()
    
    // these will be update in viewDidLayoutSubviews()
    //  when we know the view frame and safeAreaInsets
    private var userImageStartFrame: CGRect = .zero
    private var userImageFinalFrame: CGRect = .zero
    private var screenWidth: CGFloat = 0.0

    // MARK: - Lifecycle
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // we'll adjust the origin in viewDidLayoutSubviews()
        userImageStartFrame = CGRect(x: 0.0, y: 0.0, width: 90.0, height: 90.0)
        
        view.addSubview(userImage)

        // do NOT set constraints on userImage !!!

    }

    override func viewDidLayoutSubviews() {
        
        super.viewDidLayoutSubviews()

        // viewDidLayoutSubviews() will be called many times, so
        //  only set the userImage view frames when the view width changes
        if screenWidth != view.frame.width {
            
            screenWidth = view.frame.width
            
            // get the safe area rect
            let r: CGRect = self.view.bounds.inset(by:self.view.safeAreaInsets)

            userImageStartFrame.origin = r.origin

            // let's make the large-center frame 90% of the safe area width
            let finalWidth: CGFloat = r.width * 0.9
 
            userImageFinalFrame = CGRect(
                x: r.origin.x + ((r.width - finalWidth) * 0.5),
                y: r.origin.y + ((r.height - finalWidth) * 0.5),
                width: finalWidth, height: finalWidth
            )
            
            userImage.frame = userImageStartFrame

        }

    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        UIView.animate(
            withDuration: 0.5,
            delay: 0.0,
            options: .curveLinear
        ) {
            //self.backgroundBlur.alpha = 0.5
            //self.blurCloseButton.alpha = 1.0

            if self.userImage.alpha == 0.0 {
                // userImage is currently transparent (alpha: 0.0)
                //  so we want to show it
                self.userImage.alpha = 1.0
                self.userImage.layer.cornerRadius = 0
                self.userImage.frame = self.userImageFinalFrame
            } else {
                self.userImage.alpha = 0.0
                self.userImage.layer.cornerRadius = 45
                self.userImage.frame = self.userImageStartFrame
            }
            
        } completion: { finished in
            print("Background blur appeared")
        }

    }
    
}

评论

0赞 Philipp 9/19/2023
谢谢你的解释!我不知道不能同时使用 NSLayoutContraint 和框架。它真的很有帮助!