본문 바로가기
iOS

iOS 11주

by asd135 2024. 11. 13.
728x90

페이지 컨트롤

콘텐츠의 여러 페이지나 항목 간을 탐색할 수 있도록 도와주는 UI 

 

 

 

//
//  ViewController.swift
//  PageControl
//
//  Created by Ho-Jeong Song on 2021/11/25.
//

import UIKit

// 이미지 파일 이름을 저장하는 배열
var images = [ "01.png", "02.png", "03.png", "04.png", "05.png", "06.png" ]

class ViewController: UIViewController {
    // 이미지 뷰와 페이지 컨트롤을 IBOutlet으로 연결
    @IBOutlet var imgView: UIImageView!
    @IBOutlet var pageControl: UIPageControl!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 뷰가 로드된 후 추가적인 설정을 수행합니다.

        // 페이지 컨트롤의 페이지 수를 이미지 배열의 수로 설정
        pageControl.numberOfPages = images.count
        // 현재 페이지를 배열 인덱스 3으로 설정 (4번째 이미지)
        pageControl.currentPage = 3 
        
        // 페이지 인디케이터의 기본 색상을 파란색으로 설정
        pageControl.pageIndicatorTintColor = UIColor.blue 
        // 현재 페이지 인디케이터의 색상을 회색으로 설정
        pageControl.currentPageIndicatorTintColor = UIColor.gray 
        
        // 이미지 뷰에 첫 번째 이미지를 설정
        imgView.image = UIImage(named: images[0])
    }

    // 페이지 컨트롤의 페이지가 변경될 때 호출되는 액션 메서드
    @IBAction func pageChange(_ sender: UIPageControl) {
        // 현재 페이지 인덱스에 해당하는 이미지를 이미지 뷰에 설정
        imgView.image = UIImage(named: images[pageControl.currentPage])
    }
}

 

탭바 컨트롤러

탭으로 여러 화면으로 이동할 수 있는 컨트롤러

 

네비게이션 컨트롤러

사용자가 여러 화면(뷰) 간에 탐색할 수 있도록 도와주며, 주로 스택 기반의 탐색 방식으로 작동

테이블 뷰

요소를 계층적으로 보여줌

 

가장 많이 사용하는 UI컨트롤러

1. UIViewController
설명: 기본적인 뷰 컨트롤러로, 앱의 화면을 구성하는 데 사용됩니다. 사용자 인터페이스 요소를 추가하고 이벤트를 처리하는 데 필수적입니다.
용도: 여러 UI 요소를 배치하고, 사용자와의 상호작용을 관리합니다. 서브클래스를 만들어 다양한 화면을 구현할 수 있습니다.
2. UITableViewController
설명: 테이블 뷰를 전문적으로 관리하는 컨트롤러입니다. 데이터의 리스트를 표시하고 사용자가 선택할 수 있는 항목을 제공합니다.
용도: 목록, 설정, 피드 등 다양한 데이터 집합을 표시할 때 사용됩니다. 스크롤 가능한 리스트를 쉽게 구현할 수 있습니다.
3. UINavigationController
설명: 여러 뷰 컨트롤러 간의 계층적 탐색을 관리하는 컨트롤러입니다. 스택 기반으로 작동하며, 화면 전환을 부드럽게 처리합니다.
용도: 사용자에게 "뒤로" 가기 기능을 제공하며, 여러 화면 간의 관계를 명확하게 만들어줍니다. 예를 들어, 목록에서 항목을 선택하면 상세 화면으로 이동할 때 사용됩니다.

 

음악을 재생하고 녹음하는 앱

//
//  ViewController.swift
//  Audio
//
//  Created by BeomGeun Lee on 2021.
//

import UIKit
import AVFoundation

class ViewController: UIViewController, AVAudioPlayerDelegate, AVAudioRecorderDelegate {
    
    // 오디오 플레이어와 오디오 파일 URL
    var audioPlayer: AVAudioPlayer!
    var audioFile: URL!
    
    // 최대 볼륨 설정
    let MAX_VOLUME: Float = 10.0
    
    // 재생 시간을 위한 타이머
    var progressTimer: Timer!
    
    // 타이머 선택자
    let timePlayerSelector: Selector = #selector(ViewController.updatePlayTime)
    let timeRecordSelector: Selector = #selector(ViewController.updateRecordTime)

    // UI 요소 연결
    @IBOutlet var pvProgressPlay: UIProgressView!    // 재생 진행률 표시
    @IBOutlet var lblCurrentTime: UILabel!           // 현재 재생 시간 레이블
    @IBOutlet var lblEndTime: UILabel!               // 총 재생 시간 레이블
    @IBOutlet var btnPlay: UIButton!                 // 재생 버튼
    @IBOutlet var btnPause: UIButton!                // 일시 정지 버튼
    @IBOutlet var btnStop: UIButton!                 // 정지 버튼
    @IBOutlet var slVolume: UISlider!                // 볼륨 슬라이더
    
    @IBOutlet var btnRecord: UIButton!               // 녹음 버튼
    @IBOutlet var lblRecordTime: UILabel!            // 녹음 시간 레이블
    
    var audioRecorder: AVAudioRecorder!
    var isRecordMode = false                          // 녹음 모드 여부
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 뷰가 로드된 후 추가적인 설정
        selectAudioFile()  // 오디오 파일 선택
        if !isRecordMode {
            initPlay()     // 재생 초기화
            btnRecord.isEnabled = false  // 녹음 버튼 비활성화
            lblRecordTime.isEnabled = false // 녹음 시간 레이블 비활성화
        } else {
            initRecord()   // 녹음 초기화
        }
    }
    
    // 오디오 파일 선택
    func selectAudioFile() {
        if !isRecordMode {
            // 녹음 모드가 아닐 때, 리소스에서 오디오 파일 로드
            audioFile = Bundle.main.url(forResource: "Sicilian_Breeze", withExtension: "mp3")
        } else {
            // 녹음 모드일 때, 문서 디렉토리에 저장될 파일 URL 설정
            let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
            audioFile = documentDirectory.appendingPathComponent("recordFile.m4a")
        }
    }
    
    // 녹음 초기화
    func initRecord() {
        // 오디오 녹음 설정
        let recordSettings = [
            AVFormatIDKey: NSNumber(value: kAudioFormatAppleLossless as UInt32),
            AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue,
            AVEncoderBitRateKey: 320000,
            AVNumberOfChannelsKey: 2,
            AVSampleRateKey: 44100.0
        ] as [String: Any]
        
        // 오디오 레코더 초기화
        do {
            audioRecorder = try AVAudioRecorder(url: audioFile, settings: recordSettings)
        } catch let error as NSError {
            print("Error-initRecord : \(error)")
        }
        
        audioRecorder.delegate = self
        slVolume.value = 1.0  // 초기 볼륨 설정
        audioPlayer.volume = slVolume.value
        lblEndTime.text = convertNSTimeInterval2String(0)  // 총 시간 초기화
        lblCurrentTime.text = convertNSTimeInterval2String(0) // 현재 시간 초기화
        setPlayButtons(false, pause: false, stop: false) // 버튼 상태 초기화
        
        let session = AVAudioSession.sharedInstance()
        // 오디오 세션 설정
        do {
            try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default)
            try AVAudioSession.sharedInstance().setActive(true)
        } catch let error as NSError {
            print("Error-setCategory : \(error)")
        }
    }
    
    // 재생 초기화
    func initPlay() {
        // 오디오 플레이어 초기화
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: audioFile)
        } catch let error as NSError {
            print("Error-initPlay : \(error)")
        }
        
        slVolume.maximumValue = MAX_VOLUME // 최대 볼륨 설정
        slVolume.value = 1.0 // 초기 볼륨 설정
        pvProgressPlay.progress = 0 // 진행률 초기화
        
        audioPlayer.delegate = self
        audioPlayer.prepareToPlay() // 플레이어 준비
        audioPlayer.volume = slVolume.value // 볼륨 설정
        
        lblEndTime.text = convertNSTimeInterval2String(audioPlayer.duration) // 총 재생 시간 설정
        lblCurrentTime.text = convertNSTimeInterval2String(0) // 현재 시간 초기화
        setPlayButtons(true, pause: false, stop: false) // 버튼 상태 설정
    }
    
    // 버튼 상태 설정
    func setPlayButtons(_ play: Bool, pause: Bool, stop: Bool) {
        btnPlay.isEnabled = play
        btnPause.isEnabled = pause
        btnStop.isEnabled = stop
    }
    
    // NSTimeInterval을 문자열로 변환
    func convertNSTimeInterval2String(_ time: TimeInterval) -> String {
        let min = Int(time / 60) // 분 계산
        let sec = Int(time.truncatingRemainder(dividingBy: 60)) // 초 계산
        let strTime = String(format: "%02d:%02d", min, sec) // 포맷팅
        return strTime
    }

    // 재생 버튼 클릭 시 호출되는 액션
    @IBAction func btnPlayAudio(_ sender: UIButton) {
        audioPlayer.play() // 오디오 재생
        setPlayButtons(false, pause: true, stop: true) // 버튼 상태 변경
        progressTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: timePlayerSelector, userInfo: nil, repeats: true) // 타이머 시작
    }
    
    // 재생 시간 업데이트
    @objc func updatePlayTime() {
        lblCurrentTime.text = convertNSTimeInterval2String(audioPlayer.currentTime) // 현재 시간 업데이트
        pvProgressPlay.progress = Float(audioPlayer.currentTime / audioPlayer.duration) // 진행률 업데이트
    }
    
    // 일시 정지 버튼 클릭 시 호출되는 액션
    @IBAction func btnPauseAudio(_ sender: UIButton) {
        audioPlayer.pause() // 오디오 일시 정지
        setPlayButtons(true, pause: false, stop: true) // 버튼 상태 변경
    }
    
    // 정지 버튼 클릭 시 호출되는 액션
    @IBAction func btnStopAudio(_ sender: UIButton) {
        audioPlayer.stop() // 오디오 정지
        audioPlayer.currentTime = 0 // 현재 시간 초기화
        lblCurrentTime.text = convertNSTimeInterval2String(0) // 현재 시간 레이블 초기화
        setPlayButtons(true, pause: false, stop: false) // 버튼 상태 변경
        progressTimer.invalidate() // 타이머 정지
    }
    
    // 볼륨 슬라이더 값 변경 시 호출되는 액션
    @IBAction func slChangeVolume(_ sender: UISlider) {
        audioPlayer.volume = slVolume.value // 볼륨 설정
    }
    
    // 오디오 플레이어가 재생 완료 시 호출되는 델리게이트 메서드
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        progressTimer.invalidate() // 타이머 정지
        setPlayButtons(true, pause: false, stop: false) // 버튼 상태 변경
    }
    
    // 녹음 모드 스위치 변경 시 호출되는 액션
    @IBAction func swRecordMode(_ sender: UISwitch) {
        if sender.isOn {
            audioPlayer.stop() // 재생 중인 오디오 정지
            audioPlayer.currentTime = 0 // 현재 시간 초기화
            lblRecordTime!.text = convertNSTimeInterval2String(0) // 녹음 시간 레이블 초기화
            isRecordMode = true // 녹음 모드 설정
            btnRecord.isEnabled = true // 녹음 버튼 활성화
            lblRecordTime.isEnabled = true // 녹음 시간 레이블 활성화
        } else {
            isRecordMode = false // 녹음 모드 해제
            btnRecord.isEnabled = false // 녹음 버튼 비활성화
            lblRecordTime.isEnabled = false // 녹음 시간 레이블 비활성화
            lblRecordTime.text = convertNSTimeInterval2String(0) // 녹음 시간 레이블 초기화
        }
        selectAudioFile() // 오디오 파일

 

동영상 재생

    @IBAction func btnPlayInternalMovie(_ sender: UIButton) {
        // 내부 파일 mp4
        let filePath:String? = Bundle.main.path(forResource: "FastTyping", ofType: "mp4")
        let url = NSURL(fileURLWithPath: filePath!)

        playVideo(url: url)
    }
    
    @IBAction func btnPlayerExternalMovie(_ sender: UIButton) {
        // 외부 파일 mp4
        let url = NSURL(string: "https://dl.dropboxusercontent.com/s/e38auz050w2mvud/Fireworks.mp4")!

        playVideo(url: url)
    }

 

내부, 외부 비디오 재생 방식은 각각 장단점이 있음

 

사진 앱

 

화면에 그림 그리기

//
//  ViewController.swift
//  Sketch
//
//  Created by Ho-Jeong Song on 2021/12/01.
//

import UIKit

class ViewController: UIViewController {
    @IBOutlet var imgView: UIImageView! // 사용자 그림을 그릴 이미지 뷰
    
    var lastPoint: CGPoint! // 마지막 터치 위치
    var lineSize: CGFloat = 5.0 // 선의 두께
    var lineColor = UIColor.black.cgColor // 선의 색상

    override func viewDidLoad() {
        super.viewDidLoad()
        // 뷰가 로드된 후 추가적인 설정을 수행합니다.
    }

    // 이미지 뷰를 지우는 버튼 클릭 시 호출되는 액션
    @IBAction func btnClearImageView(_ sender: UIButton) {
        imgView.image = nil // 이미지 뷰의 이미지를 nil로 설정하여 지움
    }
    
    // 터치가 시작될 때 호출되는 메서드
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first! as UITouch // 첫 번째 터치를 가져옴
        lastPoint = touch.location(in: imgView) // 마지막 터치 위치 저장
    }
    
    // 터치가 이동할 때 호출되는 메서드
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        // 새로운 이미지 컨텍스트 시작
        UIGraphicsBeginImageContext(imgView.frame.size)
        UIGraphicsGetCurrentContext()?.setStrokeColor(lineColor) // 선 색상 설정
        UIGraphicsGetCurrentContext()?.setLineCap(CGLineCap.round) // 선의 끝 모양 설정
        UIGraphicsGetCurrentContext()?.setLineWidth(lineSize) // 선의 두께 설정
        
        let touch = touches.first! as UITouch // 첫 번째 터치 가져오기
        let currPoint = touch.location(in: imgView) // 현재 터치 위치 저장
        
        // 기존 이미지를 현재 컨텍스트에 그리기
        imgView.image?.draw(in: CGRect(x: 0, y: 0, width: imgView.frame.size.width, height: imgView.frame.size.height))
        
        // 마지막 위치에서 현재 위치로 선 그리기
        UIGraphicsGetCurrentContext()?.move(to: CGPoint(x: lastPoint.x, y: lastPoint.y))
        UIGraphicsGetCurrentContext()?.addLine(to: CGPoint(x: currPoint.x, y: currPoint.y))
        UIGraphicsGetCurrentContext()?.strokePath() // 선 그리기
        
        // 새로 그린 이미지를 이미지 뷰에 설정
        imgView.image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext() // 이미지 컨텍스트 종료
        
        lastPoint = currPoint // 마지막 터치 위치 업데이트
    }
    
    // 터치가 끝날 때 호출되는 메서드
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        // 새로운 이미지 컨텍스트 시작
        UIGraphicsBeginImageContext(imgView.frame.size)
        UIGraphicsGetCurrentContext()?.setStrokeColor(lineColor) // 선 색상 설정
        UIGraphicsGetCurrentContext()?.setLineCap(CGLineCap.round) // 선의 끝 모양 설정
        UIGraphicsGetCurrentContext()?.setLineWidth(lineSize) // 선의 두께 설정
        
        // 기존 이미지를 현재 컨텍스트에 그리기
        imgView.image?.draw(in: CGRect(x: 0, y: 0, width: imgView.frame.size.width, height: imgView.frame.size.height))
        
        // 마지막 위치에서 현재 위치로 선 그리기
        UIGraphicsGetCurrentContext()?.move(to: CGPoint(x: lastPoint.x, y: lastPoint.y))
        UIGraphicsGetCurrentContext()?.addLine(to: CGPoint(x: lastPoint.x, y: lastPoint.y)) // 선을 끝점으로
        UIGraphicsGetCurrentContext()?.strokePath() // 선 그리기
        
        // 새로 그린 이미지를 이미지 뷰에 설정
        imgView.image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext() // 이미지 컨텍스트 종료
    }
    
    // 기기 흔들림 감지 시 호출되는 메서드
    override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
        if motion == .motionShake {
            imgView.image = nil // 흔들림이 감지되면 이미지 뷰를 지움
        }
    }
}

 

핀치 제스처

손가락으로 화면 확대/축소

 

앱 스토어에서 기존 bmi 앱 분석하기

https://apps.apple.com/us/app/bmi-%EA%B3%84%EC%82%B0%EA%B8%B0-%EC%B2%B4%EC%A7%88%EB%9F%89%EC%A7%80%EC%88%98-%EA%B3%84%EC%82%B0%EA%B8%B0-%EB%AC%B4%EA%B2%8C-%EC%9D%BC%EA%B8%B0/id1572432663?l=ko

 

‎BMI 계산기 - 체질량지수 계산기 & 무게 일기

‎이 무료 BMI 계산기를 사용하면 나이, 성별, 키, 체중을 입력하여 간편하게 자신의 BMI(체질량 지수)를 계산할 수 있습니다. WHO BMI 분류 방식에 근거하여 설계되었으며, 미터법 및 야드파운드법

apps.apple.com

 

 

iOS BMI 앱 기획서
1. 앱 개요
앱 이름: Simple BMI Calculator
목표: 사용자가 자신의 체질량지수(BMI)를 쉽게 계산하고, 건강 상태를 평가할 수 있도록 돕는 앱.
대상 사용자: 건강 및 피트니스에 관심이 있는 일반 대중.
2. 주요 기능
BMI 계산기:

사용자 입력: 키(센티미터)와 체중(킬로그램)을 입력받아 BMI 계산.
BMI 결과: 계산된 BMI 값을 표시하고, 해당 BMI 범주(저체중, 정상, 과체중, 비만)를 알려줌.
BMI 기록:

사용자가 과거의 BMI 기록을 저장하고, 그래프로 시각화하여 변화를 추적할 수 있도록 함.
건강 정보 제공:

BMI에 따른 건강 정보 및 팁 제공(예: 건강한 체중 범위, 식이요법, 운동 추천).
단위 변환:

미터 및 파운드와 같은 다른 단위로도 입력 가능하도록 변환 기능 추가.
3. UI/UX 디자인
홈 화면:

사용자 친화적인 인터페이스로 키와 체중 입력 필드, 계산 버튼을 배치.
결과를 시각적으로 강조하여 쉽게 이해할 수 있도록 디자인.
결과 화면:

계산된 BMI 값과 해당 범주를 시각적으로 표현.
건강 정보와 팁을 아이콘과 함께 제공하여 시각적 효과를 극대화.
기록 화면:

그래프와 리스트로 과거 BMI 기록을 쉽게 확인할 수 있도록 디자인.
날짜와 함께 BMI 값을 표시하여 사용자가 변화를 추적할 수 있도록 함.
4. 추가 기능
알림 기능:

사용자가 정기적으로 BMI를 입력하도록 알림 기능 추가.
소셜 공유:

사용자가 자신의 BMI 결과를 소셜 미디어에 공유할 수 있는 기능 추가.
다국어 지원:

다양한 언어로 지원하여 다양한 국가의 사용자들에게 접근 가능하도록 함.
5. 마케팅 전략
앱 스토어 최적화(ASO):

키워드 분석을 통해 "BMI", "체중 관리", "건강" 등의 키워드를 활용하여 앱 설명 작성.
소셜 미디어 마케팅:

Instagram, Facebook, Twitter 등을 통해 건강 관련 콘텐츠 및 사용자 후기 공유.
블로그 및 유튜브 협업:

건강 및 피트니스 관련 블로그 및 유튜버와 협업하여 앱을 소개하고 리뷰를 받음.
사용자 피드백:

초기 사용자 피드백을 통해 앱의 기능 개선 및 업데이트 계획 수립.
6. 기술 스택
개발 언어: Swift
프레임워크: UIKit, Core Data (기록 저장용), Charts (그래프 표시용)
디자인 툴: Sketch 또는 Figma
7. 일정 계획
1단계: 시장 조사 및 기획 
2단계: 디자인 프로토타입 제작 
3단계: 앱 개발 
4단계: 베타 테스트 및 피드백 수집 
5단계: 최종 출시 

 

BMI 계산하는 다양한 코드들

let weight = 60.0
let height = 170.0
let bmi = weight / (height*height*0.0001) // kg/m*m
print(bmi)
---------------------------
let weight = 60.0 // 체중 (kg)
let height = 170.0 // 신장 (cm)

let bmi = weight / (height * height * 0.0001) // kg/m²로 변환

var body = "" // BMI 판정 결과 저장 변수

// BMI에 따른 판정
if bmi >= 40 {
    body = "3단계 비만"
} else if bmi >= 30 && bmi < 40 {
    body = "2단계 비만"
} else if bmi >= 25 && bmi < 30 {
    body = "1단계 비만"
} else if bmi >= 18.5 && bmi < 25 {
    body = "정상"
} else {
    body = "저체중"
}

// 결과 출력
print("BMI: \(bmi), 판정: \(body)")
------------------------
import Foundation
let weight = 60.0
let height = 170.0
let bmi = weight / (height*height*0.0001) // kg/m*m
let shortenedBmi = String(format: "%.1f", bmi)
var body = ""
if bmi >= 40 {
body = "3단계 비만"
} else if bmi >= 30 && bmi < 40 {
body = "2단계 비만"
} else if bmi >= 25 && bmi < 30 {
body = "1단계 비만"
} else if bmi >= 18.5 && bmi < 25 {
body = "정상"
} else {
body = "저체중"
}
print("BMI:\(shortenedBmi), 판정:\(body)")
--------------------------
import Foundation
func calcBMI(weight : Double, height : Double) -> String{
let bmi = weight / (height*height*0.0001) // kg/m*m
let shortenedBmi = String(format: "%.1f", bmi)
var body = ""
if bmi >= 40{
body = "3단계 비만"
} else if bmi >= 30 && bmi < 40 {
body = "2단계 비만"
} else if bmi >= 25 && bmi < 30 {
body = "1단계 비만"
} else if bmi >= 18.5 && bmi < 25 {
body = "정상"
} else {
body = "저체중"
}
return "BMI:\(shortenedBmi), 판정:\(body)"
}
print(calcBMI(weight:62.5, height: 172.3))
--------------------------
import Foundation
func calcBMI (weight : Double, height : Double) { //Void형
let bmi = weight / (height*height*0.0001) // kg/m*m
let shortenedBmi = String(format: "%.1f", bmi)
switch bmi {
case 0.0..<18.5:
print("BMI:\(shortenedBmi),판정:저체중")
case 18.5..<25.0 :
print("BMI:\(shortenedBmi),판정:정상")
case 25.0..<30.0 :
print("BMI:\(shortenedBmi),판정:1단계 비만")
case 30.0..<40.0 :
print("BMI:\(shortenedBmi),판정:2단계 비만")
default :
print("BMI:\(shortenedBmi),판정:3단계 비만")
}
}
calcBMI(weight:62.5, height: 172.3)

 

 

1. UI디자인 

2. Outlet 설정

3. 함수 설정

4. outlet, action이 한번만 연결될 것인지 확인

5. action 소스코드 작성

 

 

 

이미지는 에셋 폴더에 넣음

아이폰, 아이패드의 해상도가 다르기 때문에 해상도 별 사진을 각각 준비해야함

 

버튼 디자인 변경

시뮬레이터에서 변경된 디자인이 보임

 

키보드 타입

텍스트 필드에서 숫자만 나오는 키보드로 변경

 

출처

----------------------------------------
02 Hello World 앱 만들며 Xcode에 완벽 적응하기
03 원하는 이미지 화면에 출력하기 - 이미지 뷰
04 데이트 피커 사용해 날짜 선택하기
05 피커 뷰 사용해 원하는 항목 선택하기
06 얼럿 사용해 경고 표시하기
07 웹 뷰로 간단한 웹 브라우저 만들기
08 맵 뷰로 지도 나타내기
09 페이지 이동하기 - 페이지 컨트롤
10 탭 바 컨트롤러 이용해 여러 개의 뷰 넣기
11 내비게이션 컨트롤러 이용해 화면 전환하기
12 테이블 뷰 컨트롤러 이용해 할 일 목록 만들기
13 음악 재생하고 녹음하기
14 비디오 재생 앱 만들기
15 카메라와 포토 라이브러리에서 미디어 가져오기
16 코어 그래픽스로 화면에 그림 그리기
17 탭과 터치 사용해 스케치 앱 만들기
18 스와이프 제스처 사용하기
19 핀치 제스처 사용해 사진을 확대/축소하기

'iOS' 카테고리의 다른 글

iOS 13주  (0) 2024.11.27
iOS 12주  (0) 2024.11.20
IOS 10주차  (1) 2024.11.06
iOS 9주  (0) 2024.10.30
iOS 7주차  (2) 2024.10.16