• Margin to StackView
  • UIPanGestureRecognizer
  • CGAffineTransform
  • translatedBy

remove some warnings : https://stackoverflow.com/questions/52410471/unable-to-look-up-screen-scale-and-unexpected-physical-screen-orientation-in-xco/53024525

CardView

CardView cocoa touch class를 만들어준다. subclass of UIView

blueView는 cardsDeckView로 이름을 바꿔주고 이제 cardsDeckView안에 여러 cardView를 넣을 것이므로

setupDummyCards()라는 함수를 viewDidLoad에서 호출하여 해당 함수에서 CardView 객체들을 생성하고 관리

ViewController.swift

fileprivate func setupDummyCards() {
        print("Setting up dummy cards")
        let cardView = CardView(frame: .zero)
        cardsDeckView.addSubview(cardView)
        cardView.fillSuperview()
    }

CardView.swift

fileprivate let imageView = UIImageView(image: #imageLiteral(resourceName: "lady5c"))
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        // custom drawing code
        backgroundColor = .red
        
        addSubview(imageView)
        imageView.fillSuperview()
    }

이제 패딩or마진을 주고 싶은데, CardView에 줘도 CardView는 cardsDeckView에 subclass이기 때문에 상위 클래스에 마진 또는 패딩을 주자라고 생각했는데

왜 overallStackView에 마진을 줘야하지?

isLayoutMarginsRelativeArrangement

A Boolean value that determines whether the stack view lays out its arranged views relative to its layout margins.

일단 사용한 property는 StackView 에서만 사용가능하다.

// 사진넣기

ViewController.swift

		overallStackView.isLayoutMarginsRelativeArrangement = true
        overallStackView.layoutMargins = .init(top: 0, left: 12, bottom: 0, right: 12)

이렇게 stackView에 margin을 줄 수 있다.

CardView.swift > init

		layer.cornerRadius = 20
        clipsToBounds = true

cornerRadius는 항상 layer먼저 접근해줘야한다.

그리고 항상 clipsToBounds는 필수!

이렇게 설정을 하면 이전 cardsDeckView의 backgroundColor가 보일 것이다. 이 view의 backgroundcolor만 없애주면 끝

UIPanGestureRecognizer

override init(frame: CGRect) {
        ...
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
        addGestureRecognizer(panGesture)
    }
    
    @objc fileprivate func handlePan(gesture: UIPanGestureRecognizer) {
        print("Panning image")
    }

addGestureRecognizer로 추가

	let translation = gesture.translation(in: nil)
	print(translation.x)

handlePan()에서 접근하기 위해 self 사용

@objc fileprivate func handlePan(gesture: UIPanGestureRecognizer) {
        switch gesture.state {
        case .changed:
            let translation = gesture.translation(in: nil)
            self.transform = CGAffineTransform(translationX: translation.x, y: translation.y)
        case .ended:
            UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
                self.transform = .identity
            }) { (_) in
                
            }
        default:
            ()
        }
    }
@objc fileprivate func handlePan(gesture: UIPanGestureRecognizer) {
        switch gesture.state {
        case .changed:
            handleChanged(gesture)
        case .ended:
            handleEnded()
        default:
            ()
        }
    }
    
    fileprivate func handleChanged(_ gesture: UIPanGestureRecognizer) {
        let translation = gesture.translation(in: nil)
        self.transform = CGAffineTransform(translationX: translation.x, y: translation.y)
    }
    
    fileprivate func handleEnded() {
        UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
            self.transform = .identity
        }) { (_) in
            
        }
    }

Refactoring

UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.1, options: .curveEaseOut, animations: {
            self.transform = .identity
        }) { (_) in
            
        }

usingSpringWithDamping 인자와 initialSpringVelocity 인자 값을 변경해주면 조금 더 애니메이션 효과가 적용되는 것을 확인할 수 있다.

ViewController.swift

        overallStackView.bringSubviewToFront(cardsDeckView)

Rotation

fileprivate func handleChanged(_ gesture: UIPanGestureRecognizer) {
        // rotation
        // some not that scary math here to convert radians to degree
        let degrees: CGFloat = 15
        let angles = degrees * .pi / 180
        let rotationTransformation = CGAffineTransform(rotationAngle: angles)
        self.transform = rotationTransformation
    }

15도 돌아가는 함수

transform에 관련된 것은 CGAffineTransform()

CGAffineTransform

An affine transformation matrix for use in drawing 2D graphics.

		let translation = gesture.translation(in: nil)
        // rotation
        // some not that scary math here to convert radians to degree
        let degrees: CGFloat = translation.x / 20

degrees 위에 translation을 선언해주고 translation.x 만큼 회전시켜준다.

		self.transform = rotationTransformation.translatedBy(x: translation.x, y: translation.y)

rotationTransformation에 translatedBy() 호출하여 마지막에 이동시켜주면 된다.

translatedBy(x:y:)

Returns an affine transformation matrix constructed by translating an existing affine transform.

fileprivate func handleEnded() {
        let shouldDismissCard = true
        
        UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.1, options: .curveEaseOut, animations: {
            if shouldDismissCard {
                
                let offScreenTransform = self.transform.translatedBy(x: 1000, y: 0)
                self.transform = offScreenTransform
            } else {
                self.transform = .identity
            }
        }) { (_) in
            print("Completed animation, let's bring our card back")
            self.transform = .identity
        }
    }

shouldDismissCard

offScreenTransform을 이용하여 Dismiss시키면 어색하다.

self.frame = CGRect(x: 1000, y: 0, width: self.frame.width, height: self.frame.height)
(_) in
            print("Completed animation, let's bring our card back")
            self.transform = .identity
            self.frame = CGRect(x: 0, y: 0, width: self.superview!.frame.width, height: self.superview!.frame.height)
        }

identity

The identity transform:A 3 by 3 identity matrix.

self.superview!를 통하여 cardView에 접근 그냥 self를 하면 uiimageV

			print(self)
            print(self.superview!)
<Tinder.CardView: 0x7fd2ce0165c0; frame = (894.077 -5.68434e-14; 671.177 615.268); transform = [0.97778323675860612, 0.20961856290382183, -0.20961856290382183, 0.97778323675860612, 239.34858461333238, 38.016510144863005]; clipsToBounds = YES; gestureRecognizers = <NSArray: 0x600000b1c9c0>; layer = <CALayer: 0x600000506a00>>

<UIView: 0x7fd2cb607d30; frame = (12 80; 351 554); layer = <CALayer: 0x60000050fae0>>

이 코드에 너무 집착안해도 된다~ 나중에 안쓸거야

		let threshold: CGFloat = 120
        let shouldDismissCard = gesture.translation(in: nil).x > threshold

여기서 gesture를 사용하기 위해 handleEnded에 gesture인자를 추가 인자명 앞에 _를 추가하면 인자명을 언급하지 않아도 된다.

threshold

3.(그 점을 넘기면 무언가가 생기는) 기준점, 역치(閾値); 〔심리학·생리〕 역(閾)(limen)

▸ the threshold of consciousness식역(의식 작용의 발생과 소멸의 경계)

▸ have a high[a low] threshold of pain고통에 대한 허용 한계치가 높다[낮다].

	// Configurations
    fileprivate let threshold: CGFloat = 80

나중에 threshold 같은 값들은 빠르게 수정할 수 있도록 맨 위로 빼놓는다. configurations로 주석을 달아놓고 체크한다.

태그:

카테고리:

업데이트:

댓글남기기