LoginSignup
18
12

More than 5 years have passed since last update.

【iOS】MarkdownをHTMLにレンダリングするライブラリを使って、Qiitaの記事をMarkdownで表示してみた

Posted at

はじめに

iOS Second Stage Advent Calendar20日目の記事です。

個人的には7記事目になります。

本題

Markdownを描画するライブラリを見つけたので、それを使用してQiitaの記事を用事するサンプルをつくってみました。

ライブラリはmdiep/MMMarkdownです。

サンプルプロジェクトは以下においておいきました。

AdventCalendar2015/SampleMMMarkdown at master · ryokosuge/AdventCalendar2015

スクリーンショット

  • 一覧

    スクリーンショット 2015-12-20 0.27.39.png

  • 詳細

    スクリーンショット 2015-12-20 0.28.07.png

こんな感じで表示できました。

導入

MMMarkdownCarthageか自分でコピーするとのことなのでCarthageを使用して導入しました。

Carthageでの導入方法などは世にたくさん出ているので、そちらを参考にしてください。

ちなみに今回使ったライブラリは以下になります。

Cartfile
## Himotoki
## source: https://github.com/ikesyo/Himotoki
github "ikesyo/Himotoki" ~> 1.3

## Alamofire
## source: https://github.com/Alamofire/Alamofire
github "Alamofire/Alamofire" ~> 3.0

## BrightFutures
## source https://github.com/Thomvis/BrightFutures
github "Thomvis/BrightFutures" ~> 3.2

## MMMarkdown
## source https://github.com/mdiep/MMMarkdown
github "mdiep/MMMarkdown"

最近Himotokiを使うのが自分の中でのブームになっています。

ソースコード

QiitaのAPIから記事のMarkdownの値が取得できるので、それを使ってやりました。

Himotokiを使ってレスポンスを構造体に変換

以下はQiitaAPIから取得できるレスポンスを保持する構造体です。

ItemResponse.swift

import Foundation
import Himotoki

struct TagResponse: Decodable {
    let name: String
    let versions: [String]

    static func decode(e: Extractor) throws -> TagResponse.DecodedType {
        return try TagResponse(name: e <| "name", versions: e <|| "versions" )
    }

}

struct UserResponse: Decodable {

    let description: String?
    let facebookID: String?
    let followeesCount: Int
    let followersCount: Int
    let githubLoginName: String?
    let id: String
    let itemsCount: Int
    let linkedinID: String?
    let location: String?
    let name: String
    let organization: String?
    let permanentID: Int
    let profileImageURL: String
    let twitterScreenName: String?
    let websiteURL: String?

    static func decode(e: Extractor) throws -> UserResponse.DecodedType {
        return try UserResponse(description: e <|? "description", facebookID: e <|? "facebook_id", followeesCount: e <| "followees_count", followersCount: e <| "followers_count", githubLoginName: e <|? "github_login_name", id: e <| "id", itemsCount: e <| "items_count", linkedinID: e <|? "linkedin_id", location: e <|? "location", name: e <| "name", organization: e <|? "organization", permanentID: e <| "permanent_id", profileImageURL: e <| "profile_image_url", twitterScreenName: e <|? "twitter_screen_name", websiteURL: e <|? "website_url")
    }

}

struct ItemResponse: Decodable {

    let renderedBody: String
    let body: String
    let coediting: Bool
    let createdAt: String
    let id: String
    let privateItem: Bool
    let tags: [TagResponse]
    let title: String
    let updatedAt: String
    let URL: String
    let user: UserResponse

    static func decode(e: Extractor) throws -> ItemResponse.DecodedType {
        return try ItemResponse(renderedBody: e <| "rendered_body", body: e <| "body", coediting: e <| "coediting", createdAt: e <| "created_at", id: e <| "id", privateItem: e <| "private", tags: e <|| "tags", title: e <| "title", updatedAt: e <| "updated_at", URL: e <| "url", user: e <| "user")
    }

}

ItemResponseの中のbodyの値が投稿のMarkdownテキストになっています。

詳しくはQiita API v2 ドキュメントを参照ください。

ではそれを描画するのに MMMarkdownを使用してみます。

Markdownの描画

以下のページを参考にしてやってみました。

initWithFunk: by Eric Allam

描画にはUITextViewを使用しています。

それのソースコードは以下になります。

DetailViewController.swift
import UIKit
import MMMarkdown

class DetailViewController: UIViewController {

    static func instantiateViewControllerWithItem(item: ItemResponse) -> DetailViewController {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let viewController = storyboard.instantiateViewControllerWithIdentifier("DetailViewController") as! DetailViewController
        viewController.item = item
        return viewController
    }

    @IBOutlet weak var textView: UITextView!
    private var item: ItemResponse!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        setupView()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

/// MARK: - private methods.
extension DetailViewController {

    private func setupView() {
        if let htmlString = try? MMMarkdown.HTMLStringWithMarkdown(item.body) {
            let style = "<style>img { max-width: 300px; height: auto; }</style>\n"
            let body = style + htmlString
            print(body)
            if let data = body.dataUsingEncoding(NSUnicodeStringEncoding) {
                let attribute = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
                if let attributeText = try? NSAttributedString(data: data, options: attribute, documentAttributes: nil) {
                    textView.attributedText = attributeText
                }
            }
        }
        textView.editable = false
    }

}

DetailViewControllersetupView()の中でMarkdownを表示するテキストに変換しています。

これだけで表示することができました。

余談

let style = "<style>img { max-width: 300px; height: auto; }</style>\n"を追加しているのは 画像がそのままのサイズで表示されているからです。

比率を保ったまま、表示するので適当に設置してみました。

あとUITextViewですが、かなり色々できるクラスになっています。

以下のページがわかりやすく紹介してくれているので参考にするといいかと思います。

iOS - [Objective-C] HTMLを使って文章をスタリングする - Qiita

終わりに

Markdownを返してくるサービス(API)ってあまり見かけませんが、自社サービスとか社内サービスとかにはいいかもですね。

以上になります。

参考

18
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
12