プロトタイプからプロトタイプへ、プロトタイプからプロトタイプへ、プロトタイプから... trash

Qttyという小さなアプリケーションを開発したかったのです。 アプリケーションは、写真を撮影して一連のフィルターを適用し、この同じ写真をVKプロファイルのメイン写真として公開できる必要があります。

著者は、WWDC 2014の223回目のセッションで行ったように、プロトタイプを通してすべてを実行しようとします。







プロジェクトの説明



最初は、説明は次のようになりました。

アプリケーションはVKでのみ動作し(今のところ)、ユーザーが写真を撮って、VKの目的のアルバムに、おそらくいくつかのフィルターを使用してすぐにアップロードできるようにします。



主な機能:

1.フォトアルバムのリストを表示する

2.選択したアルバムの写真を表示する

3.写真を削除する機能

4.アルバムを削除する機能

5.アルバムを作成してアクセス権を指定する機能

6.写真を撮り、フィルターを適用し、写真をアップロードするアルバムを指定(またはプロファイルのメイン写真を作成)、場所を添付、写真に説明を追加します。





私はすぐに何かをしたいと決めたので、ほとんどの機能を削除し、そのようなアプリケーションを作成しました。これについては最初の段落で説明します。

アプリケーションはVKでのみ動作し(今のところ)、ユーザーが写真を撮って、おそらくいくつかのフィルターを使用して、VKにすぐにアップロードできるようにします。





プロトタイプ。 一



画面のスケッチを作成し、さまざまなアイデアを提供し、それらをあらゆる形で紙に掲載します。

承認画面から始めました。 承認なしでは、アプリケーションは写真を処理する意味がありません。そのため、写真を開始として撮影するための画面を表示するオプションは除外されます。 承認画面には、ユーザーがVKにログインし、ユーザーに代わってリクエストを行うことができるボタンをクリックした後、ボタンのような要素があるはずです。



私が持っていたドラフト:







それぞれについて説明します。

1.アイデアは、ユーザーが碑文のある特定の写真のセットを持っているというものでした(印象を友人と共有する、常に連絡を取り合う、楽しい瞬間を共有するなど)。 以下は認証ボタンです。

このオプションの短所:

何かをめくる必要があります。

背景色+画像の描画用のフォントとその色の選択と組み合わされる、希望する色調の画像の選択に関する追加作業。

ある種のユーザーマニュアルのように見えます。

気に入らなかった。



2.最初のバージョンで、アカウントをスクロールしている画像とすべての数が表示されていない場合、この欠陥は修正されました。 ただし、短所は同じままです。

3.画像とボタン。 簡単に思えますが、背景色、画像の色、それらの組み合わせなど、多くの疑問が生じます。 オプションは消えました。

4.ここで、背景は多くのユーザー定義写真のある写真に設定され、多くの人が目を傷つけたり、ユーザーが不安や緊張を感じたりしないように、写真に追加のレイヤーを追加できます。 ボタンは残ります。

このオプションが一番気に入った。



すべてのアイデアが頭から紙に移された後、私はこれらのスクリーンを実際の要素で実際のサイズでスケッチすることを引き受けました。 すべてが基調講演で行われました。

すべてのオプションは表示しませんが、できるのは2つだけです。 最初の2つのオプションの実装時に、リーフスルーを使用して、このような小さなアプリケーションには面倒すぎるという結論に達しました。



認可画面の最初の予備ビュー:





職場の同僚に、2つの選択肢のうちどちらが一番好きかを尋ねました。 すべてが最初に答えた。 いくつかの男と外観のために、多くは2番目を好きではありませんでした。 彼らは、アプリケーションが何であるか、この特定の人、彼が誰であるかなどを理解できませんでした。

2番目のオプションは破棄されました。



しばらくして、そのようなオプションが現れました:





手元には紙がなかったため、承認のためのUIWebViewのVK表示画面は、Keynoteですぐにスケッチされました。 判明したオプション:









彼は最初の選択肢で立ち止まった。 「閉じる」/「キャンセル」ボタンを使用すると、トップパネルが希望どおりに表示されませんでした。 そこに異なる影/透明度と「X」記号のあるボタンを追加しようとしましたが、それも出てきました(ただし、ステッカーやステッカー要素のアイデアが好きになり始めました)。





プロトタイピング段階での主なタスクは、プログラミングなしでアプリケーションを視覚的に再作成し、さまざまな種類のスクリーンを試して、ユーザーの反応を見て、 その応答聞くことです (プロトタイピングの初期段階では、通常、アプリケーション開発の途中または最後に発生しました)。



次の画面は写真画面になり、ユーザーは写真を(フロントまたはリアカメラを使用して)撮影し、フィルター/エフェクトを適用するための画面に移動できます。

スクリーンがあれば、写真はもっと面白かったです。 私はInstagramを見て作業しました。少しの間は好きではなかったので、それらを削除することにしましたが、同時に自分用に何かを採用しました。

何が起こったのか(初期オプションから最新のものまで):









この画面は、最も基本的な要素以外のもので煩雑になりたくありませんでした。したがって、一般的に、すべてのオプションは1つのバリエーションです。 最初は、画面の下部に、ユーザーのスナップショットがキャプチャされるボタンが1つ(1つの要素)だけあります。 画像をキャプチャした後、2つの追加ボタン「サイズ変更」と「プロセス」がボタンから反対側に「移動」する必要があります(私の表示では)。 スケッチの1つでわかるように、最初の段階ではボタンには「YES」と「NO」というラベルしかありませんでしたが、2番目のオプション(最初のショット、2番目の画面)で、YES / NOはまったく有益ではないと思いましたが、同時に「スナップショットで何をしたいですか?」という質問を表示する必要はありません。コンテキストから、どのアクションが必要で何が必要かが明らかだからです。

画面の下部に文字「Q」が付いたボタンを少し下げて、ボタンが少し落ち始めたのはなぜですか? 答えは簡単です-空き領域を増やしたいという願望。 このため、3つの画像(1画面)で、トップパネルが削除されています。

Instagramから、グリッドを採用しただけで、オブジェクトが写真の中央にくるように2、3のショットを撮りたい場合に必要だと思われました。



これは、40〜50分後に得たものです(以下を参照)。 いくつかのポイントが変更され、さらにいくつかのポイントが変更され、アイデアがあります。 プロトタイプのおかげで、画像にラティスとカメラのサインを置くだけではうまくいかないことに気付くことができました-その下に何かを置く必要があります。 パネルが最初の解決策ですが、写真の完全性と印象が失われるため、干渉します。

このリンクでプロトタイピングプロセスのビデオを見つけることができます。











要素をポートレートモードからランドスケープモードに移行する際に、ステータスバーを削除することを検討しました。

比較する:









比較する:









比較する:









そうすることができますか?







そして、ポートレートモードでは、要素を下に移動します。





20〜30分後、私はこのオプションで停止することにしました(オプションが増えれば増えるほど、選択肢は広くなります)。









紫色のボタンが邪魔です。 クリックするとスナップショットがキャプチャされ、クリックした後、ユーザーの前にそれ以上のアクションは表示されません-すぐにフィルターを表示、切り抜きなど。 この画面から、ユーザーはワンクリックで撮影に行くことができます。



写真処理画面のスケッチを始めました。 最初のバージョンは次のとおりです。





私はこのオプションが好きでしたが、実装に行き詰まってしまい、それは望みません。



これに簡略化:





このバージョンでは、ステッカー/ステッカーでトピックを打ち負かすことにしました。 ご覧のとおり、このテーマの最初のバージョンにはフラットな要素があります。



これらは、風景スケープモードで写真を処理するための私の画面です(後で選択しますが、既にいくつかのお気に入りがあります。 このリンクによるビデオ。):













完全に異なるもの(各画像はフィルターが適用されたソース画像でなければなりません):





クリックすると、次の画面が開きます。





確かに、このオプションにはいくつかの質問があります。

1.この画面を終了する方法は?

2.何らかのアクションを確認する2つの要素(ボタンはフィルターを適用し、チェックマークは設定に適用されます)

3.少数のフィルターでは見栄えが良く、画像のかなりの部分が見えますが、このアコーディオンは10〜15個のフィルターでどのように見えますか?

それでも、見栄えが良いので、最後にこのオプションを破棄しません。



次はブートオプション画面です。 ユーザーが指定できるもの:

1)写真をプライマリとして設定

2)現在地を添付する

3)写真をアップロードするアルバムを選択します

4)写真に友達タグを追加する

5)壁に写真を投稿する



基調講演の概要:













作成プロセスのビデオは、 このリンクにあります。



写真をダウンロードするプロセスをユーザーに示す必要がありますか? 答えが「はい」の場合、現在の画面に特定の読み込みインジケーターを配置するか、アップロードする写真のリストを含む新しい画面を作成する必要があります。 このリストは、インターネットがないときに写真をダウンロードする問題を解決するために必要です。 ユーザーはそのような明示的なリストをどれだけ必要としますか? 主なタスクは、不要なものをすべて隠し、アプリケーションを可能な限り有機的かつ自然なものにすることです。

数分後、キュー内の写真の数を表示する次のオプションが予想されました。





バックグラウンドで画像をアップロードします。 何らかの理由で写真をアップロードできなかった場合、後で再試行しますが、リストから写真を削除しません。



私はオプションがついた最後の画面があまり好きではないので、もう一度プレイすることにしました。 比較する:





このようなインターフェイスは、ランドスケープモードで取得されます。







コールアウトブロックのあるオプションは考慮しませんでした。 ランドスケープスケッチモードには十分な垂直位置がありません+ランドスケープバージョンとポートレートバージョンの間の要素の一般的な位置を維持したかったです。



プロトタイプ:レビュー。 二。



ログイン画面:



コメント: なし



VKのモーダルログインウィンドウ(修正バージョン):



コメント:

前の画面の碑文「承認」はボタンのように見え、被験者はこれについて質問しました。





撮影ウィンドウ(ポートレートモード):



コメント: なし



撮影ウィンドウ(風景モード):



コメント: なし



フィルター(ポートレートモード):



コメント: なし



フィルター(ランドスケープスキップモード):



コメント: なし



ダウンロード設定(ポートレートモード):



コメント:

フォントがひどい。 これらが私の友人であることがわかった場合、「見出し」という見出しが必要なのはなぜですか? (著者:これは、画面の2番目のバージョンが表示される方法です)





ブート設定(造園モード):



コメント: ポートレートモードの画面と同じです



プロトタイプ:アニメーション。 三。



ビデオはこのリンクで見ることができます。



メイン画面をプログラムします。



この画面で、いくつかの実験を行うことにしました。

1.背景画像とアプリケーション名の間の「ガラス」レイヤーとして、ブルー効果を使用します。

2.承認ボタンは、影付きの画像とともに挿入するのではなく、プログラムで作成する必要があります。



そもそも、純粋な形でbluerを使用しても、望ましい効果は得られません。



トリックする必要があります-別のレイヤーを追加します。 やってみましょう。 追加のレイヤーは灰色になり、目的の効果を得るには(レイアウトのように)、レイヤー自体の透明度を試す必要があります(アルファ)。



アプリケーションのロゴには、簡単な画像が挿入されています。



シャドウを扱うのはずっと面白かったです。実際、同じビューでcornerRadiusとカスタムshadowPathを使用することはできません。 グーグルでドキュメントを読んだ後、別のレイヤーに影を付けることにしました。 目的のステッカー効果を実現するには、ボタンの下の影の境界線を決定する必要があります。そのためには、 GGPathを使用してジオメトリを記憶します。



ボタンの下の影をよく見ると、1つの丸い側面(下)を持つ「ほぼ」長方形で構成されていると推定できます。 直線の作成に問題はないはずです-CGPathAddLineToPoint()およびCGPathMoveToPoint() 。 丸みを帯びた側面については、選択肢がほとんどありません。丸みを帯びた側面をだまして2本の直線に置き換えるか、 CGPathAddArc()メソッドなどを処理します。

最初の方法を使用しても、目的の効果を達成することはできないとすぐに言います。



どの質問に答える必要がありますか?

1. 弦の長さと半径を知って、弦の「静止」角度を決定する方法は

2. ラジアンとは何ですか、また円は0から2Piまではどのように見えますか?



最初の場合、特別な困難は発生しません。 コードの長さを計算するための式があり、半径と角度の変数があり、角度を表現し、必要な値を置き換える必要があります。

2番目の質問では、実装中に、予想していなかったことが発生しました。

ラジアン単位でマークされた角度を持つ円は次のようになります。





カウントダウンは反時計回りに進み、アップルの実装では、カウントダウンは時計回りになります! 私たちと一緒に270、彼らと90。

私はこれを期待していませんでした、多分私は何かを見逃していますか?



影をレンダリングするためのコードは次のとおりです(PS:ただし、Swiftのハイライトはありません)。

//   let shadow = UIView(frame: CGRectMake(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame))) shadow.layer.shadowOpacity = 0.65 shadow.layer.shadowRadius = 4 shadow.layer.shadowColor = UIColor.blackColor().CGColor shadow.layer.shadowOffset = CGSize(width: 0, height: 0) //     let diameter = (CGRectGetWidth(frame) / CGRectGetHeight(frame)) * CGRectGetWidth(frame) let radius = diameter / 2 let xCenter = CGRectGetWidth(frame) / 2 let yCenter = CGRectGetHeight(frame) + radius let angle = 2 * asin(CGRectGetWidth(frame) / (2 * radius)) let endAngle = M_PI + (M_PI - angle) / 2 let startAngle = endAngle + angle let shadowPath = CGPathCreateMutable() CGPathMoveToPoint(shadowPath, nil, 0, CGRectGetHeight(frame) / 2) CGPathAddLineToPoint(shadowPath, nil, frame.size.width, CGPathGetCurrentPoint(shadowPath).y) CGPathAddLineToPoint(shadowPath, nil, CGPathGetCurrentPoint(shadowPath).x, frame.size.height) CGPathAddArc(shadowPath, nil, xCenter, yCenter, radius, startAngle, endAngle, true) CGPathAddLineToPoint(shadowPath, nil, 0, frame.size.height) CGPathCloseSubpath(shadowPath) shadow.layer.shadowPath = shadowPath
      
      







比較できます(左側のレイアウト、右側の実装):





VKで認証画面をプログラムします。



最初に行うことは、 Vkontakte iOS SDKをプロジェクトに統合することです。 Vkontakte iOS SDKは Objective-Cで作成されています。Objective -CをSwiftプロジェクトに統合する方法に関するチュートリアルがあります。



SDKの接続に問題はありませんでした。

認可プロセスは、次のメソッドを呼び出すことで開始されます。

 VKConnector.sharedInstance().startWithAppID("87687678678", permissons: ["photo", "wall", "friends"], webView: self.webView, delegate: self)
      
      









認証に成功すると、アクセストークンが取得され、SDKデータウェアハウスに保存されます。 ユーザーは写真画面に移動します。



写真を実装するための画面をプログラムします



まず、最終結果を示します。







メッシュは削除され、意図的に見えなくなります。



ここにボタンの場所に関するこのようなオプションがありましたが、画面の境界線(ボタンは画面です)をクリックしたときにボタンの横の写真を撮ったことが多く、カメラを切り替えたりグリッドをアクティブにしたりしなかったため、捨てられました:





この記事は、画面がプログラムされた後にのみ補足されるため、残念ながらいくつかのポイントを見逃す可能性があります。



基礎として、タスクを非常によく解決するのに適したUIImagePickerControllerを使用しました。 すべての要素を非表示にし、不要なものをすべて削除し、cameraOverlayViewをインストールしました。

  let cameraView = NAGImagePickerController() cameraView.delegate = cameraView cameraView.sourceType = UIImagePickerControllerSourceType.Camera cameraView.showsCameraControls = false cameraView.allowsEditing = false cameraView.cameraOverlayView = NAGFirstPhotoOverlayView(frame: UIScreen.mainScreen().bounds)
      
      





私にとってちょっとした驚きは、この視覚的なズーム要素の外観でした。





ここでは必要ありませんでしたが、ビューを台無しにしました。さらに、ボタンをブロックしました。削除する必要があります。 頭に浮かんだ最初のメソッドを実装しました:

  let pinchGR = UIPinchGestureRecognizer(target: self, action: nil) addGestureRecognizer(pinchGR)
      
      







それから、SOでさらに興味深いソリューションオプションを検索して、userInteractionをfalseに設定することにしました。



最も興味深い行を考えてみましょう。私の意見では、最も興味深い行はそれから始まります。

 cameraView.delegate = cameraView
      
      







2つの質問:

1. UIImagePickerControllerが表示されたら、表示されるボタンのアニメーションを開始する必要があるため、何らかの方法でイベント/通知を受信する必要があります。つまり、UIImagePickerController自体のviewDidAppearメソッドを書き換える必要があります。

2.写真を撮るか、フロントカメラに切り替える必要があることを何らかの方法でUIImagePickerControllerに通知する必要があります。



2つのソリューションが見つかりました。

1. UIImagePickerControllerをグローバルスコープにします

2. UIImagePickerControllerのサブクラスを作成し、「内部」で発生したイベントに関する通知を送信し、コマンド自体を処理できるように実装します(写真の撮影、カメラの変更など)-NSNotificationCenter



最初の選択肢はほとんど試して見始めましたが、ある時点でこの決定にうんざりし、andいことに気づきました。 最終的に、通知を使用してすべてが実装されました。 非常にシンプルであると同時に柔軟性がありました。

この段階では、NAGImagePickerControllerは次のようになります。

 // // NAGImagePickerController.swift // Qtty // // Created by AndrewShmig on 21/07/14. // Copyright (c) 2014 Non Atomic Games Inc. All rights reserved. // import UIKit let kNAGImagePickerControllerViewDidLoadNotification = "NAGImagePickerControllerViewDidLoadNotification" let kNAGImagePickerControllerViewWillAppearNotification = "NAGImagePickerControllerViewWillAppearNotification" let kNAGImagePickerControllerViewDidAppearNotification = "NAGImagePickerControllerViewDidAppearNotification" let kNAGImagePickerControllerViewDidDisappearNotification = "NAGImagePickerControllerViewDidDisappearNotification" let kNAGImagePickerControllerViewWillDisappearNotification = "NAGImagePickerControllerViewWillDisappearNotification" let kNAGImagePickerControllerFlipCameraNotification = "NAGImagePickerControllerFlipCameraNotification" let kNAGImagePickerControllerCaptureImageNotification = "NAGImagePickerControllerCaptureImageNotification" class NAGImagePickerController: UIImagePickerController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { override func viewDidLoad() { super.viewDidLoad() NSNotificationCenter.defaultCenter().postNotificationName(kNAGImagePickerControllerViewDidLoadNotification, object: self) } override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) NSNotificationCenter.defaultCenter().postNotificationName(kNAGImagePickerControllerViewWillAppearNotification, object: self) } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) NSNotificationCenter.defaultCenter().postNotificationName(kNAGImagePickerControllerViewDidAppearNotification, object: self) NSNotificationCenter.defaultCenter().addObserver(self, selector: "flipCameras", name: kNAGImagePickerControllerFlipCameraNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: "captureImage", name: kNAGImagePickerControllerCaptureImageNotification, object: nil) } override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) NSNotificationCenter.defaultCenter().postNotificationName(kNAGImagePickerControllerViewWillDisappearNotification, object: self) } override func viewDidDisappear(animated: Bool) { super.viewDidDisappear(animated) NSNotificationCenter.defaultCenter().postNotificationName(kNAGImagePickerControllerViewDidDisappearNotification, object: self) } //       func flipCameras() { cameraDevice = (cameraDevice == .Rear ? .Front : .Rear) } //   func captureImage() { takePicture() } //   ,          func imagePickerController(picker: UIImagePickerController!, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]!) { println(info) } deinit { NSNotificationCenter.defaultCenter().removeObserver(self) } }
      
      





今、私たちは静かにcameraOverlayViewにサブスクライブして、UIImagePickerControllerのviewDidAppear:という通知を受け取ります。

  NSNotificationCenter.defaultCenter().addObserver(self, selector: "imagePickerControllerViewDidAppear:", name: kNAGImagePickerControllerViewDidAppearNotification, object: nil)
      
      





うん! これで、コントロールを作成してアニメーションで表示できます。

  createControlElements() //      -  UIView.animateWithDuration(1.0, animations: { self.layout(UIDevice.currentDevice().orientation) })
      
      





同じ方法で、デバイスの向きの変更に関する通知を受信するようにサブスクライブします。

  UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications() NSNotificationCenter.defaultCenter().addObserver(self, selector: "deviceDidChangeOrientation:", name: UIDeviceOrientationDidChangeNotification, object: nil)
      
      





なぜここで今それを行うのですか? 実際、アプリケーションの起動時にデバイスが任意の向きにある場合、向きの最初の通知はありません。つまり、これが要素の最初の表示かどうかを決定する変更処理メソッドにフラグを追加する必要があるということです。 最初の外観でのみアニメーションが再生されます。 不要なifを追加し、フラグ変数を入力する必要があります。結果が気に入らず、上に示したものに到達しました。



デバイスの向きの変更を処理する方法では、1)画面の目的の角にボタンを配置する2)ボタンの回転をデバイスの回転方向にアニメーション化します。

  func layout(orientation: UIDeviceOrientation) { println(__FUNCTION__) switch orientation { case .Portrait: leftButton.frame = position(leftButton, atCorner: .UpperLeftCorner) rightButton.frame = position(rightButton, atCorner: .UpperRightCorner) case .PortraitUpsideDown: leftButton.frame = position(leftButton, atCorner: .LowerRightCorner) rightButton.frame = position(rightButton, atCorner: .LowerLeftCorner) case .LandscapeRight: leftButton.frame = position(leftButton, atCorner: .LowerLeftCorner) rightButton.frame = position(rightButton, atCorner: .UpperLeftCorner) default: //    leftButton.frame = position(leftButton, atCorner: .UpperRightCorner) rightButton.frame = position(rightButton, atCorner: .LowerRightCorner) } var angle: CGFloat switch (prevDeviceOrientation, orientation) { case (.Portrait, .LandscapeLeft), (.LandscapeRight, .Portrait), (.PortraitUpsideDown, .LandscapeRight), (.LandscapeLeft, .PortraitUpsideDown): angle = CGFloat(M_PI) / 2.0 case (.Portrait, .LandscapeRight), (.LandscapeLeft, .Portrait), (.LandscapeRight, .PortraitUpsideDown), (.PortraitUpsideDown, .LandscapeLeft): angle = -CGFloat(M_PI) / 2.0 case (.Portrait, .PortraitUpsideDown), (.PortraitUpsideDown, .Portrait), (.LandscapeLeft, .LandscapeRight), (.LandscapeRight, .LandscapeLeft): angle = CGFloat(M_PI) default: angle = 0.0 } let rotate = CGAffineTransformMakeRotation(angle) UIView.animateWithDuration(0.3, animations: { self.leftButton.transform = CGAffineTransformConcat(self.leftButton.transform, rotate) self.rightButton.transform = CGAffineTransformConcat(self.rightButton.transform, rotate) }) }
      
      







しばらくの間、線の描画を選択していましたが、layer.alpha = 0.0の線が表示されない理由を理解できませんでした。 ウェッジし直し、backgroundColorをclearColor()に設定すると、すべてが適切に配置されました。

線の描画はdrawRect:メソッドにあり、次のようになります。

  let screenHeight = CGRectGetHeight(UIScreen.mainScreen().bounds) let screenWidth = CGRectGetWidth(UIScreen.mainScreen().bounds) let context = UIGraphicsGetCurrentContext() CGContextSetLineWidth(context, 1.0) CGContextSetShadow(context, CGSizeZero, 1.0) CGContextSetStrokeColorWithColor(context, UIColor(red: 0.803, green: 0.788, blue: 0.788, alpha: 0.5).CGColor) //    ( ) let horizontalLines = screenHeight / kVisualBlocks let countHLines = screenHeight / horizontalLines for i in 1..<countHLines { CGContextMoveToPoint(context, 0, i * horizontalLines) CGContextAddLineToPoint(context, screenWidth, i * horizontalLines) } //    ( ) let verticalLines = screenWidth / kVisualBlocks let countVLines = screenWidth / verticalLines for i in 1..<countVLines { CGContextMoveToPoint(context, i * verticalLines, 0) CGContextAddLineToPoint(context, i * verticalLines, screenHeight) } CGContextStrokePath(context)
      
      







画面が実装された後、 Swiftブログはアクセス修飾子に関する情報を投稿しました。

アプリケーションの実際のソースコードはGitHubで見つけることができます。記事の最後にある、リポジトリへのリンクを参照してください。



フィルターオーバーレイ画面のプログラミング



ユーザーが写真を撮った後、次のメソッドが呼び出されます。

  func imagePickerController(picker: UIImagePickerController!, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]!) { NSNotificationCenter.defaultCenter().postNotificationName(kNAGImagePickerControllerUserDidCaptureImageNotification, object: self, userInfo: info) }
      
      







写真が撮影され、コントロールを新しいものに変更する必要があるという通知を追跡オブジェクト(レイヤー)に送信します(別の画面に移動します)。

通知を「処理」する方法は次のとおりです。

  //      ,   //   func hideControlElements(notification: NSNotification) { //       ,    //        //       deviceDidChangeOrientation NSNotificationCenter.defaultCenter().removeObserver(self) //   UIImagePickerController   (notification.object as NAGImagePickerController).view.userInteractionEnabled = false //   if !superview.viewWithTag(kGridViewTag).hidden { invertGridVisibility() } //     UIView.animateWithDuration(1.0, animations: { self.layout(self.prevDeviceOrientation, animation: .BeforeAnimation) }, completion: { _ in let imagePickerController = notification.object as NAGImagePickerController imagePickerController.cameraOverlayView = NAGPhotoOverlayView(imageInfo: notification.userInfo, frame: self.frame) }) }
      
      







さらに、次のように進む予定です。最終写真を含むレイヤーを作成します。このレイヤーには、コントロール要素の表示と変更を担当する別のUIViewがあります。



NAGPhotoOverlayViewには(今のところ)2つのプロパティがあります:

1. UIImageView

2. UIImage

そして次のように宣言されます:

  var photoView: UIImageView! var originalPhoto: UIImage!
      
      







初期化は次のとおりです。

  init(imageInfo: [NSObject : AnyObject]!, frame: CGRect) { super.init(frame: frame) originalPhoto = imageInfo[UIImagePickerControllerOriginalImage] as UIImage photoView = createPhotoLayer(image: originalPhoto) addSubview(photoView) NSNotificationCenter.defaultCenter().addObserver(self, selector: "deviceDidChangeOrientation:", name: UIDeviceOrientationDidChangeNotification, object: nil) }
      
      







画像を正しく回転させるために、デバイスの回転に関する通知を受け取るために現在のレイヤーに署名します。 デフォルトでは、UIImagePickerControllerを介して撮影された写真は常にポートレートモードで表示されますが、これは表示時に画像圧縮が行われることに注意してください。 デバイスの処理方法は次のようになります。

  func deviceDidChangeOrientation(notification: NSNotification) { rotateImage(toOrientation: UIDevice.currentDevice().orientation) }
      
      





メイン画像回転コード:

  private func rotateImage(toOrientation orientation: UIDeviceOrientation) { let orientation = UIDevice.currentDevice().orientation let photoOrientation = originalPhoto.imageOrientation let isLandscapedPhoto = photoOrientation == .Down || photoOrientation == .Up if isLandscapedPhoto && (orientation == .LandscapeLeft || orientation == .LandscapeRight) { photoView.image = UIImage(CGImage: originalPhoto.CGImage, scale: originalPhoto.scale, orientation: orientation == .LandscapeRight ? .Right : .Left) } else if !isLandscapedPhoto && (orientation == .Portrait || orientation == .PortraitUpsideDown){ photoView.image = UIImage(CGImage: originalPhoto.CGImage, scale: originalPhoto.scale, orientation: orientation == .Portrait ? .Right : .Left) } }
      
      







何してるの? まず、写真の向きを確認してみましょう。 写真が横向きモードの場合、縦向きモードの写真-.Portraitおよび.PortraitUpsideDownのみの場合、デバイス.LandscapeLeftおよびLandscapeRightの位置に対してのみ回転を許可する必要があります。

UIImageインスタンスのimageOrientationプロパティを直接変更できないため、新しいオブジェクトを作成する必要があります。



次のステップでは、コントロール要素を含むレイヤーを作成し、要素の外観をアニメーション化し、フィルターを選択して画像に適用します。



終わり



疲れた...記事を削除しないことにしましたが、それでも公開します。



ソースはGitHubのこのリンクにあります



おわりに



要点が見えないことはしないでください。



ハラジテリ、ご清聴ありがとうございました。



All Articles