2016년 1월 29일 금요일

커스텀 스위치 버튼 만들기





UISwitch 가 있지만



커스텀한 스위치 버튼을 디자인 가이드에 있다면

백그라운드 이미지를 적용하고
버튼 이미지를 적용

select 되었을 때 버튼 이미지를 우측으로
unselect 되었을 때 버튼 이미지를 다시 좌측으로 이동 해야 한다.

어떻게 하나?


프로퍼티에서 inset을 변경 시켜야 한다.

default / selected에서 이값을 설정 해놓을 수는 없다.

나머지는 코드로 해결 해야 한다.

우측으로

            self.backgroundSyncButton.imageEdgeInsets = UIEdgeInsetsMake(0, 25, 0, 5)

좌측으로
            self.backgroundSyncButton.imageEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 5)

그럼 스위치 버튼 만들기 끝


2016년 1월 28일 목요일

UIProgressView 트랙, 프로그래스 커스텀 이미지 적용 버그 해결 방법










지난번에
http://mtsparrow.blogspot.kr/2016/01/uiprogress-view-height.html


UIProgressView 컨트롤에 Height 문제도 있었지만

그 외에 도 문제가 있다.

커스텀한  프로그래스 이미지와 트랙이미지를 아무리  인터페이스 빌더에서
적용해 주어도 효과가 없다.

이에 대한 해결 방밥은

https://gist.github.com/JohnEstropia/9482567

여기에서 찾을수 있다.

JEProgressView라는 클래스 이름으로 UIProgressView를 상속 받아 문제를
해결 하였다.

이를 이용하여 Track 이미지 Progress 이미지를 설정 하면 제대로 된 결과를 얻을 수 있다.


2016년 1월 23일 토요일

네비게이션 바에 컬러 아이콘으로 버튼을 만들고 거기에 넘버링 까지 하려면



이러한 화면을 구성 하려면 어찌 합니까? 어떻게 할까요?

우선 네비게이션바에 바버튼 이미지는 단색으로 설정된다.

        let btImage = Helper.textToImage("1", inImage: UIImage(named: "bt_topmenu_bell_on")!, atPoint: CGPoint(x: 26, y: 21))
        
        

        let rightButton2: UIBarButtonItem = UIBarButtonItem(image: btImage.imageWithRenderingMode(.AlwaysOriginal), style: UIBarButtonItemStyle.Plain, target: self, action: "")


위 코드에서  btImage.imageWithRenderingMode(.AlwaysOriginal) 
이를 설정 해 줘야 네비게이션바에 바버튼 이미지를 원래 색상으로 처리 한다.

btImage 즉 벨 아이콘에 숫자 넘버링을 위한 코드는 helper 클래스를 만들어서 이용 하였다.

아무데서나 편하게 쓰기 위한 helper 클래스를 만들고 거기에 
text와 이미지, 그리고 포지션을 주면 이미지위에  text를 표시하는 함수를 작성 해서 이용한다.

// 이미지 위에 쓰기 (넘버링)
    static func textToImage(drawText: NSString, inImage: UIImage, atPoint:CGPoint)->UIImage{
        
        // Setup the font specific variables
        let textColor: UIColor = UIColor.whiteColor()
        let textFont: UIFont = UIFont(name: "Helvetica Bold", size: 9)!
        
        //Setup the image context using the passed image.
        UIGraphicsBeginImageContext(inImage.size)
        
        //Setups up the font attributes that will be later used to dictate how the text should be drawn
        let textFontAttributes = [
            NSFontAttributeName: textFont,
            NSForegroundColorAttributeName: textColor,
        ]
        
        //Put the image into a rectangle as large as the original image.
        inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))
        
        // Creating a point within the space that is as bit as the image.
        let rect: CGRect = CGRectMake(atPoint.x, atPoint.y, inImage.size.width, inImage.size.height)
        
        //Now Draw the text into an image.
        drawText.drawInRect(rect, withAttributes: textFontAttributes)
        
        // Create a new image out of the images we have created
        let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
        
        // End the context now that we have the image we need
        UIGraphicsEndImageContext()
        
        //And pass it back up to the caller.
        return newImage
    }



2016년 1월 13일 수요일

statusbar 에 Text 및 아이콘의 컬러를 white로 변경 하기




ViewController나, NavigationBar의 배경색을 변경 하면 Statusbar의 배경색은 동일 하게 바뀐다.
문제는 어둡게 변경되었을 경우 Black의 폰트는 시인성이 떨어진다.

그럼 이렇게 어두운 배경톤을 사용하는 앱에서 statusbar의 text 색상을 어떻게 바꾸나



info.plist에 View controller-based status bar appearance 이항 목을 추가 하고 값을 NO로 설정 하한다.


AppDelegate.swift 파일에서 didFinishLaunchingWithOptions 함수에 다음 코드를 추가 한다.


                UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: false)



그러면 원하는 대로 어두운 배경색의 statusbar에서 white 색상에 폰트와 text를 얻을 수 있다.

2016년 1월 12일 화요일

XCode의 code snippets, key binding, font and color them을 dropbox를 이용하여 동기화 하기

주 작업 머신은 2012 MAC MINI i7 쿼드 모델 이다.

하지만 외부에 나가거나 가끔 2013 mbpr을 이용하기도 한다.

XCode를 자신에 입 맞에 맞추어 설정을 하면 서로 동기화가 필요 할 때가 있다.

특히 나 작은 코드블럭인 snippets을 설정해서 사용하고 있는데 이게 머신 마다.
다르면 좀 그렇다.

그리고 최근 안구건조증인지 눈이 많이 뻑뻑해서 Dracula 테마도 다운 받았는데
매번 이 테마 파일을 다른 머신에 복사 하기도 문제가 될 거 같다.

아직 이 드라큘라 테마가 맘에 완전 드는지 아닌지는 며칠 써보고 다른 테마를 추가 할지도 모를 일이다.

해서 다음과 같은 작업을 해보고 snippet이 동기화 됨을 확인 하였다.

1번 주 머신
dorpbox에 xcode 폴더를 생성
$ ln -s ~/Library/Developer/Xcode/UserData/CodeSnippets ~/Dropbox/xcode/CodeSnippets

$ ln -s ~/Library/Developer/Xcode/UserData/KeyBindings/ ~/Dropbox/xcode/KeyBindings

$ ln -s ~/Library/Developer/Xcode/UserData/FontAndColorThemes/ ~/Dropbox/xcode/FontAndColorThemes


mbpr 머신에서 Dropbox에 의해 동기화가 이루어 졌다.

mbpr 머신에서는 dropbox에서 ~/Library/Developer/Xcode/UserData 로 모두 링크를 걸어 준다.
KeyBindings  폴더는 있었기 때문에 기존 폴더를 과감 하게 삭제 하고 링크를 걸어 준다.

칼라 테마는 http://zenorocha.github.io/dracula-theme/xcode/ 에서 설치를 진행 하였고 
그래서 최초로 FontAndColorThemes가 생성 되었다.

CodeSnippets의 경우도 주로 사용하지 않던 mbpr에는 없던 폴더이다.
하지만  KeyBindings는 존재 했기 때문에 mbpr에서 링크를 걸기 전에 삭제 했다.

코드 스니핏으로 테스트 해보니 Xcode를 다시 열면 코드 스니핏이 추가 됨을 확인 하였다.





2016년 1월 11일 월요일

네비게이션바의 버튼 위치 조정 하기



to



어찌 합니까? 어떻게 할까요?

디자인 가이드를 맞추기가 어렵다.

    //left 슬라이드 메뉴
    public func addLeftBarButtonWithImage(buttonImage: UIImage) {
        let leftButton: UIBarButtonItem = UIBarButtonItem(image: buttonImage, style: UIBarButtonItemStyle.Plain, target: self, action: "toggleLeft")
        navigationItem.leftBarButtonItem = leftButton;

    }


네비게이션바에 버튼을 추가 하면 첫번째 화면 처럼 된다.
이걸 하단 처럼 하려면

UIButton을 생성 하고 frame을 조정, contentEdgeInset을 조정 하고
UIBarButtonItem을 customView로 버튼을 지정 하는 방법을 시도 했다.
삽질이었다.

결국 간단한 방법을 찾았다.

UIBarButtonItem 중에는 가운데 스페이스 등을 지정 하는 스페이스 아이템을 버튼과 버튼 사이에 넣을수 있다.

왼쪽 left, 오른쪽 right의 그러한 스페이스를 추가 하고 음수 값을 정해서
왼쪽 버튼을 더 왼쪽으로 , 오른쪽 버튼을 더 오른쪽으로 붙일 수  있다.

그래서 다음과 같은 코드가 위 두번째 화면 과 같은 결과를 보여 준다.

    //left 슬라이드 메뉴
    public func addLeftBarButtonWithImage(buttonImage: UIImage) {
        let leftButton: UIBarButtonItem = UIBarButtonItem(image: buttonImage, style: UIBarButtonItemStyle.Plain, target: self, action: "toggleLeft")
        
        let negativeSpacer = UIBarButtonItem(barButtonSystemItem: .FixedSpace,
            target: nil, action: nil)
        
        negativeSpacer.width = -16
        
        navigationItem.setLeftBarButtonItems([negativeSpacer, leftButton], animated: false)
    }

2016년 1월 10일 일요일

UITextField 오른쪽 아이콘 버튼 (돋보기 등) 의 표시하기



위 그림에서 처럼 TextField의 돋보기 버튼 같은 이미지를 추가 하고 클릭 했을때
이벤트를 처리를 위해서는 아래와 같은 코드를 이용한다.

        //텍스트 필드 돋보기 표시
        let magnifyingGlassButton = UIButton()
        let image = UIImage(named: "ic_input_search_n")
        magnifyingGlassButton.setBackgroundImage(image, forState: .Normal)
        magnifyingGlassButton.frame = CGRectMake(0,0, 36, 36)
        magnifyingGlassButton.addTarget(self, action: "magnifyingGlassButtonClick", forControlEvents: .TouchUpInside)
        inputKeywordTextField.rightView = magnifyingGlassButton
        inputKeywordTextField.rightViewMode = UITextFieldViewMode.Always
        

        inputKeywordTextField.delegate = self


    //돋보기 클릭
    func magnifyingGlassButtonClick() {
        //검색 시작
    }

커스텀 버튼을 하나 설정 한다. 
이미지를 할당 하고 이벤트 함수를 addTarget으로 설정 한다.
텍스트 필드에 표시될 버튼이 클릭 되었을때 처리할 이벤트 코드를 작성한다.

해당 이벤트를 
TextField의 rightView에 버튼을 할당 한다.
나와야 하는 상황에 따라 rigthViewMode를 설정 한다.

간단한 팁 끝!

2016년 1월 9일 토요일

UITextField의 inset 적용하기

TextField의 입력 글자의 시작 위치를 어느 정도 들여 쓰기를 하는 방법이 IB로 처리 할 수 없다.
하지만 이러한 디자인요구사항은 있다.


import UIKit
@IBDesignable
class FormTextField: UITextField {

    /*
    // Only override drawRect: if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func drawRect(rect: CGRect) {
        // Drawing code
    }
    */
    @IBInspectable var inset: CGFloat = 0
    
    override func textRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds, inset, inset)
    }
    
    override func editingRectForBounds(bounds: CGRect) -> CGRect {
        return textRectForBounds(bounds)
    }

}
inset을 처리 하는 코드를 별도의 UITextField 를 상속 받아 클래스를 선언 한다.

@IBDesignable와 @IBInspectable var 로 선언을 한
inset은 오른쪽 Utitlity 창에 표시 된다.



이렇게 만든 TextField 컨트롤은 글씨 들여 쓰기가 가능 하다.

아래의 그림의 Placeholder 텍스트의 표시를 보면 12픽셀 들여 쓰기가 되어 있다.


2016년 1월 8일 금요일

Dropbox를 이용한 iOS 테스트 버젼 adhoc 배포

준비물 
Dropbox 
Device uuid


애플 개발자 페이지에 Devices에 배포해야할 사람들의 iOS 기기의 UUID를 모두 입력 해 둔다.
이 디바이스 목록을 프로비져닝에 추가되어야 해당 단말기에서 동작 한다.






테스트 배포를 하려는 앱에서 Product -> Archive 를 선택한다. 
타겟이 시뮬레이터인 경우 메뉴가 disable 되어 있다. 
Generic iOS Device이거나 케이블에 iOS 디바이스를 하나 붙여서 해당 타켓으로 변경 해야 메뉴가 활성 된다.

Archives  창이 뜨고 오른쪽에 Export 버튼을 누른다.

두번째 Ad Hoc Deployment를 선택 한다.

개발자 프로그램 계정을 선택 해 준다.



프로비져닝에 UUID가 입력된 프로비져닝이 있기 때문에
그냥 첫번째 것으로 넘어 간다.

최초 작업을 진행 할때는 첫번째 항목을 체크 한다. .plist 파일을 생성 하는 것이다.



APP URL, Display 이미지등이 없으나 넘어 가려면 https:// 라도 입력해야 Export 버튼이 활성 된다.




데스크탑에 해당 .ipa 파일과 manifest.plist 파일이 생성된다.
이제 이파일들을 dropbox에 특정 폴더에 복사를 하고
index.htm 파일을 만들면 된다.

index.html파일에 내용은
manifest.plist

파일을 다운로드 받는 URL 링크를 만들면된다.


!<li><a href="itms-services://?action=download-manifest&url=https://dl.dropboxusercontent.com/s/w9ysszgqwxepx3f/SmartBand.plist">OTA 설치</a></li>

위 예제의 URL은 dropbox에서 



 





를 통해서 얻은 URL을 다음과 같이 변경 해야 한다.

https://www.dropbox.com/s/w9ysszgqwxepx3f/SmartBand.plist?dl=0
-->
https://dl.dropboxusercontent.com/s/w9ysszgqwxepx3f/SmartBand.plist


ipa 파일에 대한 링크를 얻은 다음 해당 내용은 plist 파일에 내부에 편집을 해야 한다.

.plist의 ipa를 가리키는 URL도 https://dl.dropboxusercontent.com/s 로 변경 해야 한다.

그런다음 해당 테스트 앱을 받아야 하는 고객에게는 index.htm에 대한  링크를 전달 하면 된다.

iOS에서 해당 링크를 클릭 하면 dropbox앱을 통해서 링크가 열리고 사파리 브라우저에서 해당 링크를 
클릭 하면 앱이 다운로드되고 설치 된다.


2016년 1월 7일 목요일

textfiled 입력을 위한 keyboard , pickerview 에 Cancel, Done 버튼 추가하기

어제의 post 에서 http://mtsparrow.blogspot.kr/2016/01/swift-delegate.html

문제를 처리하기 위해 잘못 접근 했다.

ViewController는 입력 TextField가 있고
Keyboard 대신 PickerView가
그리고 화면은 dimming이 되는 이러한 ViewController를 프로그래밍 하기 위한 방법으로

Storyboard 에 TextField 를 디자인 하고
별도의 여러 View 를 .xib로 생성해서 각각 PickerView를 디자인 하고 배경은  blackColor에 opacity를 80%주어서 만든 커스텀 뷰를 올리고 거기에 Done 버튼과 Cancel 버튼을 delegate로 처리 하려고 했다.
TextField delegate 메서드에서 이 커스텀 뷰를 보이게 사라지게만 처리하면 끝이다.

그런데 헐!

키보드?? 어찌합니까? 어떻게 할까요?



PickerView와 Cancel, Done 버튼을 추가 해서 별도의 View로 만들고 그것을 계속 사용하면 되겠지 하며 디자인 가이드에 다음 페이지를 넘기는 순간 ? 헐 이런 숫자 Keyboard?? 그 위에 Cancel, Done 버튼

그렇다. 문제의 접근을 처음부터 잘못 이해 하고 덤벼 들었다.

iOS에서는 키보드위에 카메라 아이콘부터 많은 여러가지 기능을 추가 하도록 디자인 되어 있다.

키보드는 별도의 컨트롤로 디자인 타임에 할 수 있는 컨트롤이 아니다. 단지  TextField의 속성이다.



숫자 키보드가 나오게 하려면 TextField의 속성을 변경 해 주면 된다.

코드에서 textField의 inputAccessoryView에 toolbar를 붙이면 그게 키보드 위에 Cancel, Done 버튼 같은 것을 언질수 있다.

    func addCancelDoneButton() {
        let keyboardToolbar = UIToolbar()
        keyboardToolbar.sizeToFit()
        
        let cancelBarButton = UIBarButtonItem(barButtonSystemItem: .Cancel,
            target: view, action: Selector("cancelEditing:"))
        let flexBarButton = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace,
            target: nil, action: nil)
        let doneBarButton = UIBarButtonItem(barButtonSystemItem: .Done,
            target: view, action: Selector("endEditing:"))
        keyboardToolbar.items = [cancelBarButton, flexBarButton, doneBarButton]
        excerTextField.inputAccessoryView = keyboardToolbar
    }

  
간단 하게 toolbar에 버튼 2개를 추가하고  excerTextField.inputAccessoryView = keyboardToolbar
를 하면 키보드 위에 버튼이 올라간다.

그럼 PickerView도?


물론 PickerView에 addSubView로 toolbar를 언저 보니 올라 간다.
이렇게 하면 또 삽질을 하는 것이다.
PickerView에 툴바를 붙이는 것도 PickerView.addSubView()로 하고
textFiled에서 PickerView를 보이게 하는 방법 또한 잘못된 접근이다.

textField에서 키보드 대신 pickerview를 보이게 하는 방법은 다음과 같다.
코드로 picker뷰를 생성하고
heightTextField.inputView = picker
마찬가지로 툴바를 생성 하고
heightTextField.inputAccessoryView = toolBar

이렇게 하면 TextField 선택시 pickerView가 나오고 pickerView 위에 cancel , done 버튼이 추가 된다.

단점

단점은 여러 입력 TextField의 각각의 PicekerView가 나와야 한다면
PickerView delegate  함수 내부가 각각의 pickerview에 따라 보여 줘야 하는 데이터부터 처리 하는 내용이 복잡 해지는 단점이 있다.
하지만 하나의 ViewController 클래스에서 모두 처리 가능 하다.

무지에서 시작된 어제의 삽질을 오늘 되돌린다.

마지막 키보드나 피커뷰가 나오면 전체 화면이 dimming 처리 하는 것은 어떻게?


다른 방법이 있을지 도 모르지만 이건 아주 간단하게

전체 화면 dimming  뷰를 만들고 이를 textfiled 편집 시작 시 보이게 하고, textfiled 편집이 종료되면
사라지게 하는 방법을 하면 된다.

var dimmingView : UIView!

viweDidLoad() {
....
dimmingView = UIView(frame: CGRectMake(0, 0, view.frame.width, view.frame.height))
        dimmingView.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.2)
        
        self.view.addSubview(dimmingView)
        dimmingView.hidden = true

func textFieldShouldBeginEditing() {
dimmingView.hidden = false

func textFieldShouldEndEditing() {
dimmingView.hidden = true

2016년 1월 6일 수요일

swift delegate 이해하기

간단하게 swift delegate 를 이해하기


C 프로그래머 입장에서 그냥 간단하게 콜백함수로 이해 하는게 가장 쉽다.

언제쓰냐?

간단하게 예제를 생각해 보면

ViewController에 TextFiled가 있다. 날짜만 입력 받아야 하는 경우

여기 편집이 시작되면 keyboard가 아니라 PickerView가 나오고
여기서 선택된 row가 TextField에 입력 되야 한다.




대충 위와 같은 디자인 
이것은 ViewController 위에 Black 컬러에 20%투명을 준 전체 화면 View에 하단에  DatePicker 그리고 Cancel, Done 버튼을 지닌 별도의 View를 위에 언지는 것이다.



PickerView 가 같은 ViewController에 존재 한다면 문제가 없지만
PickerView를 디자이너님 입맛에 맡도록 별도의 View로 만들고 별도의 View class 코드가 존재 한다면


addSubView 로 이미 PickerView가 add되어 있고 ViewController에서 hidden으로 존재 하다가
TextField가 편집 시작되면 keyboard대신 hidden 속성을 false로 해서 나오게 한다.


    func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
        datePickerView.hidden = false
    }

그러면 datePickerView 라는 pickerview를 가지고 잇는 view가화면에 출력 되었다.
모든 제어가 여기로 넘어가서 날짜를 선택 했다.

그 선택된 문자열이 textField.text에 입력이 되야 한다.

datePickerView.DateString이 결과 값이라고 할때 이것을 언제 어떻게 assign 해야 하나?

이럴때 delegate가 필요 하다.

datePickerView의 클래스

protocol DatePickerViewDelegate {
    func DatePickerDidSetDate()

}

영어가 짧은 관계로 DidSetDate?? 이렇게 delegate 함수 이름을 지었다.

var delegate: DatePickerViewDelegate?
이렇게 deleage를 선언 해준다.

self.DateString = strDate
        delegate?.DatePickerDidSetDate()

picker의 결과를 설정 한 다음 delegate 메서드를 호출 해 준다.

이제 이 View를 이용하는 ViewController Class

class ProfileViewController: UIViewController, UITextFieldDelegate, DatePickerViewDelegate
{
var datePickerView: DatePickerView!

....

datePickerView.delegate = self


...
// MARK : DatePickerViewDelegate
    func DatePickerDidSetDate() {
        birthdayTextField.text = datePickerView.DateString
    }

pickerView에서 델리게이트 함수를 호출해 주면 ViewController에 DatePickerDidDate() 함수가 호출 되고 여기서 TextField.text를 설정 하면 된다.

이런 메카니즘이 UITextFieldDelegate, UITableViewDelegate  등등... 우리가 자주 사용하는 delegate 함수를 작성해야 하던 일을 직접 만든 ViewClass에서 이용하는 방법이다.





2016년 1월 4일 월요일

UIProgress View 인터페이스 빌더에서 height 문제점

인터페이스 빌더에서 UIProgress를 뷰컨트롤러에 올리면 황당한 일이 벌어진다.

height 값이 2로 고정되어 증가 시킬 수 가 없다.



물론 현재 Xcode 7.2에 버그로 생각된다.



원래 컨트롤로 기본 모양도 이렇지 않은데 이게 왜 이럴까?




어째든 디자이너는 progress이미지와 백그라운드 이미지를 주었기 때문에
원하는 결과물을 얻어야 한다.

주어진 이미지 리소스를 슬라이싱 해서 설정해도 heigth를 19로 키우지 못하면 안된다.




해결 방법은 나의 경우 Autolayout의 컨스트레인트를 강제로 height를 준 것이다.




그래도 여전히 문제점은 있다. 19로 강제로 설정해서 한다.
Autolayout  워닝이 계속 유지된다. 이부분은 아무래도 버그!
어짜피 처음부터 height를 변경 못하는 거 자체가 버그!





런타임에 최종 결과물은 위와 같다!























2016년 1월 3일 일요일

iOS 구동 동영상을 만들고 싶을때?

앱을 앱스토어에 올리기전에 스크린샷과 설명이 필요 하다.

요즘에는 동영상도 올리기도 한다.

아이폰 구동 동영상을 만드는 방법은 어떻게 하는 것 일까?
AirServer를 이용하는 방법과 QuickTime Player를 이용하는 방법이 있다.
AirServer는 오래전에 앱을 구매하고 알게된 기능이고 QuickTime Player는 무료로 이용이 가능하다.

QuickTime Player를 이용하는 방법이 훨씬 좋다.




1.Air서버 + AirPlay 미러링 



먼저 Mac 컴퓨터에서 AirServer를 실행 한다.




iOS 에서 AirPlay  미러링을 시작 한다.





Mac  컴퓨터에 미러링이 시작되면 하단에 빨간색 녹화 버튼으로 녹화를 할 수  있다.





단점 : 유료앱 AirServer가 필요하다.


2. QuickTime Player 




QuickTime Player
기본으로 설치되어 있는 이앱이 이런 기능이 있는지 몰랐다.





iOS를 Mac과 케이블로 연결한다음 새로운 동영상 녹화를 선택 한다.






하단 녹화 버튼 옆 콤보 버튼을 누르면 iOS를 장치를 선택 할 수 있다.

그럼 iOS 화면이 디스플레이 되면서 구동 영상을 녹화 할 수 있다.