Skip to content

Latest commit

 

History

History
213 lines (159 loc) · 9.36 KB

18차 스터디.md

File metadata and controls

213 lines (159 loc) · 9.36 KB

CollectionView를 활용한 카드뷰 효과_xib로 셀 커스텀하기-pagingViewContorller사용기


  • CollectionView의 FlowLayout과 ScrollView를 활용해 애니메이션 및 효과주기
  • FlowLayOut과 Cell을 커스텀하는데, FlowLayOut의 Cell영역 Estimate Size를 꼭 None으로 해야 정상적으로 셀과 컬렉션뷰가 보여짐 (이 부분때문에 맞게 코딩해놓고도 제대로 셀이나 컬렉션뷰가 보여지지 않는경우가 많다!! 매우중요!!)

  viewDidLoad(){
        let cellWidth = CGFloat(324)
        let cellHeight = CGFloat(554)

        // 상하, 좌우 inset value 설정
        let insetX = (pagingCollectionView.bounds.width - cellWidth) / 2.0
        let insetY = (pagingCollectionView.bounds.height - cellHeight) / 2.0

        let layout = pagingCollectionView.collectionViewLayout as! UICollectionViewFlowLayout
        layout.itemSize = CGSize(width: cellWidth, height: cellHeight)
        layout.minimumLineSpacing = 15
        layout.scrollDirection = .horizontal
        pagingCollectionView.contentInset = UIEdgeInsets(top: insetY, left: insetX, bottom: insetY, right: insetX)

        pagingCollectionView.delegate = self
        pagingCollectionView.dataSource = self

        // 스크롤 시 빠르게 감속 되도록 설정
        pagingCollectionView.decelerationRate = UIScrollView.DecelerationRate.fast
  }
  • 커스텀할 셀의 크기를 설정해주고
  • 상하좌우 인셋을 설정해 뷰가 가옴데에 맞게, 또한 옆과 오른쪽 셀의 Spacing (간격) 설정
  • 스크롤 방향은 가로이므로 .horizontal
  • decelerationRate의 Rate.fast를 설정해 감속이 빠르게 되도록(스크롤이 자연스럽고 빠르게) 설정

extension ViewController : UIScrollViewDelegate
{
    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)
    {
        // item의 사이즈와 item 간의 간격 사이즈를 구해서 하나의 item 크기로 설정.
        let layout = self.pagingCollectionView.collectionViewLayout as! UICollectionViewFlowLayout
        let cellWidthIncludingSpacing = layout.itemSize.width + layout.minimumLineSpacing
        
        // targetContentOff을 이용하여 x좌표가 얼마나 이동했는지 확인
        // 이동한 x좌표 값과 item의 크기를 비교하여 몇 페이징이 될 것인지 값 설정
        var offset = targetContentOffset.pointee
        let index = (offset.x + scrollView.contentInset.left) / cellWidthIncludingSpacing
        var roundedIndex = round(index)
        
        // scrollView, targetContentOffset의 좌표 값으로 스크롤 방향을 알 수 있다.
        // index를 반올림하여 사용하면 item의 절반 사이즈만큼 스크롤을 해야 페이징이 된다.
        // 스크롤 방향을 체크하여 올림,내림을 사용하면 좀 더 자연스러운 페이징 효과를 낼 수 있다.
        if scrollView.contentOffset.x > targetContentOffset.pointee.x {
            roundedIndex = floor(index)
        } else {
            roundedIndex = ceil(index)
        }
        
        // 위 코드를 통해 페이징 될 좌표값을 targetContentOffset에 대입하면 된다.
        offset = CGPoint(x: roundedIndex * cellWidthIncludingSpacing - scrollView.contentInset.left, y: -scrollView.contentInset.top)
        targetContentOffset.pointee = offset
    }
}
  • item(cell)의 사이즈 간겨과 item의 간격을 포함해 하나의 크기로 설정
  • item의 x좌표를 targetContentOffset을 이용해 x좌표를 계산 후
  • 절반사이즈를 계산해 item의 절반사이즈일때 스크롤 효과를 준다, 이때 올림 내림 연산을 이용해 연산을 자연스럽게 해주면 사용자의 페이징 효과도 자연스러워 진다.

CellCustom

  • 당연히 기본 셀을 사용할일은 거의 없으므로, xib를 이용해서 커스텀
class CollectionViewCell: UICollectionViewCell{
    
    @IBOutlet weak var ddayLabel: UILabel!
    @IBOutlet weak var testButton: UIButton!
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        
        // cell rounded section
        self.layer.cornerRadius = 15.0
        self.layer.borderWidth = 0.5
        self.layer.borderColor = UIColor.lightGray.cgColor
        
       
       
        self.layer.masksToBounds = true
        
        //cell의 그림자와 반경 크기 높이등을 줘서 원하는 만큼의 자연스러운 그림자 효과를준다
      //시각적으로도 좋고 훨씬 카드가 자연스러워짐 + 디자이너의 요구대로
        self.layer.cornerRadius = 3.0
        layer.shadowRadius = 1
        layer.shadowOpacity = 0.15
        layer.shadowOffset = CGSize(width: 1.5, height: 3)
        self.clipsToBounds = false
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        setup()
    }
    func setup() {
        let view = loadViewFromNib()
        view.frame = bounds
        addSubview(view)
    }
    func loadViewFromNib() -> UIView {
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: "CustomCell", bundle: bundle)
        let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
       
        return view
    }
}
  • 셀에 관련된 그림자나, cornerRadius 등의 값은 뷰컨트롤러의 cell부분에서도 처리할 수 있지만 이왕이면 셀의 Class안에서 override func layoutSubviews( )을 이용해서 Cell에 관련된 부분의 초기설정을 해주는 것이 좋다. 보기에도 편하지만 이 셀의 초기화되는 xib부분에서의 처리가 logic상에서도 더 맞고, 관련 부분을 찾을때 프로젝트가 커지면 더욱이 찾기 어렵기에 해당셀에 관련된 내용은 해당 클래스에 맞도록 코딩!
  • loadViewFromNib( ) -> UIView 함수를 만들어 편리하고 유기적으로 nib파일을 붙일수 있도록 코딩

import UIKit

extension CALayer {
    func addBorder(_ arr_edge: [UIRectEdge], color: UIColor, width: CGFloat) {
        for edge in arr_edge {
            let border = CALayer()
            switch edge {
            case UIRectEdge.top:
                border.frame = CGRect.init(x: 0, y: 0, width: frame.width, height: width)
                break
            case UIRectEdge.bottom:
                border.frame = CGRect.init(x: 0, y: frame.height - width, width: frame.width, height: width)
                break
            case UIRectEdge.left:
                border.frame = CGRect.init(x: 0, y: 0, width: width, height: frame.height)
                break
            case UIRectEdge.right:
                border.frame = CGRect.init(x: frame.width - width, y: 0, width: width, height: frame.height)
                break
            default:
                break
            }
            border.backgroundColor = color.cgColor;
            self.addSublayer(border)
        }
    }
}
  • 뷰작업을 하다보면 특정 부분에만 경계선을 줄때가 많은데, 해당 extension을 이용하면 더욱 편리(google검색으로 찾긴하였으나 해당 fram에 어떻게 부분적으로 줄 수 있는지에 대한 이해를 코드를 보며 쉽게 할 수 있었음)

아쉬워서 잠깐적는 PageViewController사용기

class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
    
    
    let pageControl = UIPageControl()
    
    lazy var VCArray:[UIViewController] = {
        return [self.VCInstance(name: "FirstVC"),
                self.VCInstance(name: "SecondVC"),
                self.VCInstance(name: "ThirdVC")]
    }()
    private func VCInstance(name: String)->UIViewController{
        return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: name)
    }
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.dataSource = self
        self.delegate = self
        
 
      
        
        if let firstVC = VCArray.first{
            setViewControllers([firstVC], direction: .forward, animated: true, completion: nil)
        }
        configureMyPageControl()
        
    }
  • View커스텀시 처음시도는 페이지뷰컨트로를 이용했으나 뷰컨과 뷰컨이 아이템 처럼 양옆으로 보여지게 처리하는 것이 힘들어서 컬렉션뷰를 사용
  • 그러나 페이지뷰 효과와 덜 복잡한 간단한 사진이 넘어가는 뷰등을 만들때에는 훨씬 간단하고 직관적으로 코딩이 가능하다.
  • 필요한 뷰컨만큼 기능을 할당해주고, identifier를 이용해 뷰컨들을 초기화 후 페이징컨트롤러에 맞게 초기화 해준다.
  • 간단하게 paging효과와 paginControl을 붙여서 보여줄 수 있다.
  • pagingViewController도 아이템의 간격을 설정할 수 있는 변수가 존재하지만, 0이상으로는 설정가능하나 -값은 설정이 안됨, 그래서 이부분을 더 찾고 공부해봐야함. 하지만 여러 커스텀이 들어갈시에는 컬렉션뷰를 이용하는 것이 좋아보임
  • 보여줘야할 아이템의 갯수가 한정적이고 꽉찬 화면의 View가 페이징된다면 사용해도 무방하고 절대적으로 성능이 약하거나 기능이 부족하지 않음, 스크롤 하는 방향대로 종이질감 처럼 넘어가는 효과도 기본적으로 탑재(Page curl)