独創アプリ開発日記 77日目 フォント調整

今日もテキスト漫画サイトのガワネイティブアプリ化です。今回はちょっとフォントサイズを調整してみました。

iPhoneやmacの環境において、前は縦に間延びした感じでしたが、少し良くなったと思います。

今後のアプリ化作業ですが、ちょっと色々と調整作業がありすぎて取り止めがなくなってきたので一旦作業項目を洗い出してみました。

1.つかいかた画面の作成
2.スマホで自動ログインして「じぶんのまんが」「みんなのまんが」「他の人のまんが」の表示モード作り込み
3.リスト画面のスマホ特化デザイン
4.編集画面のスマホ特化デザイン
5.つかいかたーーーコピー方法
6.つかいかたーーー編集方法
7.つかいかたーーーQ&A
8.つかいかたーーーあなたのID
9.秘密の作業その1
10.秘密の作業その2

1日に2項目消化すれば、冬休み中に終わる筈だ!
筈だ・・・
筈・・
は・・
z

 チャーハン作るよ!!! 
   ∧ ,, ∧ 
   (;`・ω・) 。・゚・⌒) 
   /   o━ヽニニフ)) 
  しー-J

独創アプリ開発日記 76日目 ボタンエフェクト

今日もテキスト漫画サイトのガワネイティブアプリ化です。

今回は、appleからrejectを喰らわないよう、よりネイティブアプリっぽくするために、animsitionというライブラリを使って画面遷移時のエフェクトを付けようとしました。

が、テキスト漫画のサイトにはうまく適用できませんでした。

そこで、自力でエフェクトを付けていました。

まあ、

・メニュータップと同時に選択メニュー文字に背景色をセット
・画面全体をopacityの指定によりだんだん透明化
・timerを使って0.5秒後くらいに次の画面に飛ぶ
・遷移後の画面でもopacityの指定により画面が徐々に現れる

というような単純な処理ですが・・・

でもこれでよりネイティブアプリっぽくなったと思います。

 チャーハン作るよ!!!
   ∧ ,, ∧
   (;`・ω・) 。・゚・⌒)
   /   o━ヽニニフ))
  しー-J

独創アプリ開発日記 75日目 タイトル画面完成

テキスト漫画サイトのガワネイティブアプリのタイトル画面が完成しました。

・3Dタッチが有効になっていたので、無効化しました。
・テキスト漫画タップ時に、テキストの選択領域?としてグレーの色が付いたのですが、色が付かないようにしました。
・テキスト漫画タップ時に、黒色の吹き出しでテキスト漫画を表示する処理を行わないオプションを追加し、タイトル画面の場合は吹き出しを表示しないようにしました。

あ、あとできればメニューボタン押した時にエフェクトとかかけたいんだけど、ガワネイティブの場合ってどうすればいいのかな・・・

   γ⌒)? 
    |.|"´  
    |.|  ./⌒ヽ____¶___ 
    |.| /( 'ん`  )   ¶//|  /| 
    U_⊆__⊆_ )_   / ̄|/// 
  /┌────┐|. /'`) // 
/( / ≡≡≡ .//(__/// 
|  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ |/

独創アプリ開発日記 73日目 画面装飾

今日はクリスマスですね。ちまちまアプリ作ってる場合ではありません。今日くらいはぱーっと遊びましょう。

はい、というわけで今回はアプリのトップ画面が文字だけで寂しいので、テキスト漫画自身を使って装飾してました。

あ、文字だけで寂しいとか言ったけど、結局文字しかなかった。

    :/ ̄| :  :  ./ /  #  ;,;  ヽ 
  :. | ::|    /⌒  ;;#  ,;.;::⌒ : ::::\ : 
    | ::|:  / -==、   '  ( ●) ..:::::| 
  ,―    \   | ::::::⌒(__人__)⌒  :::::.::::| :  
 | ___)  ::|: ! #;;:..  l/ニニ|    .::::::/ 
 | ___)  ::|  ヽ.;;;//;;.;`ー‐'ォ  ..;;#:::/ 
 | ___)  ::|   .>;;;;::..    ..;,.;-\ 
 ヽ__)_/ :  /            \   
 

独創アプリ開発日記 72日目 固定画面

今日はクリスマスイブですね。ちまちまアプリ作ってる場合ではありません。今日くらいはぱーっと遊びましょう。

はい、というわけで、今回はアプリのトップ画面を作っていました。

スクロールしない画面です。

コードは以下のような感じです。テキスト等を画面のどの位置に配置するか、画面のサイズに対する比率を指定して配置するようにしました。

やろうと思えば絶対座標で位置を指定出来るので、まるでネイティブアプリを作っているような錯覚に陥ります。

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
        <style type="text/css">
        .vintage {
            background: #EEE                         url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAIAAAAmkwkpAAAAHklEQVQImWNkYGBgYGD4//8/A5wF5SBYyAr+//8PAPOCFO0Q2zq7AAAAAElFTkSuQmCC) repeat;
            text-shadow: 5px -5px black, 4px -4px white;
            font-weight: bold;
            -webkit-text-fill-color: transparent;
            -webkit-background-clip: text
        }
        .title_label {
            font-size: 48px;
            text-align: center;
            width: 400px;
            line-height:150px;
        }
        .txtbase {
            position: absolute;
            -moz-user-select: none; /* Firefox */
            -ms-user-select: none; /* Internet Explorer */
            -khtml-user-select: none; /* KHTML browsers (e.g. Konqueror) */
            -webkit-user-select: none; /* Chrome, Safari, and Opera */
            -webkit-touch-callout: none; /* Disable Android and iOS callouts*/
        }
        .btn {
            font-size: 36px;
            text-align: center;
            width: 400px;
            line-height:100px;
        }
        </style>
        <title>TextManga</title>
    </head>
    <body>
        <span id="title" class="title_label txtbase vintage">てきすとまんが</span>
        <a id="mine_btn" class="btn txtbase vintage" href="<?php echo url(''); ?>">じぶんのまんが</a>
        <a id="everyone_btn" class="btn txtbase vintage" href="<?php echo url(''); ?>">みんなのまんが</a>
        <a id="other_btn" class="btn txtbase vintage" href="<?php echo url(''); ?>">他の人のまんが</a>
        <a id="help_btn" class="btn txtbase vintage" href="https://minnano.app/support/2015/02/01/usage_of_textmanga_1/">つかいかた</a>
        <script type="text/javascript" src="<?php echo env('ASSETS_PATH').'/js/jquery-2.1.0.min.js'; ?                >">
        </script>
        <script type="text/javascript">
        // スクロールを無効にする
        $(window).on('touchmove.noScroll', function(e) {
            e.preventDefault();
        });
        function adjust() {
            var w = $(window).width();
            var h = $(window).height();
            if (w < h) {
                // タイトル
                setPos("#title", 0.5, 0.2, w, h);
                // 各ボタン
                var y_base = 0.5;
                var pitch = 0.12;
                setPos("#mine_btn", 0.5, y_base + pitch * 0, w, h);
                setPos("#everyone_btn", 0.5, y_base + pitch * 1, w, h);
                setPos("#other_btn", 0.5, y_base + pitch * 2, w, h);
                setPos("#help_btn", 0.5, y_base + pitch * 3, w, h);
            } else {
                // タイトル
                setPos("#title", 0.5, 0.05, w, h);
                // 各ボタン
                var y_base = 0.4;
                var pitch = 0.2;
                setPos("#mine_btn", 0.5, y_base + pitch * 0, w, h);
                setPos("#everyone_btn", 0.5, y_base + pitch * 1, w, h);
                setPos("#other_btn", 0.5, y_base + pitch * 2, w, h);
                setPos("#help_btn", 0.5, y_base + pitch * 3, w, h);
            }
        }
        function setPos(selector, rate_x, rate_y, w, h) {
            var ih = parseInt($(selector).css("height"));
            var iw = parseInt($(selector).css("width"));
            $(selector).css("left", (w - iw) * rate_x + "px");
            $(selector).css("top", (h - ih) * rate_y + "px");
        }
        $(document).ready(function () {
            adjust();
        });
        $(window).resize(function () {
            adjust();
        });
        </script>
    </body>
</html>

なお、リンク先はまだ全然作っていません。

    :/ ̄| :  :  ./ /  #  ;,;  ヽ 
  :. | ::|    /⌒  ;;#  ,;.;::⌒ : ::::\ : 
    | ::|:  / -==、   '  ( ●) ..:::::| 
  ,―    \   | ::::::⌒(__人__)⌒  :::::.::::| :  
 | ___)  ::|: ! #;;:..  l/ニニ|    .::::::/ 
 | ___)  ::|  ヽ.;;;//;;.;`ー‐'ォ  ..;;#:::/ 
 | ___)  ::|   .>;;;;::..    ..;,.;-\ 
 ヽ__)_/ :  /            \   
 

独創アプリ開発日記 71日目 アプリ専用画面

今日も引き続きテキスト漫画サイトのアプリ化作業です。

今回は、アプリから同サイトを参照した場合、アプリに不要な機能を削除していました。

・アプリは端末IDを元に自動でログインするため「ログイン」や「アカウント作成」を削除

・「手動コピー」のリンクは、自動コピーができないIEなどのブラウザ用ですが、アプリなら必ず自動コピーが成功するので削除

・ページ下部の「uka.appleサイトへのリンク」を削除

とてもシンプルな画面になりました。

これでアプリ申請したいところですが、まだWebっぽいページなのでもうちょっと改良します。

以下画面の作成を予定しています。

・タイトル画面

以下のメニューを選べます。

[自分の漫画]—自分が作った漫画をリスト表示します。
[みんなの漫画]—みんなで編集可能な漫画をリスト表示します。
[他の人の漫画]—自分以外の人が作った漫画をリスト表示します。
[使い方]—使い方画面に遷移します。

・使い方画面

[コピーの仕方]—テキスト漫画の貼り付け手順を説明します。
[編集の仕方]—テキスト漫画の作り方を説明します。
[Q&A]—このページの内容を表示します。
[あなたのID]—IDを表示します。また、IDの入力フィールドを用意して他の端末からの移行を可能とします。

上記2つの”スクロールしない”画面を作成すれば、アプリっぽくなると思います。Webサイトをそのままアプリ化するとRejectされるという噂ですが、上記画面を作ればRejectされないはず!!

            i⌒i スッ
             | 〈 
     Apple様  / .フ
      ( ^+^)/  |  
    /      /  ノ
   / /\   /   |
 _| ̄ ̄ \ /.  ノ__
 \ ̄ ̄ ̄ ̄ ̄ ̄( ^ν^)
  ||\            \
  ||\|| ̄ ̄ ̄ ̄ ̄ ̄ ̄|| ̄
  ||  || ̄ ̄ ̄ ̄ ̄ ̄ ̄||
     .||              || 

独創アプリ開発日記 70日目 alert, confirm, prompt

今日も引き続きテキスト漫画のガワネイティブアプリ化です。

ガワネイティブアプリでWebを表示するのに多用されるWKWebViewですが、JavaScriptのalert,confirm,promptに関してはデフォルトで何も表示してくれません。

alert,confirm,promptのダイアログを表示させるには UIAlertAction で適切に処理してあげる必要があります。

 

と言っても定型でほぼ処理コードは決まっているため、以下のように書いてあげれば大丈夫です。Swift4のコードです。


import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate {

    private var _webView : WKWebView!
    〜略〜
    override func viewDidLoad() {
        super.viewDidLoad()
        〜略〜
        _webView.uiDelegate = self
        〜略〜
    }

    func webView(_ _webView: WKWebView, runJavaScriptAlertPanelWithMessage alert: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        
        let alertController = UIAlertController(title: "", message: alert, preferredStyle: .alert)
        let otherAction = UIAlertAction(title: "OK", style: .default) {
            action in completionHandler()
        }
        alertController.addAction(otherAction)
        self.present(alertController, animated: true, completion: nil)
    }
    
    func webView(_ _webView: WKWebView, runJavaScriptConfirmPanelWithMessage confirm: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        
        let alertController = UIAlertController(title: "", message: confirm, preferredStyle: .alert)
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) {
            action in completionHandler(false)
        }
        let okAction = UIAlertAction(title: "OK", style: .default) {
            action in completionHandler(true)
        }
        alertController.addAction(cancelAction)
        alertController.addAction(okAction)
        self.present(alertController, animated: true, completion: nil)
    }
    
    func webView(_ _webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
        
        let alertController = UIAlertController(title: "", message: prompt, preferredStyle: .alert)
        
        alertController.addTextField { (textField) in
            textField.text = defaultText
        }
        alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) in
            completionHandler(nil)
        }))
        alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
            if let textField = alertController.textFields?.first?.text {
                completionHandler(textField)
            } else {
                completionHandler(defaultText)
            }
        }))
        self.present(alertController, animated: true, completion: nil)
    }    
    〜略〜
}

 
 
 
    _,,..,,,,_
   / ,’ 3  `ヽーっ
   l   ⊃ ⌒_つ
    `’ー—‐””'”