iOS_System View & Control

longlivedrgn·2022년 9월 27일
0

iOS 스터디

목록 보기
1/8
post-thumbnail

UIControl & Target-Action

IBAction으로 연결할 경우

  • Action을 설정시, Argument는 총 세개를 선택할 수 있다.
	// sender로 선택할 경우
    @IBAction func test1(_ sender: Any) {
    }
    // None으로 선택할 경우	
    @IBAction func test2() {
    }
    // Sender and Event로 설정할 경우
    @IBAction func test3(_ sender: Any, forEvent event: UIEvent) {
    }
    
    @IBAction func sliderChanged(_ sender: Any) {
    }

코드로 연결하기

  • 먼저 objc로 함수를 생성해준다.
    @objc func action(_ sender: Any){
        print(#function)
    }
  • 그리고 addTarget해줘서 action 추가해주기
    override func viewDidLoad() {
        super.viewDidLoad()
        // Method를 selector로 변경해주기
        let sel = #selector(action(_:))
        btn.addTarget(self, action: sel, for: .touchUpInside)
    }
}

action_: 가 뭔가??

Text Button

  • button의 state를 변경해보기
    @IBAction func report(_ sender: UIButton) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
            self.stateLabel.text = sender.state.debugString
        }
    }
    
    @IBAction func stateChanged(_ sender: UISegmentedControl) {
        switch sender.selectedSegmentIndex{
        case 0:
            btn.isEnabled = true
            btn.isSelected = false
            btn.isHighlighted = false
        case 1:
            btn.isHighlighted.toggle()
        case 2:
            btn.isSelected.toggle()
        case 3:
            btn.isEnabled = false
        default:
            break
        }
        report(btn)
    }

https://zeddios.tistory.com/513 - (DispatchQueue)

  • button의 Text 설정을 변경해보기
class TextButtonViewController: UIViewController {
    
    @IBOutlet weak var btn: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //btn은 text와 textcolor를 아래와 같이 변경할 수 없다.
//        btn.titleLabel?.text = "Hello"
//        btn.titleLabel?.textColor = .systemRed
        
        // for 아래는 state를 말하는 것이다.
        btn.setTitle("Hello", for: .normal)
        btn.setTitle("Haha", for: .highlighted)
        btn.setTitleColor(.systemRed, for: .normal)
        btn.titleLabel?.backgroundColor = .systemYellow
        
    }
}

Image Button

  • Image를 만들고 해당 Image를 button에 넣기
class ImageButtonViewController: UIViewController {
    
    @IBOutlet weak var btn: UIButton!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let normalImage = UIImage(named: "plus-normal")
        let highlightedImage = UIImage(named: "plus-highlighted")
        
        btn.setImage(normalImage, for: .normal)
        btn.setImage(highlightedImage, for: .highlighted)
        //btn.setBackgroundImage(<#T##image: UIImage?##UIImage?#>, for: <#T##UIControl.State#>)
    }
}

Picker View

  • Picker View를 생성해주고 아래와 같이 datasource와 delegate을 연결해 준다.

  • 그리고 아래와 같이 UIPickerViewDataSource 프로토콜을 만족해야된다.

extension TextPickerViewController: UIPickerViewDataSource{
// pickerview의 column은 몇개인가?
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
    }

// pickerview에는 몇개의 element가 들어가는가?
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    }
}
  • 아래와 같이 dataSource와 delegate을 설정해 줄 수 있다.
class TextPickerViewController: UIViewController {
    let devTools = ["Xcode", "Postman", "SourceTree", "Zeplin", "Android Studio", "SublimeText"]
    let fruits = ["Apple", "Orange", "Banana", "Kiwi", "Watermelon", "Peach", "Strawberry"]
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

extension TextPickerViewController: UIPickerViewDataSource{
    // 몇개의 componenet인가?(column)
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return devTools.count
    }
}

extension TextPickerViewController: UIPickerViewDelegate{
    // 어떤 글자를 나타낼 것인가? pickerview는 위에서부터 index 0이라고 한다.
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return devTools[row]
    }
    
     // 선택될 경우 함수가 실행이 된다.
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        print(devTools[row])
    }
}
  • 만약 numberOfComponents의 return 값을 2로하면 아래와 같아진다.

  • report Action을 설정하여 현재 지목하고 있는 pickerview의 값을 print한다.

    @IBAction func report(_ sender: Any) {
    // inComponent는 컬럼의 index이다. 즉 0이면 맨 왼쪽 column이다.
        let row = picker.selectedRow(inComponent: 0)
        guard row >= 0 else {
            print("not found")
            return
        }
        print(devTools[row])
    }

Image PickerView

  • PickerView의 datasource와 delegate을 설정해준다.

Datasource 설정해주기

class ImagePickerViewController: UIViewController {
    
    lazy var images: [UIImage] = {
        return (0...6).compactMap { UIImage(named: "slot-machine-\($0)") }
    }()
}

extension ImagePickerViewController: UIPickerViewDataSource{
    // 항목의 column을 몇개로 할 것인가?
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    // 한 컬럼에는 몇개의 component를 넣어줄 것인가? -> 반복해서 componenet를 보여주는 것이 가능
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return images.count * 3
    }
}

Delegate 설정하기

/////////// 이해가 잘 안됨 /////////////

// View를 재 사용하기!
extension ImagePickerViewController: UIPickerViewDelegate {
    func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        // 만약 마지막 Parameter가 imageview인지 확인하기
        if let imageView = view as? UIImageView{
            imageView.image = images[row % images.count]
            return imageView
        }
        // 재 사용할 imageview가 없다면 Imageview를 만들어서 사용하기
        let imageView = UIImageView()
        imageView.image = images[row % images.count]
        imageView.contentMode = .scaleAspectFit
        return imageView
    }
}

PickerView 높이 설정하기

    // pickerView에 설정된 높이
    func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
        return 60
    }

Shuffle Action 설정하기

  • Shuffle button을 누를 경우, pickerview가 random하게 설정되게 하기
@IBAction func shuffle(_ sender: Any?) {
        let firstIndex = Int.random(in: 0..<images.count) + images.count
        let secondIndex = Int.random(in: 0..<images.count) + images.count
        let thirdIndex = Int.random(in: 0..<images.count) + images.count

        // pickerView에 있는 특정 로우를 선택할 때는 selectRow를 사용한다.
        picker.selectRow(firstIndex, inComponent: 0, animated: true)
        picker.selectRow(secondIndex, inComponent: 1, animated: true)
        picker.selectRow(thirdIndex, inComponent: 2, animated: true)
    }
  • 처음 view가 나올 때, shuffle 설정하기
override func viewDidLoad() {
        super.viewDidLoad()
        
        // touchEvent를 비활성화 해주기
        picker.isUserInteractionEnabled = false
        picker.reloadAllComponents()
        shuffle(nil)
        
    }

PageControl

  • 먼저 scrollView를 datasource와 delegate으로 이어주기

  • 아래와 같이 pageControl을 설정해줄 수 있다. UI로 tint color와 current page를 설정해 줄 수 있다.

  • 아래와 같이 코드로 pagecontrol을 설정할 수 있다.

@IBOutlet weak var pager: UIPageControl!
@IBOutlet weak var listCollectionView: UICollectionView!
    
let list = [UIColor.red, UIColor.green, UIColor.blue, UIColor.gray, UIColor.black]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // pages를 List의 숫자로 설정하기
        pager.numberOfPages = list.count
        // 첫 화면의 page를 첫번째꺼로 설정하기
        pager.currentPage = 0
	    //pager의 색깔을 변경해주기
        pager.pageIndicatorTintColor = UIColor.systemGray3
        pager.currentPageIndicatorTintColor = UIColor.systemRed
        
    }
  • 근데 현재는 pagecontrol이 scroll이 되어도 변경이 되지 않는다.
  • 따라서 아래와 같은 code를 추가해준다.

https://sweethoneybee.tistory.com/49 -contentOffset

// page를 넘기면 pagecontrol도 넘어가게 하기
extension PageControlViewController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let width = scrollView.bounds.size.width
        let x = scrollView.contentOffset.x + (width / 2.0)
        
        let newPage = Int(x / width)
        if pager.currentPage != newPage {
            pager.currentPage = newPage
        }
    }
}

  • PageControl을 탭하면 다음 페이지로 넘어가게 하기

먼저 아래와 같이 action을 설정해준다.

  • 그리고 아래와 같이 코드를 작성해준다.
    // pageControl을 탭하는 순간 page가 한개씩 넘어가게 설정해보기
    @IBAction func pageChanged(_ sender: UIPageControl) {
        let indexPath = IndexPath(item: sender.currentPage, section: 0)
        listCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
    }

Slider

Simple Slider

  • 아래와 같이 outlet이 설정이되어있다.
lass SimpleSliderViewController: UIViewController {
    
    @IBOutlet weak var redSlider: UISlider!
    
    @IBOutlet weak var greenSlider: UISlider!
    
    @IBOutlet weak var blueSlider: UISlider!

  • slider의 값을 변경할 경우, 그 값을 저장하고, 그 값으로 background color를 설정해보기
// valueChange로 action을 설정하기
    @IBAction func sliderChanged(_ sender: Any) {
        // 슬라이더의 현재 값을 가져오기
        let r = CGFloat(redSlider.value)
        let g = CGFloat(greenSlider.value)
        let b = CGFloat(blueSlider.value)

        let color = UIColor(red: r, green: g, blue: b, alpha: 1.0)
        // view의 background를 위에 설정한 color로 설정하기
        view.backgroundColor = color
    }
  • 그리고 slider의 초기값을 설정해준다.
    override func viewDidLoad() {
        super.viewDidLoad()
        
        redSlider.value = 1.0
        greenSlider.value = 1.0
        blueSlider.value = 1.0
        
        redSlider.minimumValue = 0.0
        redSlider.maximumValue = 1.0
        
        
    }
}

CustomSlider

  • 아래와 같이 outlet이 설정이되어있다.
class CustomSliderViewController: UIViewController {
    @IBOutlet weak var slider: UISlider!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}
  • Image랑 track Tintcolor를 설정해보기
    override func viewDidLoad() {
        super.viewDidLoad()
        // slider를 커스텀 이미지로 설정해보기
        let img = UIImage(systemName: "lightbulb")
        slider.setThumbImage(img, for: .normal)
        
        // track의 tintcolor를 설정해보기
        slider.minimumTrackTintColor = UIColor.systemRed
        slider.maximumTrackTintColor = UIColor.black
        
    }
}
  • 위와 같이 설정을 하면 아래와 같이 slider가 구성이 된다.

NonContinuousSlider

  • 아래와 같이 outlet과 action(valueChanged)이 설정이 되어있다.
class NonContinuousSliderViewController: UIViewController {
    
    @IBOutlet weak var valueLabel1: UILabel!
    @IBOutlet weak var slider1: UISlider!
    
    @IBOutlet weak var valueLabel2: UILabel!
    @IBOutlet weak var slider2: UISlider!
    
    
    @IBAction func sliderChanged1(_ sender: UISlider) {
        valueLabel1.text = String(format: "%.1f", sender.value)
    }
    
    @IBAction func sliderChanged2(_ sender: UISlider) {
        valueLabel2.text = String(format: "%.1f", sender.value)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}
  • 아래와 같이 storyBoard가 구성되어있다.

Continuous Updates

  • Slider의 continuous update가 체크가 되어있다면, slider를 움직일 때마다 계속 값이 변경이 되지만, continuous update가 체크가 되어있지않다면, slier를 움직이다가 때야지 값이 변경이 된다.

Segmented Control

  • 아래와 같이 segmented control을 추가해주고, segments를 3으로 설정하면 3개의 segment가 생성이된다.

  • 그리고 아래와 같이 segments를 구성해준다.(title을 변경하기)

  • Label을 segmented Control을 통하여 alignment를 변경해보자

  • 아래와 같이 SegmentedControl을 outlet으로 추가하고, alignmentControl의 segement Index를 textAlignment의 rawvalue로 설정을 해준다.

    @IBOutlet weak var label: UILabel!

    @IBOutlet weak var alignmentControl: UISegmentedControl!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 초기 정렬을 초기 Label의 정렬에 맞추기
        alignmentControl.selectedSegmentIndex = label.textAlignment.rawValue
    }
}
  • 그리고 SegmentedControl을 누르면 segment에 맞게 align되게 하는 action을 추가해보자.
    // value Changed -> sender의 index로 rawValue를 받는다. 아니면 그냥 .center로
    @IBAction func alignmentChanged(_ sender: UISegmentedControl) {
        label.textAlignment = NSTextAlignment(rawValue: sender.selectedSegmentIndex) ?? .center
    }

Switch를 통하여 momentary를 설정하기

  • momentary가 설정이되면 영구적으로 값이 변하는 것이 아니라, 한시적으로만 값이 변하게 된다.

↓ ViewDidLoad에 아래의 코드를 추가한다.

        momentarySwitch.isOn = alignmentControl.isMomentary
  • 그리고 switch를 누르면 moementary 성질이 변하게 설정해보자
    @IBAction func toggleMomentary(_ sender: UISwitch) {
        alignmentControl.isMomentary = sender.isOn
        
    }

코드로 segmentedControl을 설정해보기

        alignmentControl.setTitle("왼쪽", forSegmentAt: 0)

SegmentedControl을 추가하는 코드 생성하기

  • 아래와 같이 Storyboard를 구성하고, Insert를 누르면 segment가 추가되고, remove를 누르면 segment가 삭제되게 설정해보자.

↓ 아래와 같이 insert action 코드를 추가하자.

    @IBAction func insertSegment(_ sender: Any) {
    // 먼저 title에 값이 들어갔는 지, guard를 통하여 확인하기
        guard let title = titleField.text, title.count > 0 else {
            return
        }
        
        segmentedControl.insertSegment(withTitle: title, at: segmentedControl.numberOfSegments, animated: true)
        titleField.text = nil
    }

↓ 아래와 같이 delete action 코드를 추가하자.

    @IBAction func removeSegment(_ sender: Any) {
    // for 문을 통하여 segment 한 개 한 개씩 확인하기.
        guard let title = titleField.text, title.count > 0 else {
            return
        }
        for index in 0..<segmentedControl.numberOfSegments {
            if let currentTitle = segmentedControl.titleForSegment(at: index), currentTitle == title {
                segmentedControl.removeSegment(at: index, animated: true)
            }
            break
        }
        titleField.text = nil
    }
  • segment 디자인하기
override func viewDidLoad() {
        super.viewDidLoad()
        
        let normalImage = UIImage(named: "segment_normal")
        let selectedImage = UIImage(named: "segment_selected")
        
        // segment의 background를 설정하기
        segmentedControl.setBackgroundImage(normalImage, for: .normal, barMetrics: .default)
        segmentedControl.setBackgroundImage(selectedImage, for: .selected, barMetrics: .default)
        
        
        var img = UIImage(named: "segment_normal_normal")
        print(img?.size)
        segmentedControl.setDividerImage(img, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
        
        let halfWidth = (img!.size.width - 20) / 3.0
        var offset = UIOffset(horizontal: halfWidth, vertical: 0.0)
        segmentedControl.setContentPositionAdjustment(offset, forSegmentType: .left, barMetrics: .default)
        
        img = UIImage(named: "segment_normal_selected")
        segmentedControl.setDividerImage(img, forLeftSegmentState: .normal, rightSegmentState: .selected, barMetrics: .default)
        
        img = UIImage(named: "segment_selected_normal")
        segmentedControl.setDividerImage(img, forLeftSegmentState: .selected, rightSegmentState: .normal, barMetrics: .default)
    }

Switch

  • Switch의 attribute을 아래와 같이 설정을 하면

  • 아래와 같이 switch의 UI가 변하게 된다.

  • 그리고 switch 위에 imageview는 아래와 같이 highlighted일 경우를 설정해주자.

  • 아래와 같이 switch를 누를 때에 highlight의 boolean값을 변경하고 싶으면 아래와 같이 action을 추가해준다.


    @IBOutlet weak var bulbImageView: UIImageView!
    
    @IBOutlet weak var testSwitch: UISwitch!
    
    // switch Action
    @IBAction func stateChanged(_ sender: UISwitch) {
        bulbImageView.isHighlighted = sender.isOn
    }
  • 초기값을 설정해준다.( Highlighted가 true일 때, isOn도 true일 수 있게)
    override func viewDidLoad() {
        super.viewDidLoad()
        
        testSwitch.isOn = bulbImageView.isHighlighted
        
    }
  • 토글을 이용해서 switch 이용하기
    @IBAction func toggle(_ sender: Any) {
        testSwitch.setOn(!testSwitch.isOn, animated: true)
        stateChanged(testSwitch)
    }

Stepper

  • 아래와 같이 storyboard를 구성하자

  • 아래와 같이 outlet을 설정해주자.

class StepperViewController: UIViewController {
    
    @IBOutlet weak var valueLabel: UILabel!
    @IBOutlet weak var valueStepper: UIStepper!
    @IBOutlet weak var autorepeatSwitch: UISwitch!
    @IBOutlet weak var continuousSwitch: UISwitch!
    @IBOutlet weak var wrapSwitch: UISwitch!
  • stepper값으로 valuelable 설정하기
    // stepper가 바뀌면 valuelabel의 text값이 해당값으로 바뀌게 설정하기
    @IBAction func valueChanged(_ sender: UIStepper) {
        valueLabel.text = "\(sender.value)"
    }
  • 다른 action 함수 설정하기
    // 사용자가 꾹 누르는 것을 허용을 할 것인가?
    @IBAction func toggleAutorepeat(_ sender: UISwitch) {
        valueStepper.autorepeat = sender.isOn
        
    }
    // 꾹 누르고 있으면 바로 올라가는게 아니라 touch event가 다 끝나고 결과값이 변하게 된다.
    @IBAction func toggleContinuous(_ sender: UISwitch) {
        valueStepper.isContinuous = sender.isOn
    }
    
    // true일 경우 최댓값을 도달 후 최솟값으로 바꿔준다.
    @IBAction func toggleWrap(_ sender: UISwitch) {
        valueStepper.wraps = sender.isOn
    }

    
    override func viewDidLoad() {
        super.viewDidLoad()
        autorepeatSwitch.isOn = valueStepper.autorepeat
        continuousSwitch.isOn = valueStepper.isContinuous
        wrapSwitch.isOn = valueStepper.wraps
    }
}

Activity Indicator View

  • Animating은 indicator가 움직이고, hides when stopped이면 animation이 멈추면 사라지는 것이다.

↓ 아래와 같이 outlet과 action이 설정이되어있다.

class ActivityIndicatorViewViewController: UIViewController {
    
    
    @IBOutlet weak var hiddenSwitch: UISwitch!
    
    @IBAction func toggleHidden(_ sender: UISwitch) {
        
    }
    
    @IBAction func start(_ sender: Any) {
        
    }
    
    @IBAction func stop(_ sender: Any) {
        
    }
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
    }
}
  • ActivityIndicatorView outlet을 추가해주자.
    @IBOutlet weak var loader: UIActivityIndicatorView!
  • 미리 추가한 action 코드를 완성시켜주자.
class ActivityIndicatorViewViewController: UIViewController {
    
    
    @IBOutlet weak var loader: UIActivityIndicatorView!
    
    @IBOutlet weak var hiddenSwitch: UISwitch!
    
    // 토글 스위치를 설정해주기
    @IBAction func toggleHidden(_ sender: UISwitch) {
        loader.hidesWhenStopped = sender.isOn
    }
    
    // activity indicator 시작하기
    @IBAction func start(_ sender: Any) {
        if !loader.isAnimating{
            loader.startAnimating()
        }
    }
    
    @IBAction func stop(_ sender: Any) {
        if loader.isAnimating {
            loader.stopAnimating()
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        hiddenSwitch.isOn = loader.hidesWhenStopped
//        loader.isAnimating = true
        loader.startAnimating()
    }
}

Progress View


class ProgressViewViewController: UIViewController {
    
    // progressView outlet 생성하기
    @IBOutlet weak var progress: UIProgressView!
    
    // setProgress를 사용하여 80프로까지 차는 애니메이션 구현하기
    @IBAction func update(_ sender: Any) {
        progress.setProgress(0.8, animated: true)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 초기 프로그레스 값은 0.0
        progress.progress = 0.0
        progress.trackTintColor = UIColor.systemGray
        progress.progressTintColor = .systemRed
    }
}

0개의 댓글