class StackViewAxisViewController: UIViewController {
@IBOutlet weak var stackView: UIStackView!
// view가 horizontal에서 vertical로 바뀌는 혹은 그 반대로 바뀌는 animation을 호출하는 action 생성
@IBAction func toggleAxis(_ sender: Any) {
UIView.animate(withDuration: 0.3){[self] in
if stackView.axis == .horizontal {
stackView.axis = .vertical
} else {
stackView.axis = .horizontal
}
}
}
아래와 같이 있던 stackview가 toggleAxis를 누르면
아래와 같이 stackview가 horizontal하게 변하게 된다.
먼저 아래와 같이 stackview를 구성해보자(현재 spacing은 음수)
아래는 slider를 통하여 넘어간 value값이 stackview의 spacing으로 넘어가게 된다.
class StackViewSpacingViewController: UIViewController {
@IBOutlet weak var redView: UIView!
@IBOutlet weak var horizontalStackView: UIStackView!
@IBOutlet weak var spacingLabel: UILabel!
@IBOutlet weak var spacingSlider: UISlider!
@IBAction func spacingChanged(_ sender: UISlider) {
UIView.animate(withDuration: 0.3){
self.horizontalStackView.spacing = CGFloat(sender.value)
}
updateLabel()
}
private func updateLabel() {
spacingLabel.text = "\(Int(horizontalStackView.spacing))"
}
override func viewDidLoad() {
super.viewDidLoad()
updateLabel()
spacingSlider.value = Float(horizontalStackView.spacing)
}
}
class StackViewSpacingViewController: UIViewController {
@IBOutlet weak var redView: UIView!
@IBOutlet weak var horizontalStackView: UIStackView!
@IBOutlet weak var spacingLabel: UILabel!
@IBOutlet weak var spacingSlider: UISlider!
// slider 값을 stackview의 SPACING 값으로 넣기
@IBAction func spacingChanged(_ sender: UISlider) {
UIView.animate(withDuration: 0.3){
self.horizontalStackView.spacing = CGFloat(sender.value)
}
updateLabel()
}
private func updateLabel() {
spacingLabel.text = "\(Int(horizontalStackView.spacing))"
}
override func viewDidLoad() {
super.viewDidLoad()
updateLabel()
spacingSlider.value = Float(horizontalStackView.spacing)
//
// //
// horizontalStackView.setCustomSpacing(60, after: redView)
}
}
※ superview에 바로 view를 추가하면 subview로 들어가지만, stackview에 view를 추가하면 arrangedsubview로 들어가게 된다.
cf) https://ios-development.tistory.com/986 - layoutIfNeeded()
import UIKit
class StackViewArrangedSubviewsViewController: UIViewController {
@IBOutlet weak var stackView: UIStackView!
// 뒤에 view를 넣어주기
@IBAction func add(_ sender: Any) {
let v = generateView()
stackView.addArrangedSubview(v)
UIView.animate(withDuration: 0.3){
self.stackView.layoutIfNeeded()
}
}
// index 0에 view를 추가해주기
@IBAction func insert(_ sender: Any) {
let v = generateView()
stackView.insertArrangedSubview(v, at: 0)
UIView.animate(withDuration: 0.3){
self.stackView.layoutIfNeeded()
}
}
// 랜덤으로 view를 삭제하기
@IBAction func remove(_ sender: Any) {
// 먼저 stackview에 subview가 있는 지 확인하기
guard stackView.arrangedSubviews.count > 0 else {
return
}
let index = Int.random(in: 0..<stackView.arrangedSubviews.count)
let v = stackView.arrangedSubviews[index]
// remove가 되는 것은 animation을 조금 다르게 설정해줘야된다. - 0.3초동안 v를 hidden하고, 그 이후에는 remove한다!
UIView.animate(withDuration: 0.3){
v.isHidden = true
} completion: {finished in
self.stackView.removeArrangedSubview(v)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// viewDidload에서 바로 view를 넣고싶다면?
// stackview에는 바로 addsubview가 되지 않는다. 따라서 frame을 설정하고 해줘야된다.
let v = generateView()
v.frame = stackView.bounds
stackView.addSubview(v)
}
}
extension StackViewArrangedSubviewsViewController {
private func generateView() -> UIView {
let v = UIView()
let r = CGFloat.random(in: 0.0 ... 256.0) / 255
let g = CGFloat.random(in: 0.0 ... 256.0) / 255
let b = CGFloat.random(in: 0.0 ... 256.0) / 255
v.backgroundColor = UIColor(red: r, green: g, blue: b, alpha: 1.0)
return v
}
}
세개의 .alert 스타일이 있다. -> .default / .cancel / destructive
preferredAction을 사용하면 우선순위도 올라가고 볼드체로 변하게 된다. 단, addAction을 한 후에만 사용이 가능하다.
class AlertViewController: UIViewController {
@IBAction func show(_ sender: Any) {
// alert vs actionsheet
let controller = UIAlertController(title: "Hello", message: "Have a nice day :)", preferredStyle: .alert)
// Ok button을 만들어주기. 뒤에는 클로져인데, action을 실행(버튼 클릭)하면 클로져가 실행이된다.
let okAction = UIAlertAction(title: "Ok", style: .default) { (action) in
print(action.title)
}
// Ok 버튼 추가해주기
controller.addAction(okAction)
// canel 버튼을 만들어주자!.
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
print(action.title)
}
// cancel 버튼 추가해주기
controller.addAction(cancelAction)
// Destructive style의 버튼 만들어보기
let destructive = UIAlertAction(title: "Destructive", style: .destructive){ (action) in
print(action.title)
}
// destructive 버튼 넣어주기
controller.addAction(destructive)
// alert는 cancel 타입의 버튼을 볼드체로 보여준다. -> 그러나 preferred를 하면 우선순위도 높아지고, 볼드체도 된다.
controller.preferredAction = okAction
// alertcontroller를 보여준다!
present(controller, animated: true, completion: nil)
}
현재 아래와 같이 viewcontroller가 구성이되어있다
import UIKit
class AddTextFieldViewController: UIViewController {
@IBOutlet weak var idLabel: UILabel!
@IBOutlet weak var passwordLabel: UILabel!
@IBAction func show(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
아래와 같이 스토리보드가 구성이되어있다.
아래와 같이 코드를 구성하여 경고창에 text를 입력하면 실제 view에 해당 text가 입력이 되도록 변경을 할 수 있다.
@IBAction func show(_ sender: Any) {
// 경고창을 띄우기!
let controller = UIAlertController(title: "Sign In to iTunes Store", message: nil, preferredStyle: .alert)
// 경고창에 textfield 생성하기
controller.addTextField{(idField) in
// placeholder 생성하기
idField.placeholder = "Apple Id"
}
controller.addTextField{(passwordField) in
passwordField.placeholder = "Input Password"
// 마스킹 하기
passwordField.isSecureTextEntry = true
}
let okAction = UIAlertAction(title: "Ok", style: .default){[weak self]
(action) in
if let fieldList = controller.textFields{
// 경고창 첫번째 textfield를 idLabel에 넣기
if let idField = fieldList.first{
self?.idLabel.text = idField.text
}
if let passwordField = fieldList.last {
self?.passwordLabel.text = passwordField.text
}
}
}
controller.addAction(okAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
controller.addAction(cancelAction)
present(controller, animated: true, completion: nil)
}
// 경고창에 textfield 생성하기
controller.addTextField{(idField) in
// placeholder 생성하기
idField.placeholder = "Apple Id"
}
controller.addTextField{(passwordField) in
passwordField.placeholder = "Input Password"
// 마스킹 하기
passwordField.isSecureTextEntry = true
}
class ActionSheetViewController: UIViewController {
@IBOutlet weak var resultLabel: UILabel!
@IBAction func show(_ sender: UIButton) {
let controller = UIAlertController(title: "Languages", message: "Choose one", preferredStyle: .alert)
let swiftAction = UIAlertAction(title: "Swift", style: .default) { [weak self] (action) in
self?.resultLabel.text = action.title
}
controller.addAction(swiftAction)
let javaAction = UIAlertAction(title: "Java", style: .default) { [weak self] (action) in
self?.resultLabel.text = action.title
}
controller.addAction(javaAction)
let pythonAction = UIAlertAction(title: "Python", style: .default) { [weak self] (action) in
self?.resultLabel.text = action.title
}
controller.addAction(pythonAction)
let cSharpAction = UIAlertAction(title: "C#", style: .default) { [weak self] (action) in
self?.resultLabel.text = action.title
}
controller.addAction(cSharpAction)
let clearAction = UIAlertAction(title: "Clear", style: .destructive) { [weak self] (action) in
self?.resultLabel.text = nil
}
controller.addAction(clearAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
controller.addAction(cancelAction)
present(controller, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
if let pc = controller.popoverPresentationController{
pc.sourceView = view
pc.sourceRect = sender.frame
}
// 만약 이미 설정한 action이 있다면 그 액션은 다시 설정을 못하게하기
for action in controller.actions {
if action.title == resultLabel.text {
action.isEnabled = false
}
}