ちょっと話題の記事

[iOS 11][ARKit] UIViewをテクスチャーにしてTwitterクライアントを作ってみる

2017.10.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

ARKitの登場によって、多くのデバイスで手軽にARを楽しめるようになったと思います。Web上でも、日々、色々なアプリが紹介されており、「どれも皆、作って見たい!」という衝動に駆られて忙しいかぎりです。

そして、いよいよ3Dオブジェクトの表現が重要であることを痛感しています。

基本的なシェードで作成するオブジェクトは、変形とテクスチャーを駆使することになりますが、今回は、このテクスチャーにUIViewを貼ってみました。

最初に、参考に作って見たアプリを見てやってください。 普通のTwitterクライアントで表示されるようなタイムラインを仮想オブジェクトにしてみました。

2 UIViewのオブジェクト

仕組みは、簡単で、UIViewを画像化してテクスチャーに使っているだけです。

描画するためのUIViewを、あらかじめ、非表示でアプリ内に作成しておき、そこに通常通り描画します。そして、それを画像(UIImage)に変換し、オブジェクトのテクスチャーに適用しているわけです。

非表示のUIVIewは、画像変換できなかったので、一瞬だけ、表示状態にしていますが、実機では、気になるようなものでは無いようでした。

UIViewを、UIImageに変換しているコードは、以下のとおりです。

参考にさせて頂きました:しめ鯖日記 -UIViewにUIImageへの変換メソッドを追加する(Swift)-

func createImage(view:UIView) -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(view.frame.size, false, 0)
    guard let context = UIGraphicsGetCurrentContext() else {
        return nil
    }
    view.isHidden = false // 画像を取得する間だけ表示
    view.layer.render(in: context)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    view.isHidden = true // 再び非表示
    return image
}

また、取得した画像(UIImage)を貼って作成するTweetノードは、以下のようになっています。

class TweetNode: SCNNode {

    init(image:UIImage, panelColor: UIColor, width: CGFloat, panelThickness: CGFloat) {
        super.init()

        let panelNode = SCNNode(geometry: SCNBox(width: width, height: width * 0.5, length: panelThickness, chamferRadius: 0))

        let material_front = SCNMaterial()
        material_front.diffuse.contents = image
        let material_other = SCNMaterial()
        material_other.diffuse.contents = panelColor
        panelNode.geometry?.materials = [material_front, material_other, material_other, material_other, material_other, material_other]

        addChildNode(panelNode)
    }

    // ・・・略・・・
}

TweetNodeは、画像、パネルの色、サイズ(幅)、パネルの厚みを指定して生成されます。

パネルは、SCNBoxで作成され、テクスチャーとして、正面に指定した画像、その他の面に指定した色が適用されています。

縦のサイズは、内部で横幅の1/2で固定されています。

3 STTwitter

Twitterのタイムライン取得は、STTwitterを使用させて頂きました。

https://github.com/nst/STTwitter

STTwitterは、CocoaPodsでインストールが可能です。

pod 'STTwitter'

利用方法は、以下のとおりです。

import STTwitter

public final class Twitter {

    let consumerKey = "カスタマーキー"
    let consumerSecret = "カスタマーシークレット"
    let username = "ユーザ名"
    let password = "パスワード"

    func get(query: String, complete: @escaping ([Tweet]?)->Void ){

        let api = STTwitterAPI(oAuthConsumerKey: consumerKey, consumerSecret: consumerSecret, username: username, password: password)
        api?.fetchAndFollowCursors(forResource: "search/tweets.json", httpMethod: "GET", baseURLString: "https://api.twitter.com/1.1", parameters: ["q":query], uploadProgressBlock: nil, downloadProgressBlock: nil, successBlock: { (request, requestHeaders, responsHeaders, response, morePagesToCome, stop) in
            // 結果の受信
            var tweets: [Tweet] = []
            let json = response as! NSDictionary
            let statuses = json["statuses"] as! NSArray
            for status in statuses as! [NSDictionary] {
                let text = status["text"] as! String
                let user = status["user"] as! NSDictionary
                let created_at = status["created_at"] as! String
                let profile_image_url = user["profile_image_url"] as! String
                let name = user["name"] as! String
                let screen_name = user["screen_name"] as! String
                tweets.append(Tweet(name: name, screen_name: screen_name, profile_image_url: profile_image_url, text: text, created_at: created_at))
            }
            complete(tweets)
        }, pause: { (nextRequestDate) in
            // ロード中
        }, errorBlock: { (request, requestHeaders, responseHeaders, error) in
            print("ERROR:\(String(describing: error))") // エラー
            complete(nil)
        })

    }
}

取得した結果は、Tweetクラスで取得しました。

class Tweet {
    let name: String!
    let screen_name: String!
    let profile_image_url: String!
    let text: String!
    let created_date: NSDate!

    init(name: String, screen_name: String, profile_image_url: String, text: String, created_at: String) {
        self.name = name
        self.screen_name = screen_name
        self.profile_image_url = profile_image_url
        self.text = text

        let inFormatter = DateFormatter()
        inFormatter.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy"
        self.created_date = inFormatter.date(from: created_at)! as NSDate
    }
}

4 最後に

UIViewの表示を、そのままノードに使用できると、結構便利なのでは無いでしょうか。

最後に、もう一つ、作成したサンプルを紹介させて下さい。 下記は、最近、弊社のイベントでよく登場する「クラスメソッドのおみくじ」です。Web上のコンテンツをWKWebViewで表示し、それを、画像化して使用しています。

「クラスメソッドのおみくじ」を、近所の駐車場で引いてみる

5 参考リンク


しめ鯖日記 -UIViewにUIImageへの変換メソッドを追加する(Swift)-
[OS X] 透過型のTwitterクライアントを作ってみた
[iOS 11] はじめてのARKit #WWDC2017
[iOS 11][ARKit] 距離の計測について #WWDC2017
[iOS 11][ARKit] 平面の検出について #WWDC2017
[iOS 11][ARKit] 物理衝突を実装して、キューブを落として見る #WWDC2017
[iOS 11][ARKit] 空間に3Dテキストを表示してみる #WWDC2017
[iOS 11] ARKitでソファー設置からあの子の身長測定まで色々やってみた
[iOS 11][ARKit] 近所の駐車場で、大型ディスプレイでビデオを見る!
[iOS11][ARKit] オブジェクトの位置と回転「常にこっちを向いている怪獣」
[iOS11][ARKit] SCNBoxとSCNTextでラベルみたいなノードを作成してみました