Swift. Rotation animation, 100 lines of code

Effect:

Static: sub view s are arranged symmetrically, allowing dynamic addition, and 0 ~ 24 can be displayed well

When rotating: the center view does not move, the sub view rotates with the gesture, and the bottom sub view becomes larger and prominent

Implementation ideas:

All the controls are added to a large background view. In essence, the background view is rotated. When the background view is rotated, all its child controls are rotated in the opposite direction. This effect is achieved

Using touchMoved method to get gesture, using transform to achieve animation

The view at the bottom becomes larger is the loop judgment sub view.frame.x. when it is in a range and frame.y is larger than the center view.frame.y, modify its transform to make it larger, and modify its tag to mark that it has become larger. When its frame.x is out of the predetermined range, restore it

Implementation mode:

1. Add background transparent view and center circle view

2. Add peripheral rotor view

3. Add rotation method

4. Interactive optimization

1. Add background transparent view and center circle view

 ///Add background view, which is also a rotated view
    private func setContentView() {
        setCircleView()
        contentView = UIView(frame: CGRect(x: 0, y: 0, width: ScreenInfo.Width, height: ScreenInfo.Width))
        contentView?.center = self.view.center
        self.view.addSubview(contentView!)
        contentView!.addSubview(circleView!)
    }
    ///Add middle circle view
    private func setCircleView(){
        let view = UIImageView(frame: CGRect(x: 0.5 * CGFloat(1 - PROPORTION) * ScreenInfo.Width + 10, y: 0.5 * CGFloat(1 - PROPORTION) * ScreenInfo.Width + 10, width: ScreenInfo.Width * CGFloat(PROPORTION) - 20, height: ScreenInfo.Width * CGFloat(PROPORTION) - 20))
        ///In order to adapt and ensure the size change center unchanged
        let centerPoint = view.center
        view.frame.size = CGSize(width: ScreenInfo.Width * CGFloat(PROPORTION) - 40, height: ScreenInfo.Width * CGFloat(PROPORTION) - 40)
        view.center = centerPoint
        view.image = UIImage(named: "11")
        view.layer.cornerRadius = view.frame.width*0.5
        view.layer.masksToBounds = true
        view.isUserInteractionEnabled = true
        circleView = view
    }

2. Add peripheral rotor view

   ///Sub view of layout rotation
    private func rotationCircleCenter(contentOrgin: CGPoint,
                                      contentRadius: CGFloat,subnode: [String]){
        // Add proportion to realize adaptive size when the number of child view s to be added is large
        var scale: CGFloat = 1
        if subnode.count > 10 {
            scale = CGFloat(CGFloat(subnode.count) / 13.0)
        }

        for i in 0..<subnode.count {
            let x = contentRadius * CGFloat(sin(.pi * 2 / Double(subnode.count) * Double(i)))
            let y = contentRadius * CGFloat(cos(.pi * 2 / Double(subnode.count) * Double(i)))
            // When the number of child views is greater than 10, the view.size becomes smaller to prevent view offset, and the view.center should be kept unchanged
            let view = EWSubView(frame: CGRect(x:contentRadius + 0.5 * CGFloat((1 + PROPORTION)) * x - 0.5 * CGFloat((1 - PROPORTION)) * contentRadius, y: contentRadius - 0.5 * CGFloat(1 + PROPORTION) * y - 0.5 * CGFloat(1 - PROPORTION) * contentRadius, width: CGFloat((1 - PROPORTION)) * contentRadius, height: CGFloat((1 - PROPORTION)) * contentRadius), imageName: subnode[i])
            let centerPoint = view.center
            view.frame.size = CGSize(width: CGFloat((1 - PROPORTION)) * contentRadius / scale , height: CGFloat((1 - PROPORTION)) * contentRadius / scale)
            view.center = centerPoint
            view.drawSubView()
            // This tag determines whether the view is in the state of becoming larger at the bottom, and in the state of non becoming larger 0, it becomes larger 1
            view.tag = 0
            // Get the rect of the child view in the current screen to make the bottom one bigger
            let rect = view.convert(view.bounds, to: UIApplication.shared.keyWindow)
            let viewCenterX = rect.origin.x + (rect.width) / 2
            if viewCenterX > self.view.center.x - 20 && viewCenterX < self.view.center.x + 20 && rect.origin.y > (contentView?.center.y)! {
                view.transform = view.transform.scaledBy(x: 1.5, y: 1.5)
                view.tag = 1
            }
            contentView?.addSubview(view)
            viewArray.append(view)
        }
    }

3. Add rotation method

 ///The core rotation method, the specific method is the background view rotation, the center view and the sub view rotate at the same angle in reverse, to achieve the animation effect
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let contentView = contentView else { return }
        guard let circleView = circleView else { return }
        orgin = CGPoint(x: 0.5 * ScreenInfo.Width, y: MENURADIUS + 0.17 * ScreenInfo.Height)
        let currentPoint = touches.first?.location(in: self.view)
        if self.touchPointInsideCircle(center: orgin!, radius: MENURADIUS*1.45, targetPoint: currentPoint!){
            b = DIST(pointA: beginPoint!, pointB: orgin!)
            c = DIST(pointA: currentPoint!, pointB: orgin!)
            a = DIST(pointA: beginPoint!, pointB: orgin!)
            let angleBegin = atan2(beginPoint!.y - orgin!.y, beginPoint!.x - orgin!.x)
            let angleAfter = atan2(currentPoint!.y - orgin!.y, currentPoint!.x - orgin!.x)
            let angle = angleAfter - angleBegin
            // Background view rotation
            contentView.transform = contentView.transform.rotated(by: angle)
            // Center view reverse rotation
            circleView.transform = circleView.transform.rotated(by: -angle)
            for i in 0..<viewArray.count {
                // Child view reverse rotation
                viewArray[i].transform = viewArray[i].transform.rotated(by: -angle)
                // Judge whether the child view at the bottom of the implementation is larger
                let rect = viewArray[i].convert(viewArray[i].bounds, to: UIApplication.shared.keyWindow)
                let viewCenterX = rect.origin.x + (rect.width) / 2
                if viewCenterX > self.view.center.x - 20 && viewCenterX < self.view.center.x + 20 && rect.origin.y > contentView.center.y {
                    if viewArray[i].tag == 0{
                        viewArray[i].transform = viewArray[i].transform.scaledBy(x: 1.5, y: 1.5)
                        viewArray[i].tag = 1
                        contentView.bringSubview(toFront: viewArray[i])
                    }
                }
                else {
                    if viewArray[i].tag == 1 {
                        viewArray[i].transform = viewArray[i].transform.scaledBy(x: 1/1.5, y: 1/1.5)
                        viewArray[i].tag = 0
                        contentView.sendSubview(toBack: viewArray[i])
                    }
                }
            }
            beginPoint = currentPoint
        }
    }

4. Interactive optimization

     ///Get the finger touch position, beyond the range, do not allow rotation interaction
    private func touchPointInsideCircle(center: CGPoint, radius: CGFloat, targetPoint: CGPoint) -> Bool{
        let dist = DIST(pointA: targetPoint, pointB: center)
        return (dist <= radius)
    }

    func DIST(pointA: CGPoint, pointB: CGPoint) -> CGFloat{
        let x = (pointA.x - pointB.x) * (pointA.x - pointB.x)
        let y = (pointA.y - pointB.y) * (pointA.y - pointB.y)
        return CGFloat(sqrtf(Float(x + y)))
   }

demo address: CircleView

Using pop framework to achieve, long press the center button, circle the sub View rotation effect items: Swift. Rotation animation + Pop frame

If you have any questions, welcome to discuss

Keywords: Mobile Swift

Added by saeeddeep on Thu, 12 Dec 2019 21:45:07 +0200