ホーム

Javascript を WKWebView の中で使う Swift3

WKWebViewをaddSubviewしたviewの中でJavascriptを実行してみたいと思います。概念的な理解を優先するために、クリック処理などのちょっと複雑な処理は書かず、ローカルでhtml,css,JavascriptをXcodeに取り込み、下記のような紙吹雪アニメーションをJavascriptで表現してみたいと思います。Javascriptの優れたUIの力をお借りしたいと思います(紙吹雪はただのコピペテンプレートです)

on.gif

ファイルの状況

スクリーンショット 2017-06-26 14.02.11.png

Swift3

まずはWebKitをインポートます

import WebKit

WKNavigationDelegateを継承します

class ViewController: UIViewController, WKNavigationDelegate {

WKWebViewを作ります

let webView: WKWebView = WKWebView()

    override func viewDidLoad() {
        super.viewDidLoad()

        webView.frame = view.bounds
        webView.navigationDelegate = self
        webView.scrollView.bounces = false
        view.addSubview(webView)

viewDidLoadの中でhtmlを読み込みます

let url = Bundle.main.url(forResource: "index", withExtension: ".html")!
        let urlRequest = URLRequest(url: url)
        webView.load(urlRequest)

    }

完成形

import UIKit
//import JavaScriptCore
import WebKit

class ViewController: UIViewController, WKNavigationDelegate {

    let webView: WKWebView = WKWebView()

    override func viewDidLoad() {
        super.viewDidLoad()

        webView.frame = view.bounds
        webView.navigationDelegate = self
        webView.scrollView.bounces = false
        view.addSubview(webView)

        let url = Bundle.main.url(forResource: "index", withExtension: ".html")!
        let urlRequest = URLRequest(url: url)
        webView.load(urlRequest)

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }
}




html

<!DOCTYPE html>
<html lang="ja">
    <head>
        <title>Title</title>
         <meta charset="utf-8">
            <!--    画面の大きさを制御している-->
            <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0" />
            <!--    <link rel="stylesheet" type="text/css" href="main.css" />-->
            </head>
    <body>
        <h1>Call Javascript from Swift3 On Xcode8</h1>
<!--        </br>-->
<!--        </br>-->
<!--        </br>-->
<!--        </br>-->
<!--        <div id="col">Javascripでこの部分を赤色にします</div>-->
        <canvas id="canvas"></canvas>
        <script type="text/javascript" src="main.js"></script>
    </body>
</html>

css

body { background: lightgray; }

Javascript

//即時関数
(function() {

 //document.getElementById("col").style.color = "red";










 /*


  下記コピペ


  */


 // forked from dobin's "forked: [canvas] 紙ふぶき" http://jsdo.it/dobin/qEcf
 // forked from Shingo.Shibamoto's "forked: [canvas] 紙ふぶき" http://jsdo.it/Shingo.Shibamoto/llOI
 // forked from teetteet's "forked: [canvas] 紙ふぶき" http://jsdo.it/teetteet/r8As
 // forked from ikr7's "forked: [canvas] 紙ふぶき" http://jsdo.it/ikr7/nutG
 // forked from tsubao's "[canvas] 紙ふぶき" http://jsdo.it/tsubao/iR2g
    var DEF_KAMIKIRE_MAX = 1000;

    var kamikire_array = [];
    var cvs;
    var ctx;
    var stageWidth, stageHeight;
    var resizeFlg = true;
    //
    window.onload = function()
    {
 init();
    }


 function hsv2rgb(hue, sat, val) {
 var red, grn, blu, i, f, p, q, t;
 hue%=360;
 if(val==0) {return({r:0, g:0, v:0});}
 sat/=100;
 val/=100;
 hue/=60;
 i = Math.floor(hue);
 f = hue-i;
 p = val*(1-sat);
 q = val*(1-(sat*f));
 t = val*(1-(sat*(1-f)));
 if (i==0) {red=val; grn=t; blu=p;}
 else if (i==1) {red=q; grn=val; blu=p;}
 else if (i==2) {red=p; grn=val; blu=t;}
 else if (i==3) {red=p; grn=q; blu=val;}
 else if (i==4) {red=t; grn=p; blu=val;}
 else if (i==5) {red=val; grn=p; blu=q;}
 red = Math.floor(red*255);
 grn = Math.floor(grn*255);
 blu = Math.floor(blu*255);
 return ({r:red, g:grn, b:blu});
 }


    //初期処理
    function init()
    {
 cvs = document.getElementById("canvas");

 //ウィンドウサイズ設定
 stageWidth = window.innerWidth ? window.innerWidth : $(window).width();
 stageHeight = window.innerHeight ? window.innerHeight : $(window).height();
 cvs.width = stageWidth;
 cvs.height = stageHeight;

 ctx = cvs.getContext("2d");
 ctx.fillStyle = "#fff";
 ctx.fillRect(0, 0, cvs.width, cvs.height);

 //生成
 for(var i=0; i<DEF_KAMIKIRE_MAX; i++){
 var kami = new Kamikire(10+Math.floor(Math.random()*5));

 kami.x = Math.random()*stageWidth;
 kami.y = Math.random()*stageHeight;

 ctx.fillStyle = "#" + kami._r + kami._g + kami._b;
 ctx.fillRect(kami.x, kami.y, kami.SIZE, kami.SIZE);

 //
 kamikire_array.push(kami);
 }

 setInterval(EnterFrame, 30);
    }

 //紙ふぶき
    function Kamikire(_size){
 this.SIZE = _size;

 this.x = 0;
 this.y = 0;
 this.alpha = 1;

 var t = Math.random()*Math.PI*2;
 //var r = Math.floor((1+Math.cos(t))*127.9999);
 //var g = Math.floor((1+Math.cos(t+Math.PI*2/3))*127.9999);
 //var b = Math.floor((1+Math.cos(t-Math.PI*2/3))*127.9999);

 var hue = 200;
 var sat = 60;
 //var val = Math.floor((1+Math.cos(t-Math.PI*2/3))*127.9999);
 //var val = 35;
 var val = Math.round(Math.random()*50) + 50;

 var rgbvalue = hsv2rgb(hue, sat, val);

 //ctx.fillStyle = 'rgb('+rgbvalue[r]+','+rgbvalue[g]+','+rgbvalue[b]+')';


 //this._r = r;
 //this._g = g;
 //this._b = b;

 this._r = rgbvalue['r'];
 this._g = rgbvalue['g'];
 this._b = rgbvalue['b'];

 this._backColor = 0x010101*Math.floor(127+Math.random()*64);
 this._omega = (Math.random()*2-1)*Math.PI/4;
 this._fallTheta = 0;
 this._fallSpeed = 1+Math.random()*2;

 this._theta = Math.random()*Math.PI*2;
 this._Ax = 1;
 this._Ay = Math.random();
 this._Az = Math.random()*2-1;
 var _l = Math.sqrt(this._Ax*this._Ax+this._Ay*this._Ay+this._Az*this._Az);
 this._Ax /= _l;
 this._Ay /= _l;
 this._Az /= _l;
 var _s = Math.sqrt(this._Ax*this._Ax+this._Ay*this._Ay);
 if(_s == 0){ // then A == ( 0, 0, -1 );
 this._Bx = 1.0; this._By = 0.0; this._Bz = 0.0;
 this._Cx = 0.0; this._Cy = 1.0; this._Cz = 0.0;
 } else {
 this._Bx = this._Ay; this._By = -this._Ax; this._Bz = 0;
 this._Cx = this._Ax*this._Az; this._Cy = this._Ay*this._Az; this._Cz = -(_s*_s);
 this._Bx /= _s; this._By /= _s;
 this._Cx /= _s*_l; this._Cy /= _s*_l; this._Cz /= _s*_l;
 }
    }

    Kamikire.prototype = {
 get rotation3D(){
 return this._theta - (Math.PI*2)*Math.floor(this._theta/(Math.PI*2));
 },
 set rotation3D(theta){
 this._theta = theta - (Math.PI*2)*Math.floor(theta/(Math.PI*2));
 var _cos = Math.cos(this._theta);
 var _sin = Math.sin(this._theta);

 // vector F is the rotated image of (1,0,0);
 var _Fx = this._Ax*this._Ax+(this._Bx*this._Bx+this._Cx*this._Cx)*_cos;
 var _Fy = this._Ax*this._Ay+(this._Bx*this._By+this._Cx*this._Cy)*_cos+(this._Bx*this._Cy-this._Cx*this._By)*_sin;
 var _Fz = this._Ax*this._Az+(this._Bx*this._Bz+this._Cx*this._Cz)*_cos-(this._Bx*this._Cz-this._Cx*this._Bz)*_sin;
 // vector G is the rotated image of (0,1,0);
 var _Gx = this._Ax*this._Ay+(this._By*this._Bx+this._Cy*this._Cz)*_cos+(this._By*this._Cx-this._Cy*this._Bx)*_sin;
 var _Gy = this._Ay*this._Ay+(this._By*this._By+this._Cy*this._Cy)*_cos;
 var _Gz = this._Ay*this._Az+(this._By*this._Bz+this._Cy*this._Cz)*_cos+(this._By*this._Cz-this._Cy*this._Bz)*_sin;

 //
 //ctx.fillStyle = 'rgba('+this._r+', '+this._g+', '+this._b+', '+this.alpha+')';
 ctx.fillStyle = 'rgb('+this._r+', '+this._g+', '+this._b+')';

 //ctx.fillStyle = 'rgb(135, 190, 240)';

 //ctx.fillStyle = 'rgb(135, 190, 240)';hsb(.55, 0%, 0%)';


 ctx.beginPath();
 ctx.lineTo(this.x+-_Fx*this.SIZE/2+_Gx*this.SIZE/2, this.y+-_Fy*this.SIZE/2+_Gy*this.SIZE/2);
 ctx.lineTo(this.x+-_Fx*this.SIZE/2-_Gx*this.SIZE/2, this.y+-_Fy*this.SIZE/2-_Gy*this.SIZE/2);
 ctx.lineTo(this.x+_Fx*this.SIZE/2-_Gx*this.SIZE/2, this.y+_Fy*this.SIZE/2-_Gy*this.SIZE/2);
 ctx.lineTo(this.x+_Fx*this.SIZE/2+_Gx*this.SIZE/2, this.y+_Fy*this.SIZE/2+_Gy*this.SIZE/2);
 ctx.closePath();
 ctx.fill();
 },
 fall: function(){
 this.rotation3D = this.rotation3D + this._omega;

 this.x += this._fallSpeed*Math.sin(this._fallTheta);
 this.y += this._fallSpeed*Math.cos(this._fallTheta);
 this._fallTheta += (Math.random()*2-1)*Math.PI/12;
 if(this._fallTheta < -Math.PI/2){
 this._fallTheta = -Math.PI - this._fallTheta;
 }
 if(this._fallTheta > Math.PI/2){
 this._fallTheta = Math.PI - this._fallTheta;
 }
 }
    }


    //enterframe
    function EnterFrame()
    {
 //初期化
 if(resizeFlg){
 resizeFlg = false;
 cvs.width = stageWidth;
 cvs.height = stageHeight;
 }
 ctx.clearRect(0,0,stageWidth,stageHeight);

 //表示更新
 for( i=0; i<DEF_KAMIKIRE_MAX; ++i){
 if(kamikire_array[i].y>0){
 var par = kamikire_array[i].y / stageHeight;
 par = 1 - par;

 kamikire_array[i].alpha = par;
 }

 if(kamikire_array[i].x - kamikire_array[i].SIZE/Math.SQRT2 > stageWidth){
 kamikire_array[i].x -= stageWidth;
 }
 if(kamikire_array[i].x + kamikire_array[i].SIZE/Math.SQRT2 < 0){
 kamikire_array[i].x += stageWidth;
 }
 if(kamikire_array[i].y - kamikire_array[i].SIZE/Math.SQRT2 > stageHeight){
 kamikire_array[i].y -= stageHeight;
 }

 kamikire_array[i].fall();
 }
    }

    /**
     * リサイズ
     */
    $(window).resize(function(){
                     resizeFlg = true;
                     stageWidth = window.innerWidth ? window.innerWidth : $(window).width();
                     stageHeight = window.innerHeight ? window.innerHeight : $(window).height();
                     });


 })();

参考

iOSでガワネイティブ

ソース

GitHub

Pocket
LinkedIn にシェア

エンジニアにおすすめできる本

Card image cap
リーダブルコード

より良いコードを書くためのシンプルで実践的なテクニック

Card image cap
Webを支える技術

HTTP,URI,HTML,そしてREST

Card image cap
誰でもPythonで作れる

儲かるAIとソフトウェアの作り方

Card image cap
プログラマが知るべき97のこと

現場で使える実践哲学のマスターピース

Card image cap
情熱プログラマー

時代を超えて。ソフトウェア開発者の幸せな生き方

Card image cap
アジャイルサムライ

プログラミング達人開発者への道

Card image cap
Rubyを作った男 まつもとゆきひろ

コードの世界 スーパー・プログラマになる14の思考法

ご提供 sponsor
 

Meee!(ミー)は、ビジネスからプライベート利用まで、個人のスキルを気軽に売り買いできるスキルマーケットです。カテゴリや居住地から、検索することが可能です。

 

ランゲージエクスチェンジは、ネイティブスピーカーと気軽にマッチングできる言語交換プラットフォームです。あなたの地元に住む外国人を探したり、留学や海外移住の前に、現地のネイティブスピーカーと繋がることもできます!

宣伝
 

りょすけトークchは、仕事や私生活をより豊にするYouTubeチャンネルです。文献(本、映画、論文)から役に立つ情報をまとめ、生涯にわたり役に立つ哲学をお届けしています。是非、チャンネル登録してみてね

-ホーム

Copyright© offブログ! , 2021 All Rights Reserved Powered by AFFINGER5.