Flutterで書くiOSアプリハンズオン(QiitaClientを作ってみよう)
Flutterを使ったハンズオン用に記事を作成しました
使用するAPI
今回はQiitaAPiを題材とします。(ドキュメント)
登録不要で使えて、例えば、 https://qiita.com//api/v2/items で、投稿を取得できます。
[{ rendered_body: " <h1> <span id=" プロローグ " class=" fragment "></span><a href="# % E3 % 83 % 97 % E3 % 83 % AD % E3 % 83 % AD % E3 % 83 % BC % E3 % 82 % B0 "><i class=" fa fa - link "></i></a>プロローグ</h1> <p><a href=" https: //camo.qiitausercontent.com/6c659e011f46abdb3a08bf3bac0a5d82418cbac3/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f37363834332f31356433383165642d343436312d633235392d633831312d3062373163393133646364652e706e67" target="_blank" rel="nofollow noopener"><img src="https://camo.qiitausercontent.com/6c659e011f46abdb3a08bf3bac0a5d82418cbac3/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f37363834332f31356433383165642d343436312d633235392d633831312d3062373163393133646364652e706e67" alt="20171109214610.png" data-canonical-src="https://qiita-image-store.s3.amazonaws.com/0/76843/15d381ed-4461-c259-c811-0b71c913dcde.png"></a></p> <p>参照: <a href="http://r-dimension.xsrv.jp/classes_j/sine_cosine/" class="autolink" rel="nofollow noopener" target="_blank">http://r-dimension.xsrv.jp/classes_j/sine_cosine/</a></p> <p><strong>うげ〜。いやだこの図。。</strong>はい、こんにちは。。。<br> こちらの図見るとオエ〜ってなりますよね。僕はなります。<br> なのでお口直しに、小松菜奈さんの画像貼っときますわ。</p> <p><a href="https://camo.qiitausercontent.com/1ce1b5e53bb6405ccc06ed7fe0ce189cad70e816/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f37363834332f64383133376461362d656337362d633435322d663637392d6266306130646566343164642e6a706567" target="_blank" rel="nofollow noopener"><img src="https://camo.qiitausercontent.com/1ce1b5e53bb6405ccc06ed7fe0ce189cad70e816/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f37363834332f64383133376461362d656337362d633435322d663637392d6266306130646566343164642e6a706567" width="200" data-canonical-src="https://qiita-image-store.s3.amazonaws.com/0/76843/d8137da6-ec76-c452-f679-bf0a0def41dd.jpeg"></a></p> <p>最近ネバヤン(バンド)に胸熱で。。お別れの歌のMVやばい。<br> <a href="https://www.youtube.com/watch?v=ZFI-Hqeu_Ag" class="autolink" rel="nofollow noopener" target="_blank">https://www.youtube.com/watch?v=ZFI-Hqeu_Ag</a></p> <h1> <span id="本題" class="fragment"></span><a href="#%E6%9C%AC%E9%A1%8C"><i class="fa fa-link"></i></a>本題</h1> <p><strong>円運動とかゆらゆら上下運動とかってsin()とかcos()が必要じゃないですか?<br> メディアアート系のプログラミングって。oFとかprocessingとか、Unityも?。</strong></p> <p>なのでなるべく優し〜く入門勉強してきたいと思います。</p> <p>参考サイト<br> <a href="http://yoppa.org/ma2_10/1739.html" class="autolink" rel="nofollow noopener" target="_blank">http://yoppa.org/ma2_10/1739.html</a><br> <a href="http://r-dimension.xsrv.jp/classes_j/sine_cosine/" class="autolink" rel="nofollow noopener" target="_blank">http://r-dimension.xsrv.jp/classes_j/sine_cosine/</a></p> <h1> <span id="入門します" class="fragment"></span><a href="#%E5%85%A5%E9%96%80%E3%81%97%E3%81%BE%E3%81%99"><i class="fa fa-link"></i></a>入門します!</h1> <blockquote> <p>さて、プログラムによって図形を描く場合に避けて通れないのが三角関数(サイン、コサイン)です。<br> 円などに代表される曲線を描く際によく使われます。<br> タンジェントは使用頻度が低いので、ここでは省略します。</p> </blockquote> <p>だそうです。。。</p> <p>まず先ほどの図。<br> 大丈夫だから、ちょっとみてみてください。</p> <p><a href="https://camo.qiitausercontent.com/6c659e011f46abdb3a08bf3bac0a5d82418cbac3/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f37363834332f31356433383165642d343436312d633235392d633831312d3062373163393133646364652e706e67" target="_blank" rel="nofollow noopener"><img src="https://camo.qiitausercontent.com/6c659e011f46abdb3a08bf3bac0a5d82418cbac3/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f37363834332f31356433383165642d343436312d633235392d633831312d3062373163393133646364652e706e67" alt="20171109214610.png" data-canonical-src="https://qiita-image-store.s3.amazonaws.com/0/76843/15d381ed-4461-c259-c811-0b71c913dcde.png"></a></p> <p>これを勇気を出して、単純に読み解くと、</p> <h2> <span id="r--円の半径" class="fragment"></span><a href="#r--%E5%86%86%E3%81%AE%E5%8D%8A%E5%BE%84"><i class="fa fa-link"></i></a>R → 円の半径</h2> <h2> <span id="x--y-円上の座標" class="fragment"></span><a href="#x--y-%E5%86%86%E4%B8%8A%E3%81%AE%E5%BA%A7%E6%A8%99"><i class="fa fa-link"></i></a>(x , y) →円上の座標</h2> <h2> <span id="θ--角度" class="fragment"></span><a href="#%CE%B8--%E8%A7%92%E5%BA%A6"><i class="fa fa-link"></i></a>θ → 角度</h2> <p>らしいです。</p> <p><a href="https://camo.qiitausercontent.com/67043a3190bfd14f3ed76443dc06bafe7c52a117/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f37363834332f31343937306263642d303762632d656361322d306138632d3730363130393662323235372e6a706567" target="_blank" rel="nofollow noopener"><img src="https://camo.qiitausercontent.com/67043a3190bfd14f3ed76443dc06bafe7c52a117/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f37363834332f31343937306263642d303762632d656361322d306138632d3730363130393662323235372e6a706567" alt="20171109214219.jpg" data-canonical-src="https://qiita-image-store.s3.amazonaws.com/0/76843/14970bcd-07bc-eca2-0a8c-7061096b2257.jpeg"></a></p> <p>雰囲気がある。いい。<br> 溺れるナイフは漫画最高だったけど映画最悪だったなー笑</p> <p>そして(x,y)の座標の求め方は、</p> <h2> <span id="x--r--cosθ" class="fragment"></span><a href="#x--r--cos%CE%B8"><i class="fa fa-link"></i></a>x = R * cos(θ)</h2> <h2> <span id="y--r--sinθ" class="fragment"></span><a href="#y--r--sin%CE%B8"><i class="fa fa-link"></i></a>y = R * sin(θ)</h2> <p>でOKだそうです。お、意外といけるのでは?<br> ではこの式を使ってoFで円を描いてみます。<br> まぁofDrawCircle()で描けるのですが、、、勉強に。</p> <p>できたぞ〜!!!!!<br> <a href="https://camo.qiitausercontent.com/af4ce1ca438fff2abb9967032271b63454ecd513/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f37363834332f36316235636230612d346234642d326533322d353264342d3938303938663566303362622e706e67" target="_blank" rel="nofollow noopener"><img src="https://camo.qiitausercontent.com/af4ce1ca438fff2abb9967032271b63454ecd513/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f37363834332f36316235636230612d346234642d326533322d353264342d3938303938663566303362622e706e67" alt="スクリーンショット 2017-11-09 22.37.08.png" data-canonical-src="https://qiita-image-store.s3.amazonaws.com/0/76843/61b5cb0a-4b4d-2e32-52d4-98098f5f03bb.png"></a></p> <p>動画<br> <a href="https://www.youtube.com/watch?v=JTVPKTFheS8" class="autolink" rel="nofollow noopener" target="_blank">https://www.youtube.com/watch?v=JTVPKTFheS8</a></p> <p>コード</p> <div class="code-frame" data-lang="cpp"> <div class="code-lang"><span class="bold">ofApp.cpp</span></div> <div class="highlight"><pre><span></span> <span class="cp">#include</span> <span class="cpf">"ofApp.h"</span><span class="cp"></span> <span class="kt">float</span> <span class="n">phase</span><span class="p">;</span> <span class="c1">// 段階の意味</span> <span class="k">const</span> <span class="kt">float</span> <span class="n">R</span> <span class="o">=</span> <span class="mi">200</span><span class="p">;</span> <span class="c1">// 円の半径</span> <span class="c1">//--------------------------------------------------------------</span> <span class="kt">void</span> <span class="n">ofApp</span><span class="o">::</span><span class="n">setup</span><span class="p">(){</span> <span class="n">ofSetFrameRate</span><span class="p">(</span><span class="mi">60</span><span class="p">);</span> <span class="n">ofSetBackgroundAuto</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span> <span class="c1">// 毎回背景を塗りつぶしてリセットしない!</span> <span class="n">ofBackground</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">);</span> <span class="p">}</span> <span class="c1">//--------------------------------------------------------------</span> <span class="kt">void</span> <span class="n">ofApp</span><span class="o">::</span><span class="n">update</span><span class="p">(){</span> <span class="c1">// 段階を更新</span> <span class="n">phase</span> <span class="o">+=</span> <span class="mf">0.01</span><span class="p">;</span> <span class="p">}</span> <span class="c1">//--------------------------------------------------------------</span> <span class="kt">void</span> <span class="n">ofApp</span><span class="o">::</span><span class="n">draw</span><span class="p">(){</span> <span class="c1">//原点を画面の中心点に</span> <span class="n">ofTranslate</span><span class="p">(</span><span class="n">ofGetWidth</span><span class="p">()</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span> <span class="n">ofGetHeight</span><span class="p">()</span><span class="o">/</span><span class="mi">2</span><span class="p">);</span> <span class="c1">//点の座標を三角関数で計算するぞ x = R * cos(θ) y = R * sin(θ)</span> <span class="n">ofVec2f</span> <span class="n">pos</span><span class="p">;</span> <span class="c1">// 円の位置</span> <span class="n">pos</span><span class="p">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">R</span> <span class="o">*</span> <span class="n">cos</span><span class="p">(</span><span class="n">phase</span><span class="p">);</span> <span class="n">pos</span><span class="p">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">R</span> <span class="o">*</span> <span class="n">sin</span><span class="p">(</span><span class="n">phase</span><span class="p">);</span> <span class="c1">//色を黄色に</span> <span class="n">ofSetColor</span><span class="p">(</span><span class="mi">256</span><span class="p">,</span><span class="mi">256</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">// 4ポイントの円を描画</span> <span class="n">ofDrawCircle</span><span class="p">(</span><span class="n">pos</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">pos</span><span class="p">.</span><span class="n">y</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span> <span class="p">}</span> </pre></div> </div> <p><strong>どうやら 先ほどの公式のcos(θ)のθにあたる変数phase(段階)をupdateで増やしていくのがキモみたいっすね。</strong></p> <p>これに時間経過とか入れてやればいいのかな<br> そんくらいの理解でいいかな。。</p> <h1> <span id="浅くてすんません" class="fragment"></span><a href="#%E6%B5%85%E3%81%8F%E3%81%A6%E3%81%99%E3%82%93%E3%81%BE%E3%81%9B%E3%82%93"><i class="fa fa-link"></i></a>浅くてすんません。。</h1> <p>次は、</p> <h2> <span id="y--r--sinθ-1" class="fragment"></span><a href="#y--r--sin%CE%B8-1"><i class="fa fa-link"></i></a>y = R * sin(θ)</h2> <p>の公式を取得したので上下ゆらゆらやってみます!!</p> <p>おっできた</p> <p><a href="https://camo.qiitausercontent.com/8a931fa630600b58c095bbc10aae74e23045e908/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f37363834332f64373435653365632d633033382d303038662d653062322d6430366564386234336330642e706e67" target="_blank" rel="nofollow noopener"><img src="https://camo.qiitausercontent.com/8a931fa630600b58c095bbc10aae74e23045e908/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f37363834332f64373435653365632d633033382d303038662d653062322d6430366564386234336330642e706e67" alt="スクリーンショット 2017-11-09 22.43.45.png" data-canonical-src="https://qiita-image-store.s3.amazonaws.com/0/76843/d745e3ec-c038-008f-e0b2-d06ed8b43c0d.png"></a></p> <p>動画<br> <a href="https://www.youtube.com/watch?v=pQptfrukBRE" class="autolink" rel="nofollow noopener" target="_blank">https://www.youtube.com/watch?v=pQptfrukBRE</a></p> <p><strong>コードはこちら。今回はRがゆらゆらさせる範囲で、変数phase(段階)の増える値がゆらゆらする速度になってるんですね。</strong></p> <div class="code-frame" data-lang="cpp"> <div class="code-lang"><span class="bold">ofApp.cpp</span></div> <div class="highlight"><pre><span></span> <span class="kt">float</span> <span class="n">phase</span><span class="p">;</span> <span class="c1">// 段階の意味</span> <span class="k">const</span> <span class="kt">float</span> <span class="n">R</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span> <span class="c1">//ゆらゆらさせる範囲</span> <span class="c1">//--------------------------------------------------------------</span> <span class="kt">void</span> <span class="n">ofApp</span><span class="o">::</span><span class="n">setup</span><span class="p">(){</span> <span class="n">ofSetFrameRate</span><span class="p">(</span><span class="mi">60</span><span class="p">);</span> <span class="n">ofBackground</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">);</span> <span class="p">}</span> <span class="c1">//--------------------------------------------------------------</span> <span class="kt">void</span> <span class="n">ofApp</span><span class="o">::</span><span class="n">update</span><span class="p">(){</span> <span class="c1">// 段階を更新</span> <span class="n">phase</span> <span class="o">+=</span> <span class="mf">0.01</span><span class="p">;</span> <span class="p">}</span> <span class="c1">//--------------------------------------------------------------</span> <span class="kt">void</span> <span class="n">ofApp</span><span class="o">::</span><span class="n">draw</span><span class="p">(){</span> <span class="c1">//原点を画面の中心点に</span> <span class="n">ofTranslate</span><span class="p">(</span><span class="n">ofGetWidth</span><span class="p">()</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span> <span class="n">ofGetHeight</span><span class="p">()</span><span class="o">/</span><span class="mi">2</span><span class="p">);</span> <span class="n">ofVec2f</span> <span class="n">pos</span><span class="p">;</span> <span class="n">pos</span><span class="p">.</span><span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// 左右は運動なし</span> <span class="n">pos</span><span class="p">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">R</span> <span class="o">*</span> <span class="n">sin</span><span class="p">(</span><span class="n">phase</span><span class="p">);</span> <span class="c1">// 上下ゆらゆら</span> <span class="c1">//色を黄色に</span> <span class="n">ofSetColor</span><span class="p">(</span><span class="mi">256</span><span class="p">,</span><span class="mi">256</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">// 30ポイントの円を描画</span> <span class="n">ofDrawCircle</span><span class="p">(</span><span class="n">pos</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="n">pos</span><span class="p">.</span><span class="n">y</span><span class="p">,</span> <span class="mi">30</span><span class="p">);</span> <span class="p">}</span> </pre></div> </div> <h2> <span id="x--r--cosθ-1" class="fragment"></span><a href="#x--r--cos%CE%B8-1"><i class="fa fa-link"></i></a>x = R * cos(θ)</h2> <p>を使えば左右ゆらゆらも表現できると思います^^。<br> ちょっとは三角関数と仲良くなれた気がします!<br> 今回で基礎をかじった気がするから、sin波も学んでみたいです。</p> <p>完。</p> <p>本家のブログはこちら 超雑多です。w🍺<br> ホンキートンク・スーダラブルース<br> <a href="http://www.sudara-bluse.tokyo/entry/openframeworks_5" class="autolink" rel="nofollow noopener" target="_blank">http://www.sudara-bluse.tokyo/entry/openframeworks_5</a></p> ", body: " #プロローグ ![20171109214610.png](https://qiita-image-store.s3.amazonaws.com/0/76843/15d381ed-4461-c259-c811-0b71c913dcde.png) 参照: http://r-dimension.xsrv.jp/classes_j/sine_cosine/ **うげ〜。いやだこの図。。**はい、こんにちは。。。 こちらの図見るとオエ〜ってなりますよね。僕はなります。 なのでお口直しに、小松菜奈さんの画像貼っときますわ。 <img src=" https: //qiita-image-store.s3.amazonaws.com/0/76843/d8137da6-ec76-c452-f679-bf0a0def41dd.jpeg" width="200"> 最近ネバヤン(バンド)に胸熱で。。お別れの歌のMVやばい。 https://www.youtube.com/watch?v=ZFI-Hqeu_Ag #本題 **円運動とかゆらゆら上下運動とかってsin()とかcos()が必要じゃないですか? メディアアート系のプログラミングって。oFとかprocessingとか、Unityも?。** なのでなるべく優し〜く入門勉強してきたいと思います。 参考サイト http://yoppa.org/ma2_10/1739.html http://r-dimension.xsrv.jp/classes_j/sine_cosine/ #入門します! >さて、プログラムによって図形を描く場合に避けて通れないのが三角関数(サイン、コサイン)です。 円などに代表される曲線を描く際によく使われます。 タンジェントは使用頻度が低いので、ここでは省略します。 だそうです。。。 まず先ほどの図。 大丈夫だから、ちょっとみてみてください。 ![20171109214610.png](https://qiita-image-store.s3.amazonaws.com/0/76843/15d381ed-4461-c259-c811-0b71c913dcde.png) これを勇気を出して、単純に読み解くと、 ##R → 円の半径 ##(x , y) →円上の座標 ##θ → 角度 らしいです。 ![20171109214219.jpg](https://qiita-image-store.s3.amazonaws.com/0/76843/14970bcd-07bc-eca2-0a8c-7061096b2257.jpeg) 雰囲気がある。いい。 溺れるナイフは漫画最高だったけど映画最悪だったなー笑 そして(x,y)の座標の求め方は、 ## x = R * cos(θ) ## y = R * sin(θ) でOKだそうです。お、意外といけるのでは? ではこの式を使ってoFで円を描いてみます。 まぁofDrawCircle()で描けるのですが、、、勉強に。 できたぞ〜!!!!! ![スクリーンショット 2017-11-09 22.37.08.png](https://qiita-image-store.s3.amazonaws.com/0/76843/61b5cb0a-4b4d-2e32-52d4-98098f5f03bb.png) 動画 https://www.youtube.com/watch?v=JTVPKTFheS8 コード ```cpp:ofApp.cpp #include "ofApp.h" float phase; // 段階の意味 const float R = 200; // 円の半径 //-------------------------------------------------------------- void ofApp::setup(){ ofSetFrameRate(60); ofSetBackgroundAuto(false); // 毎回背景を塗りつぶしてリセットしない! ofBackground(255, 255, 255); } //-------------------------------------------------------------- void ofApp::update(){ // 段階を更新 phase += 0.01; } //-------------------------------------------------------------- void ofApp::draw(){ //原点を画面の中心点に ofTranslate(ofGetWidth()/2, ofGetHeight()/2); //点の座標を三角関数で計算するぞ x = R * cos(θ) y = R * sin(θ) ofVec2f pos; // 円の位置 pos.x = R * cos(phase); pos.y = R * sin(phase); //色を黄色に ofSetColor(256,256, 0); // 4ポイントの円を描画 ofDrawCircle(pos.x, pos.y, 4); } ``` **どうやら 先ほどの公式のcos(θ)のθにあたる変数phase(段階)をupdateで増やしていくのがキモみたいっすね。** これに時間経過とか入れてやればいいのかな そんくらいの理解でいいかな。。 #浅くてすんません。。 次は、 ## y = R * sin(θ) の公式を取得したので上下ゆらゆらやってみます!! おっできた ![スクリーンショット 2017-11-09 22.43.45.png](https://qiita-image-store.s3.amazonaws.com/0/76843/d745e3ec-c038-008f-e0b2-d06ed8b43c0d.png) 動画 https://www.youtube.com/watch?v=pQptfrukBRE **コードはこちら。今回はRがゆらゆらさせる範囲で、変数phase(段階)の増える値がゆらゆらする速度になってるんですね。** ```cpp:ofApp.cpp float phase; // 段階の意味 const float R = 100; //ゆらゆらさせる範囲 //-------------------------------------------------------------- void ofApp::setup(){ ofSetFrameRate(60); ofBackground(255, 255, 255); } //-------------------------------------------------------------- void ofApp::update(){ // 段階を更新 phase += 0.01; } //-------------------------------------------------------------- void ofApp::draw(){ //原点を画面の中心点に ofTranslate(ofGetWidth()/2, ofGetHeight()/2); ofVec2f pos; pos.x = 0; // 左右は運動なし pos.y = R * sin(phase); // 上下ゆらゆら //色を黄色に ofSetColor(256,256, 0); // 30ポイントの円を描画 ofDrawCircle(pos.x, pos.y, 30); } ``` ## x = R * cos(θ) を使えば左右ゆらゆらも表現できると思います^^。 ちょっとは三角関数と仲良くなれた気がします! 今回で基礎をかじった気がするから、sin波も学んでみたいです。 完。 本家のブログはこちら 超雑多です。w🍺 ホンキートンク・スーダラブルース http://www.sudara-bluse.tokyo/entry/openframeworks_5 ", coediting: false, comments_count: 0, created_at: "2017-11-09T22:50:51+09:00", group: null, id: "fe412a67b64e793d138b", likes_count: 0, private: false, reactions_count: 0, tags: [{ name: "processing", versions: [] }, { name: "openFrameworks", versions: [] } ], title: "【openFrameworks 初心者冒険記5】逃げまくってた...三角関数の扉を再ノック。sin() cos() サインコサイン....。メディアアートで避けては通れない?最初の壁", updated_at: "2017-11-09T22:50:51+09:00", url: "http://qiita.com/39_isao/items/fe412a67b64e793d138b", user: { description: "鮭とメロンパンが好物な奥田民生になりたいボーイです。 最近はてなブログ始めました http://sudara-bluse.hatenablog.com/", facebook_id: "", followees_count: 52, followers_count: 44, github_login_name: null, id: "39_isao", items_count: 103, linkedin_id: "", location: "", name: "", organization: "", permanent_id: 76843, profile_image_url: "https://qiita-image-store.s3.amazonaws.com/0/76843/profile-images/1508030106", twitter_screen_name: "sudara_bluse", website_url: "http://sudara-bluse.hatenablog.com/" } }, {,,,} ]
今回は、以下のデータを使ってiOSアプリを作ってみます。
- 投稿タイトル
- ユーザアイコン
- URL
完成したアプリ
プロジェクトを作成する
使うライブラリをインストールする
dependencies: flutter: sdk: flutter provider: ^4.0.4 http: ^0.12.0+4 webview_flutter: ^0.3.19+8
通信周りのクラスを作成する
JSONを変換するための構造体を作成
class Item { final String id; final String title; final String body; final String url; final User user; Item({ this.id, this.title, this.body, this.url, this.user, }); static Item fromJson(dynamic json) { return Item( id: json['id'], title: json['title'], body: json['body'], url: json['url'], user: User.fromJson(json['user']), ); } } class User { final String profileImageUrl; User({ this.profileImageUrl, }); static User fromJson(dynamic json) { return User( profileImageUrl: json['profile_image_url'], ); } }
APIからデータを取得するクラスを実装
import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'item.dart'; class ItemModel extends ChangeNotifier { List<Item> get items => _items; List<Item> _items = []; void search(String query) async { final http.Response res = await http.get("https://qiita.com//api/v2/items?query=$query"); if (res.statusCode != 200) { throw HTTPException(res.statusCode, "unable to fetch weather data"); } final itemsJson = json.decode(res.body) as List; _items = itemsJson.map((data) => Item.fromJson(data)).toList(); notifyListeners(); } } class HTTPException implements Exception { final int code; final String message; HTTPException(this.code, this.message) : assert(code != null); @override String toString() { return 'HTTPException{code: $code, message: $message}'; } }
一覧画面を作る
一覧画面を作成する
新しく item_list_screen.dart というファイルを作成します
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:qiita_client/models/item.dart'; import 'item_detail_screen.dart'; import 'models/item_model.dart'; class ItemListScreen extends StatelessWidget { @override Widget build(BuildContext context) { final itemModel = Provider.of<ItemModel>(context); return Scaffold( appBar: AppBar( title: Text('Qiita Client'), ), body: Column( children: [ Padding( padding: EdgeInsets.only(left: 8, right: 8), child: TextField( decoration: InputDecoration(labelText: "Search something"), onSubmitted: (text) { itemModel.search(text); }, ), ), Expanded( child: ListView.builder( padding: const EdgeInsets.all(8), itemCount: itemModel.items.length, itemBuilder: (BuildContext context, int index) { final item = itemModel.items[index]; return ItemListRow(item: item); }, ), ) ], ), ); } } class ItemListRow extends StatelessWidget { final Item item; const ItemListRow({Key key, this.item}) : super(key: key); @override Widget build(BuildContext context) { return InkWell( onTap: () { }, child: Container( height: 60, child: Row( children: [ Container( height: 44, width: 44, padding: const EdgeInsets.only(right: 8), child: Image.network(item.user.profileImageUrl), ), Expanded( child: Text('Entry ${item.title}'), ), ], ), ), ); } }
起動画面を一覧画面にする
もともと作成されている main.dart を修正して一覧画面を表示するようにします
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:qiita_client/item_list.dart'; import 'models/item_model.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider<ItemModel>( create: (_) => ItemModel(), ), ], child: MaterialApp( title: 'Qiita client app', theme: ThemeData( primarySwatch: Colors.orange, ), home: ItemListScreen(), ), ); } }
起動する
ここまで作ったら一度起動して入力した文字で検索できることを確認してみましょう
詳細画面を作る
詳細画面は一覧でタップした投稿をWebViewで表示します 新しくitem_detail_screen.dartを作成します
import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; class ItemDetailScreen extends StatelessWidget { final String title; final String url; const ItemDetailScreen({ Key key, this.title, this.url, }) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(title), ), body: WebView( initialUrl: url, ), ); } }
一覧から詳細画面に遷移できるようにする
item_list_screen.dart を以下のように修正して画面遷移できるようにします
onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ItemDetailScreen(title: item.title, url: item.url), ), ); },
実行してみましょう
最後に
完成はこちらにあります。 github.com
おつかれさまでした。
SchemaPolicyCheckでDB設計ルールを自動チェックしよう
目次
- SchemaPolicyチェックとは
- 設定方法
SchemaPolicyチェックとは
プログラミングをする際にはコードのチェックスタイルを使っていると思います。 Ruby では rubocop, JavaならIntelliJやEclipseのフォーマッタが一般的ですね。
コードよりも気軽に変更できないDBに関してはこのようなチェックを行っているチームはあまりないと思います。 そこで今回は、SchemaPocilyCheckを使いBooleanなら末尾にFLGをつけると言った細かなルールを自動的にチェックする方法を紹介します。
設定方法
※ DBFlute-introを使ってチェックを行うのでまだ設定をしていない人はこちらから設定を行ってください
まずDBFlute-introのSchemaPolicyCheckのページを開きます。 ここでは、
- SchemaPolicyCheckの実行
- DB設計ルールの設定
を行う事ができます。
では、実際に設定を変更していきます。
以下ルールの設定をして実行を押下しましたが成功していますね。
- テーブルのPKの必須化
- テーブル名を全て小文字
今後は失敗するように以下設定にして実行してみます
- テーブルのPKの必須化
- テーブル名を全て大文字
失敗すると失敗理由をリンクから確認できるようになります。
この機能を使うことで、単純なルールはDBFluteにまかせてレビュワーはもっと本質的なレビューに集中することができます。
まとめ
- DB設計のルール確認は人がチェックしているケースが多い
- DBFluteIntroを使えば、ルール設定を行い自動チェックができる
Elasticsaerchでサジェスト検索を作ってみよう
目次
- Elasticsearch の説明
- 検索の基礎知識
- サジェスト検索をやってみる
- まとめ
Elasticsearchとは
Elastic社が開発している全文検索エンジンで、リアルタイムデータ分析、ログ解析、全文検索など様々な用途に使われています。
検索の基礎知識
Elasticsearchでは保存されている文書の文字と、検索ワードで与えられた文字列がマッチしたら検索結果に含まれます
たとえば、
this is a test
というデータがあった場合、
this / is / a / test
と分解されるので、
this
か is
か a
か test
で検索するとこのデータが返ってきます。
サジェスト検索をやってみる
上の設定のままだと t
や th
という検索ワードではデータが返ってこないためサジェスト検索を実現することができません。
そこで文章の解析方法を指定するTokenizerの設定を変更します。
今回は、this
を t
th
のように単語をより詳細に分割をする必要があります。
そのためには、ngram
と edge_ngram
という Tokenizer があるので見ていきましょう。
ngram は、以下の様に単語を1~2文字に分割してくれます。
t th h hi i is s / i is s / a / t te e es s st t
edge_ngram は、以下の様に文字を分割してくれます。
t th thi this / i is / a / t te tes test
こうすることで、t
や th
と入力したタイミングで結果を返すサジェスト検索を実現することができます。
まとめ
- Elasticsearch は様々な用途に使われている検索エンジン
- Tokenizerが分割したTokenに当てはまる文字とInputが一致すると検索結果に含まれる
- サジェスト検索をするためには単語単位ではなく、文字数ベースで文章の分割をする必要がある
DBFlute-IntroでDB変更履歴を管理する
目次
- HistoryHTMLとは
- 実際にHistoryHTMLを生成する
- コメントを書こう
- まとめ
HistoryHTMLとは
スキーマの変更履歴を人が見やすい形にまとめたドキュメントです。 DBFluteが自動生成のためにメタデータを取得するたびに、一つ前のメタデータと内容の比較をしてスキーマ構造に違いがあった部分だけをドキュメントにまとめます。
実際にHistoryHTMLを生成する
アプリケーションで、DBFluteを使っている場合は自動で生成されます。 もし使っていない場合は、DBFluteIntroの「Generate Documents」ボタンをクリックしましょう。
するとHistoryHTMLが更新されます
このように以前のDB変更からどのような変更がはいったのか確認をすることができます。
コメントを書こう
DBFlute-intro特有の機能として、diffNo のところをクリックするとHistoryHTMLにコメントを追記することができます。 この機能を使うことで、リリース単位でどんなDB変更をしたのか、意図はなんだったのかドキュメントにまとめることができます
まとめ
- DBFluteはHistoryHTMLという機能でDBの履歴を管理できる
- あとでコメントを追加し、どういった意図でDB変更したのかドキュメントにまとめられる
Railsで外部キー成約を追加した際のIndex名のまとめ
普段 Ruby on Rails でつくられたWebサービス開発をしています。 この前、既存カラムに外部キー成約(FK)を追加したとき普段と違う命名の index名になってしました。
FK追加時にどのような index 名になるのか気になったので、いろいろなパターンを試してまとめました!
Indexの貼り方
RailsアプリケーションではFKを貼る際に大きく以下の方法があります。
1. テーブル作成時に指定するカラム作成時にFKを貼る
class AddTable < ActiveRecord::Migration[5.2] def change create_table :parent1s create_table :parent2s create_table :parent3s create_table :children do |t| t.references :parent1, foreign_key: true end end end
2.カラム追加時にFKを貼る
class AddChild < ActiveRecord::Migration[5.2] def change add_reference :children, :parent2, foreign_key: true end end
3.後からFKを貼る
class AddFk < ActiveRecord::Migration[5.2] def change add_column :children, :parent3_id, :bigint add_foreign_key :children, :parent3s, column: "parent3_id" end end
生成されたIndex
実行結果
schema.rb
ActiveRecord::Schema.define(version: 2019_08_10_050953) do create_table "children", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| t.bigint "parent1_id" t.bigint "parent2_id" t.bigint "parent3_id" t.index ["parent1_id"], name: "index_children_on_parent1_id" t.index ["parent2_id"], name: "index_children_on_parent2_id" t.index ["parent3_id"], name: "fk_rails_c04e2dbc44" end create_table "parent1s", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| end create_table "parent2s", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| end create_table "parent3s", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| end add_foreign_key "children", "parent1s" add_foreign_key "children", "parent2s" add_foreign_key "children", "parent3s" end
add_foreigin_key
でFKを貼った場合、Indexの名前がFK成約と同じ名前になってしまいます。 fk_rails_c04e2dbc44
Indexは後からチューニングする際に名前の規約が決まっていた方が便利なので、この名前は使いたくないですよね。 対処方法は、以下のように際にIndexを貼り、あとでFKを貼ることで回避することができます
class AddFk < ActiveRecord::Migration[5.2] def change add_column :children, :parent3_id, :bigint add_index :children, :parent3_id add_foreign_key :children, :parent3s, column: "parent3_id" end end
まとめ
- FKの貼り方は大きく3種類ある
- 既存カラムに
add_foreign_key
でFKを追加したときだけ Indexの名前が違うので注意する
Railsのスキーマ情報をDBFlute-Introで管理しよう
前回 DBFlute-Intro を使ってデータベースのドキュメントを管理する方法をまとめました。
私は普段、Ruby on Rails でWebサービスの開発をしているのですが、その際にいくつかエラーが出てしまったのでその回避方法をまとめます。
DBFlute-IntroをRailsを使う時の問題
Ruby on Rails で開発するときは、ライブラリが自動生成するテーブルがあったり、カラム名に規約があり意図せずにMySQLの予約語を使ってしまうケースが多々あります。 一方でDBFlute-Intro では、依存しているDBFluteが基本的に予約語は使わない想定で作られているため、ドキュメント生成時に以下のようなエラーが起きてしまいました。
[df-jdbc] /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * [df-jdbc] Failed to execute the SQL for getting auto-increment [df-jdbc] [df-jdbc] [Advice] [df-jdbc] DBFlute executes the SQL to get auto-increment meta data. [df-jdbc] The table might not exist on your schema. Or the schema [df-jdbc] to be set at 'dfprop' might be mistake in the first place. [df-jdbc] [df-jdbc] And other points can be causes [df-jdbc] e.g. reservation word, authentication, ... [df-jdbc] If your primary key of the table is reservation word in the DBMS, [df-jdbc] set quatation settings 'quoteColumnNameList' of littleAdjustmentMap.dfprop. [df-jdbc] [df-jdbc] So check your settings and environments. [df-jdbc] [df-jdbc] [Table] [df-jdbc] maihamadb.ar_internal_metadata [df-jdbc] [df-jdbc] [PrimaryKey] [df-jdbc] key [df-jdbc] [df-jdbc] [SQL for getting] [df-jdbc] select key from ar_internal_metadata where 0 = 1 [df-jdbc] * * * * * * * * * */
key という名前が予約語になっているようです...
解決策
DBFluteは予約語を使いたい場合は、
自動で生成された dbflute_xxx のディレクトリに存在する、littleAdjustmentMap.dfprop
を以下のように変更します。
dbflute_xxx └ dfprop └ littleAdjustmentMap.dfprop
-#; quoteTableNameList = list:{} +; quoteTableNameList = list:{$$ALL$$} ... 省略 -#; quoteColumnNameList = list:{} +; quoteColumnNameList = list:{$$ALL$$}
この変更をすることで、テーブル名とカラム名をバッククオートで囲った状態で扱う事ができます。
まとめ
- Ruby on Rails の スキーマも DBFlute-Introで管理することができる
- 予約語を使うOR Mapper を使う場合は、DBFlute-Intro側の設定変更が必要
DBFlute Intro を使ってデータベースのドキュメント管理を楽にしよう
以前、開発人数の多いサービスで働いているメンバーから、「データベースにコメントは残したいんだけど、DB変更の手順が面倒だったり、レビューにはDBAの人が必要で気軽にできないんだよー」という悩みを耳にしました。
DBFlute Intro ではDB変更なしでドキュメントの更新、コメント追加が行える機能を開発しました。
今回はその手順をまとめました。
目次
- そもそもSchemaHTML とは
- ドキュメントの表示手順
- ドキュメントの更新方法
- チームでのドキュメントの共有方法
- まとめ
そもそもSchemaHTML とは
DBFlute Intro では SchemaHTMLという、スキーマのメタデータ(テーブル構成など)を人が見やすい形にまとめたドキュメントを閲覧することができます
詳しくはこちらをご覧ください dbflute.seasar.org
ドキュメントの表示手順
1.DBFlute Intro のダウンロード
Githubのリリースページ から最新の jar
ファイルをダウンロードします
2.ダウンロードした jar
ファイルを「右クリック」をして「開く」を押すと数秒後にブラウザで自動的に立ち上がります。
3.立ち上がった画面にドキュメント生成したいDBの情報を入力します
4.DBのセットアップが完了するとTOP画面遷移するので、生成したDB名をクリックします
すると以下画面が表示されるので、「Generate Documents」をクリックすると数秒後にドキュメントへのリンクが表示されます
5.実際にドキュメントを開きます
ドキュメントの更新方法
SchemaHTMLの更新したいテーブルや、カラムのコメント部分をクリックします。(表の「Table Comment、Column Comment」)
ダイアログが立ち上がるのでコメントを変更して「OK」をクリックします
するとコメントが変更され、誰が書いたのか auther名が追加されます
変更前
変更後
またDB変更があったときには、「Generate Documents」をクリックすると作成したコメントを残したままDB変更をドキュメントに反映をすることができます
チームでのドキュメントの共有方法
jar
ファイルをダウンロードしたディレクトリを見ると、いくつかディレクトリができています。
コメントはこのディレクトリでファイル管理されているので、これらまとめて開発チームの git レポジトリとして共有するとドキュメントの共有をすることができます。
※ 以下の様なディレクトリなら my-project
を Git 管理する
まとめ
- DBコメントは管理したいが気軽に変更しづらい
- DBFlute Intro では ドキュメントの自動生成とコメントの気軽な更新ができる
- チーム内での共有は Git レポジトリを用意すれば簡単にできる