본문 바로가기

iOS 개발/번역기 앱(RxSwift)

번역기 앱 - 10. 번역 결과 View

반응형

안녕하세요. Skillist입니다

 

2월 1일 공부는 끝내려고 했는데,

빨리 끝내고 다른 프로젝트 하는게 좋을것 같아, 글 한개 더 작성합니다.

 

번역 결과를 보여주는 View를 구현할거에요.

 

———————————————————————————————————————————————————

 

ViewModel 부터 살펴보죠

 

15라인 : 언어가 변경됐을때 활용하는 Relay입니다.

16라인 : 복사 버튼을 탭했을때의 Relay입니다.

17라인 : 보관(북마크) 버튼을 탭했을때의 Relay입니다.

18라인 : 번역된 Text에 대한 Relay입니다.

19라인 : 해당 View의 isHidden에 대한 Relay입니다.

 

24라인 : 버튼 탭 이벤트를 받으면, 번역된 text를 클립보드에 복사합니다.

 

———————————————————————————————————————————————————

 

이번엔 View를 볼게요.

역시 bind는 마지막에 알아보도록 하겠습니다.

 

Label과 복사버튼, 보관(북마크)버튼, 번역결과 Label입니다.

 

104라인 : View에 대한 기본 설정입니다.

108라인 : 번역 결과 View의 isHidden은 true가 기본 값입니다.

111~148라인 : 스냅킷으로 레이아웃 제약사항을 구성합니다.

 

bind입니다.

59라인 : viewModel의 selectedLanguage의 title를 언어 Label에 바인드 합니다.

66라인 : viewModel의 TranslatedText의 이벤트가 방출하면(번역이 성공하면), 번역 Label에 바인딩하고, 70라인을 통해, 레이아웃을 업데이트 합니다. 또, isHidden에 대한 이벤트를 전달합니다.

75라인 : 복사 버튼을 터치하면, 번역된 text를 복사합니다.

79라인 : 보관(북마크) 버튼을 터치하면, viewModel에 바인드 합니다.

83라인 : viewModel의 isHiddenView를 통해, view의 hidden을 설정합니다.

 

설명을 너무 간략하게 한것 같은데, 이해되세요???

viewModel과 view를 나란히 놓고, 흐름을 봐야지 이해가 쉬울거에요

 

———————————————————————————————————————————————————

 

방금 글을 작성하며, 코드를 다시 보는 와중에,

불필요한 코드도 발견하고, 좀 더 최적화를 할 수 있었습니다.

셀프 코드리뷰라고 할까요?

또, 머릿속에 얽혀있던 부분들이 점점 정리되고 있습니다.

그럼 2월 1일 글 작성은 정말 끝났습니다.

고생하셨어요~

 

잘못되거나 부족한 내용 등, 피드백 감사합니다!

 

https://github.com/DeveloperSkillist/TranstorKing

 

GitHub - DeveloperSkillist/TranstorKing

Contribute to DeveloperSkillist/TranstorKing development by creating an account on GitHub.

github.com

 

 

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓  전체 코드  ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

import RxCocoa
import RxSwift

struct TranslatedTextOutputViewModel {
    let disposeBag = DisposeBag()
    
    //view -> viewModel
    let selectedLanguage = PublishRelay<Language>()
    let copyButtonTap = PublishRelay<Void>()
    let bookmarkButtonTap = PublishRelay<Void>()
    let translatedText = PublishRelay<String>()
    let isHiddenView = PublishRelay<Bool>()
    
    //viewModel -> view
    
    init() {
        copyButtonTap
            .withLatestFrom(translatedText) { $1 }
            .bind(onNext: {
                UIPasteboard.general.string = $0
            })
            .disposed(by: disposeBag)
    }
}
import UIKit
import SnapKit
import RxCocoa
import RxSwift

class TranslatedTextOutputView: UIView {
    let disposeBag = DisposeBag()
    
    private lazy var languageLabel: UILabel = {
        let label = UILabel()
        label.font = .systemFont(ofSize: 17, weight: .bold)
        label.textColor = .systemGray
        label.text = Language.en.title
        label.numberOfLines = 0
        return label
    }()
    
    private lazy var copyButton: UIButton = {
        let button = UIButton()
        button.setImage(UIImage(systemName: "doc.on.doc"), for: .normal)
        button.tintColor = .systemGray
        return button
    }()
    
    private lazy var bookmarkButton: UIButton = {
        let button = UIButton()
        button.setImage(UIImage(systemName: "square.and.arrow.down"), for: .normal)
        button.tintColor = .systemGray
        return button
    }()
    
    private lazy var translatedLabel: UILabel = {
        let label = UILabel()
        label.backgroundColor = .systemBackground
        label.font = .systemFont(ofSize: 20)
        label.numberOfLines = 0
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: .zero)
        
        attribute()
        layout()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func bind(_ viewModel: TranslatedTextOutputViewModel) {
        viewModel.selectedLanguage
            .map {
                $0.title
            }
            .bind(to: languageLabel.rx.text)
            .disposed(by: disposeBag)
        
        viewModel.translatedText
            .bind(onNext: { [weak self] text in
                self?.translatedLabel.rx.text
                    .onNext(text)
                self?.translatedLabel.setNeedsLayout()
                viewModel.isHiddenView.accept(text.isEmpty)
            })
            .disposed(by: disposeBag)
        
        copyButton.rx.tap
            .bind(to: viewModel.copyButtonTap)
            .disposed(by: disposeBag)
        
        bookmarkButton.rx.tap
            .bind(to: viewModel.bookmarkButtonTap)
            .disposed(by: disposeBag)
        
        viewModel.isHiddenView
            .bind(to: self.rx.isHidden)
            .disposed(by: disposeBag)
    }
    
    private func attribute() {
        self.backgroundColor = .systemBackground
        self.layer.cornerRadius = 10
        self.clipsToBounds = true
        self.isHidden = true
    }
    
    private func layout() {
        
        self.clipsToBounds = true
        
        [
            languageLabel,
            bookmarkButton,
            copyButton,
            translatedLabel
        ].forEach {
            self.addSubview($0)
        }
        
        languageLabel.snp.makeConstraints {
            $0.top.equalToSuperview().inset(16)
            $0.leading.equalToSuperview().inset(20)
        }
        
        bookmarkButton.snp.makeConstraints {
            $0.top.bottom.equalTo(languageLabel)
            $0.trailing.equalToSuperview().inset(16)
            $0.width.height.equalTo(languageLabel.snp.height)
        }
        
        copyButton.snp.makeConstraints {
            $0.top.bottom.equalTo(languageLabel)
            $0.trailing.equalTo(bookmarkButton.snp.leading).offset(-8)
            $0.width.height.equalTo(languageLabel.snp.height)
        }
        
        translatedLabel.snp.makeConstraints {
            $0.top.equalTo(languageLabel.snp.bottom).offset(8)
//            $0.leading.equalToSuperview().inset(20)
            $0.leading.equalTo(languageLabel)
            $0.trailing.equalTo(bookmarkButton)
            $0.bottom.equalToSuperview().inset(16)
        }
    }
}
반응형