안녕하세요 😄😄
이번에도 PilGwonKim님의 예제를 참조해서 만든 내용이에요!!
RxSwift에 대한 예제가 찾아보니까 많이 없더라구요
이 분의 글을 보면서 조금씩 공부해가고 있어요
PilGwonKim님은 chameleon라이브러리를 사용해서 만들었는데 좀예전 게시물이라서
Swift3.0버전으로 만들어졌고 그라이브러리도 3버전만 지원하더라구요
그래도 이라이브러리르 사용하겠다하시면 사용하셔도되요!!
저는 색바꾸는 작업을 직접 해보려고해요
아 우선 기능을 설명 안드렸네요!!
간단한 예제로 짧막하게 연습하기때문에 제목에 보이는게 다에요
기능
▶원생성
▶원위치에 따른 뷰의 색지정
딱 2가지에요
디자인을 먼저 해볼게요~
func setUp() {
// 원 모양의 뷰를 그립니다
circleView = UIView(frame: CGRect(origin: view.center, size: CGSize(width: 100.0, height: 100.0)))
circleView.layer.cornerRadius = circleView.frame.width / 2.0
circleView.center = view.center
circleView.backgroundColor = .green
view.addSubview(circleView)
//제스쳐 달아주기
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(circleMove(_:)))
circleView.addGestureRecognizer(gestureRecognizer)
}
@objc func circleMove(_ recognizer: UIPanGestureRecognizer){
let location = recognizer.location(in: view)
UIView.animate(withDuration: TimeInterval(0.1)) {
self.circleView.center = location
}
}
이렇게하면
가운데에 원이 생성되고
원을 클릭하면 이동시킬 수 있어요
circleView.rx.observe(CGPoint.self, "center")
.filter{ $0 != nil}
.map{ $0! }
.bind(to: circleViewModel.centerObservable)
.disposed(by: disposebag)
/* 아래 RxOptional 이용 */
circleView.rx.observe(CGPoint.self, "center")
.filterNil()
.bind(to: circleViewModel.centerObservable)
.disposed(by: disposebag)
버전이 많이 달라져서 사용법이 달라졌나봐요
보면서 공부하는데 많이 막히네요...
이 에러에서 많이 헤맷어요...ㅠㅠ
이유는!!
그냥 bind를 할경우 이러한 오류가 뜨는데 옵셔널을 체크하지않아서에요!
여러가지 방법이 있는데
filter{ $0 != nil }.map{ $0! }
이랑
RxOptional이란 라이브러리를 pod install해서 쓰는방법이 대표적인거 같아요
다음으로 원뷰모델에 색을 지정해줄거에요
좌표값이 변경되면 색이 변하는 방식이에요
//뷰모델의 새로운 색을 얻기위해 backgroundColorObservable구독
circleViewModel.backgroundColorObservable
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] background in
UIView.animate(withDuration: TimeInterval(0.1)) {
self?.circleView.backgroundColor = background
let r = background.components.red
let g = background.components.green
let b = background.components.blue
//원이보일수 있도록 다른 색으로 바꾸기
let viewBackground: UIColor = UIColor.init(red: 1-r.truncatingRemainder(dividingBy: 0.4), green: 1-g.truncatingRemainder(dividingBy: 0.4), blue: 1-b.truncatingRemainder(dividingBy: 0.4), alpha: 1.0)
//원과 배경색이다를때 변경
if background != viewBackground {
self?.view.backgroundColor = viewBackground
}
}
})
.disposed(by: disposebag)
우선 바로 위의코드처럼 따라하면 오류가 날거에요
왜냐하면!!
이제부터 설명합니다!!
저는 여기서 정말 많이삽질했어요 UIColor조작하는게...
라이브러리를 안쓰고 제공되는 컬러로 조작하려니까 안되더라구요...
rgb값을 뽑아내려고 CIColor를 썻는데
NSInvalidArgumentException', reason: '*** -CIColor not defined for the UIColor UIExtendedSRGBColorSpace
이러한 에러를 마주쳤어요 이거때문에 또 헤맷죠 ㅎㅎ
해결방법으로는
extension UIColor {
var coreImageColor: CIColor {
return CIColor(color: self)
}
//UIColor에서 rgb값 뽑아내기
var components: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
let color = coreImageColor
return (color.red, color.green, color.blue, color.alpha)
}
}
UIColor를 확장해서
rgb값을 뽑아오는 방식으로 가져와서 적용하면 너무너무 잘작동해요
코드가 뒤죽박죽이네요... 헷갈리니까 전체코드한번 볼게요!
전체코드
뷰모델.swift
class CircleViewModel {
var centerObservable: BehaviorSubject<CGPoint> = BehaviorSubject(value: CGPoint(x: 0.0, y: 0.0))
var backgroundColorObservable: BehaviorSubject<UIColor> = BehaviorSubject(value: UIColor.black)
var disposeBag = DisposeBag()
init() {
self.setup()
}
func setup() {
centerObservable.map(pointToColor)
.bind(to: backgroundColorObservable)
.disposed(by: disposeBag)
}
func pointToColor(_ center: CGPoint) -> UIColor{
var r: CGFloat = ((center.x + center.y).truncatingRemainder(dividingBy: 255) / 255.0)
let g: CGFloat = 0.1
let b: CGFloat = 0.1
let rs = String(format: "%.1f", r)
r = stringToCgFloat(rs)
return UIColor.init(red: r, green: g, blue: b, alpha: 1.0)
}
func stringToCgFloat(_ s: String) -> CGFloat {
let float = Float(s)!
return CGFloat(float)
}
}
뷰컨트롤러.swift
import UIKit
import RxSwift
import RxCocoa
import RxOptional
class ViewController: UIViewController {
var circleView: UIView!
var disposebag = DisposeBag()
let circleViewModel = CircleViewModel()
override func viewDidLoad() {
super.viewDidLoad()
setup()
}
func setup() {
// 원 모양의 뷰를 그립니다
circleView = UIView(frame: CGRect(origin: view.center, size: CGSize(width: 100.0, height: 100.0)))
circleView.layer.cornerRadius = circleView.frame.width / 2.0
circleView.center = view.center
circleView.backgroundColor = .green
view.addSubview(circleView)
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(circleMove(_:)))
circleView.addGestureRecognizer(gestureRecognizer)
circleView.rx.observe(CGPoint.self, "center")
.filterNil()
.bind(to: circleViewModel.centerObservable)
.disposed(by: disposebag)
//뷰모델의 새로운 색을 얻기위해 backgroundColorObservable구독
circleViewModel.backgroundColorObservable
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] background in
UIView.animate(withDuration: TimeInterval(0.1)) {
self?.circleView.backgroundColor = background
let r = background.components.red
let g = background.components.green
let b = background.components.blue
// 원이보일수 있도록 다른 색으로 바꾸기
let viewBackground: UIColor = UIColor.init(red: 1-r.truncatingRemainder(dividingBy: 0.4), green: 1-g.truncatingRemainder(dividingBy: 0.4), blue: 1-b.truncatingRemainder(dividingBy: 0.4), alpha: 1.0)
// 원과 배경색이다를때 변경
if background != viewBackground {
self?.view.backgroundColor = viewBackground
}
}
})
.disposed(by: disposebag)
}
@objc func circleMove(_ recognizer: UIPanGestureRecognizer){
let location = recognizer.location(in: view)
UIView.animate(withDuration: TimeInterval(0.1)) {
self.circleView.center = location
}
}
}
extension UIColor {
var coreImageColor: CIColor {
return CIColor(color: self)
}
//UIColor에서 rgb값 뽑아내기
var components: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
let color = coreImageColor
return (color.red, color.green, color.blue, color.alpha)
}
}
이제 끝이에요!!
원을 이렇게 움직일때마다 실시간으로 색이 변하는걸 볼 수 있어요!!
정말 많이 헤맨만큼 뭔가 개운하네요 ㅎㅎ
개념정리
이런 느낌이다~ 정도의 정리에요!! 확실치않아요..!
우선 제가 경험한 그대로에요
▶bind - (map 이나 filter등으로 분류될 수 도있어요)데이터들을 변수에 넘기는 역할
▶observeOn - 스레드같은개념! 디자인을 건드릴때는 MainScheduler를 가져오기
▶subscribe - 구독하던 값이 변하면 그 값으로 실행되는 부분
▶filterNil - filter.map을 한번에해주는 간편한 녀석
▶BehaviorSubject - 디폴트값을 정할 수 있고, 최근의 값이 저장 될 수 있는 타입
'iyOmSd > Title: RxSwift' 카테고리의 다른 글
[RxSwift] TableView 구현하기 (0) | 2020.06.05 |
---|---|
[RxSwift] Combine Operator정리 - CombineLatest, Merge, Zip (0) | 2020.05.30 |
[RxSwift] RxDataSources을 이용한 TableView구현하기 (0) | 2020.01.21 |
[RxSwift 기초] 검색창 결과 바로보기 - 예제로 RxSwift익히기 (0) | 2019.08.06 |
[RxSwift 기초] 로그인창을 입력에 따른 반응으로 구현하기 (0) | 2019.08.04 |