パークのソフトウエア開発者ブログ|ICT技術(Java・Android・iPhone・C・Ruby)なら株式会社パークにお任せください -26ページ目

パークのソフトウエア開発者ブログ|ICT技術(Java・Android・iPhone・C・Ruby)なら株式会社パークにお任せください

開発の解決方法や新しい手法の情報を、パークのエンジニアが提供します。パークのエンジニアが必要な場合は、ぜひお気軽にお問い合わせ下さい。 株式会社パーク:http://www.pa-rk.co.jp/

こんにちは & はじめまして。iPhone開発が得意なzerowiredと申します。
今回はiOSのライブラリを簡単に導入・管理できるCocoaPodsの使い方について、
グラフライブラリCorePlotを例にご紹介します。
(CorePlotはiPhoneアプリでグラフを描くためのライブラリです。)

時折コンパイルオプションの設定ミスで、ライブラリの取り込みがうまくいかない事があります。
CocoaPodsはこの設定を自動で実施してくれます。

■ CocoaPodsで何ができる?

オープンソースのライブラリを使う際は通常であれば
  1. ライブラリのダウンロード
  2. ヘッダファイルの参照設定
  3. ライブラリの参照設定
  4. 必要なフレームワークの設定
  5. コンパイルオプションの設定
などの作業が発生します。
プロジェクトでは一度だけの作業ですが、結構面倒な作業です。


CocoaPodsを使った場合
  1. CocoaPodsの設定ファイルを書く
  2. コマンドを実行する
これにより、通常の手順における1~5をすべてやってくれるので、
ライブラリの取り込みがかなり省力化されます。

■ CocoaPodsのインストール

これについては色々な所で語られておりますので、コマンドだけ紹介します。
ターミナルから、以下を実行するだけです。
$ sudo gem install cocoapods


CocoaPodsを使う準備ができたら、プロジェクトにライブラリを追加してみます。
ここではCorePlotを取り込むものとして説明します。

まずは、ライブラリを利用するプロジェクトを作成してください。
この説明ではSingleViewのアプリケーションプロジェクト"Sample01"があるものとして、そこにCorePlotを取り込みます。

■ PodFileの作成

作成したプロジェクトの.xcodeprojが置かれている階層に"Podfile"という名前でファイルを作ります。Podfileに書かれた設定でCorePlotはライブラリを導入してくれます。
PodFileの置き場所
platform :ios, '7.1' # サポートプラットフォーム
xcodeproj './Sample01.xcodeproj' # ライブラリを利用するプロジェクト
pod 'CorePlot', '~> 1.5' # CorePlot

1行目、2行目の説明は割愛します。
3行目の"pod"で始まる行は、自分の使いたいライブラリの設定を記述します。
書く内容はcocoapodsのサイトで下図のように取得できます。
CorePlot取り込みの設定

■ ライブラリの取り込み

ライブラリを取り込むには、ターミナルでPodfileをおいた階層で、次のコマンドを実行します。
$ pod install

これだけで、ライブラリを取得し、プロジェクトの設定を変更してワークスペースを作成してくれます。
コマンドをタイプした後のAnalyze dependencies から Downloading dependencies になるまでは、かなり時間がかかります。
環境にもよると思われますが、今回の例では13分ほどかかりました。
CorePlot取り込み

下図のワークスペースをX-codeで開くと、取り込んだライブラリとともにアプリケーションをビルドする環境が整えられます。
この後の作業では元々のxcodeprojではなく、このワークスペースのファイルを開いてください。
生成されたワークスペース

ワークスペースを開くと以下の図のようになります。
開かれたワークスペース

取り込んだCorePlotは"Pods"プロジェクトに追加されます。
アプリケーションでは"Pods"プロジェクトが生成するライブラリを参照する事でCorePlotを使える仕組みです。
元々の xcodeproj (Sample01) には、コンパイルオプション変更、CorePlotのヘッダを参照するためのインクルードパス追加、"Pods"のライブラリへの参照追加などが自動で行われます。
これにより、Sample01をビルドする事が出来るようになります。


以上が、"とりあえず" CocoaPodsを使う流れです。
次の機会では、CorePodsを使う上で「少し考えないと」と思った点を整理できればと思います。
インクルードパスとか…

■記事作成環境
OS : OS X 10.9.2(13C64)
X-Code : Version 5.1.1 (5B1008)
RubyGems : version 2.0.3 (要 command line tools)
以前矩形波(のこぎり波)を紹介しましたが、今回は三角波の作成方法を紹介します。
何かsin波に似てますね。カーブが無くなってギザギザになった波形です。
しかし、作成するには自分で計算式を組まないと作れないので結構やっかいです。

三角波


周期ごとの場合分けと、位相と周波数の考え方は以前紹介した矩形波やのこぎり波とほぼ一緒です。

では早速
サンプリング間隔:nInterval(ms)
データ数:nDataNum
振幅:dbAmp(dBやVolt等)
周波数:dbFrequency(Hz)
位相:dbPhase(度)
オフセット:dbOffset
三角波を作成してみます。


int nInterval // サンプリング間隔(ms)
double dbOffset // 縦軸オフセット(0点)
double dbAmp // 振幅(dB、電圧値等)
double dbFrequency // 周波数(Hz)
double dbPhase // 位相(度)

for( nDataCnt = 0; nDataCnt < nDataNum; nDataCnt++ )
{
nRemain = (int)( nInterval * nDataCnt - 1000 * dbPhase / 360 + 250 / dbFrequency )
% (int)( 1000 / dbFrequency );

if( -1000 <= nRemain && nRemain < -500/dbFrequency )

adWaveData[ nDataCnt ] = dbAmp / ( 250/dbFrequency ) * nRemain + dbOffset + 3 * dbAmp;

else if( -500/dbFrequency <= nRemain && nRemain < 0 )

adWaveData[ nDataCnt ] = (-1) * dbAmp / (250/dbFrequency) * nRemain + dbOffset - dbAmp;

else if( 0 <= nRemain && nRemain < 500/dbFrequency )

adWaveData[ nDataCnt ] = dbAmp / (250/dbFrequency) * nRemain + dbOffset - dbAmp;

else if( 500/dbFrequency <= nRemain && nRemain < 1000/dbFrequency )

adWaveData[ nDataCnt ] = (-1) * dbAmp / (250/dbFrequency) * nRemain + dbOffset + 3 * dbAmp;
}


さて、前回ののこぎり波は右上がりの一次式:y = a x + b (0 < a) が連続しているだけでしたが、
今回は傾きが周期毎に+、-と変化しています。三角形が右上がり(左下がり)、左上がり(右下がり)の直線の形になってるからですね。
ですが、基本は y = a x + b の形の式です。
±dbAmp / ( 250 / dbFrequency ) が傾き±aの部分です。

nRemain が現在の横軸の点の位置(x)になります。
nDataCnt がインクリメントするごとにサンプリング間隔毎に点が移動するので、
nInterval * nDataCnt(ms) になります。

更に位相ずれ分(横軸に平行移動)を考慮した部分が - 1000 * dbPhase / 360 になります。

全体を最終的に % (int)( 1000 / dbFrequency ) してる部分が作成したい波形の
周期を考慮した部分です。
これにより、nInterval * nDataCnt(ms) 部分が周期 (1000 / dbFrequency) を超えたら nRemain が 0 に戻ります。
この部分が周期関数を実現している部分になります。

さて、以前紹介した矩形波(のこぎり波)には無かった、250 / dbFrequency の部分ですが、
この波形の式は始まり(x=0)の値が最小値から始まった式になってます。よってsin波等と同じく
dbOffset値(0点)から始める為にx軸方向に1/4周期平行移動している分になります。

矩形波、のこぎり波:
nRemain = (int) ( nInterval * nDataCnt - 1000 * dbPhase / 360 ) % (int) ( 1000 / dbFrequency );
三角波:
nRemain = (int) ( nInterval * nDataCnt - 1000 * dbPhase / 360 + 250 / dbFrequency ) % (int) ( 1000 / dbFrequency );


次にb:一次式のy切片の部分です。

dbOffsetは波形の縦軸方向中間位置を表し、波形全体を縦軸方向に平行移動させます。
場合分け毎全ての式において共通の部分です。
以下場合分け毎のy切片の説明です。

・-1000 < nRemain && nRemain < -500 / dbFrequencyの時は
 右上がりの直線なので、y切片は dbOffset + 3 * dbAmp となります。

・500 / dbFrequency < nRemain && nRemain < 1000 / dbFrequencyの時は、
 右下がりの直線なので、y切片は dbOffset - 3 * dbAmp となります。

・-500 / dbFrequency < nRemain && nRemain < 0 及び
 0 < nRemain && nRemain < 500 / dbFrequency の時は隣り合う三角形同士境目(極小値)の部分なので、
 dbOffset - dbAmp となります。

では、また。

こんにちは。ひらのです。


セキュリティの理由から

「印刷物はプリンターに放置しておくな!」

というのはどこの企業でも気をつけていると思います。


プリントした紙の取り忘れ防止に、

パークではプリンターから印刷物が出てきたら

光ってお知らせする装置を販売しています。


今回はこの装置、"排紙検知灯"(検知灯)を取り上げます。


目次
  • 検知灯ってどう使うの?
  • 検知灯の性能は?
  • 入手から設置まで
  • 検知灯を手に入れる


  検知灯ってどう使うの?

排紙検知灯(c)Park

検知灯は、紙を認識するセンサーと

ライト部分でできています。


このセンサーをプリンターの紙が出てくる部分において、

検知灯をどこか目立つ場所に置いておきます。


あとは、紙が出てきたら自動で光って

お知らせしてくれます。


紙をプリンターから退かすと光は消えます。


  検知灯の性能は?

検知灯を眺め回してみて、以下のことが気になりました。

(1)透明な紙でも認識してくれるのか?

(2)暗いところで光りっぱなしにならないか?

(3)プリンタとライト部分はどこまで離せるか?


ということで、実験してみました。



(1)透明な紙でも認識してくれるのか?

iPhone購入時にくっついてきた透明な紙(?)を

センサーに乗っけてみました。

透明な紙

あ、光りますね。

薄かったり透明だったりする紙でも認識してくれるようです。


(2)暗いところで光りっぱなしにならないか?

センサーをキャビネットに入れてみました。

真っ暗闇センサーをキャビネットの中に入れました。

あ、光りませんね。


これなら、社内の照明を消したら検知灯だけ

ピカピカ光っているという、

電気のもったいない話にはなりませんね。


(3)プリンターとライト部分はどこまで離せるか?

センサーとライト部分までのケーブルの距離を測ってみました。

ケーブルの長さ


プリンタから3mまで離せますが、

ケーブルをどこに這わせるかは各オフィスでご検討くださいm(_ _)m


  入手から設置まで

自社製品なので、私は社長にお願いして

製品版の検知灯を取り寄せてもらいました。


届いた段ボールに入っていたのは、この2つ。

部品(ランプタワー・センサー・コントローラー)部品(ACアダプター)


組み立て作業は特にいらないようですね。

電源を入れたら即使えました。


  検知灯を手に入れる

現在、排紙検知灯は仕様を変えて、
東興産業株式会社様にて取り扱っております。

以下、HPをご覧いただきお問い合わせ頂くか、
Amazonでも販売されているようですのでそちらをご覧下さい。

http://www.toukousangyo.com/__jushindenshin.html

最近 WebView を利用したスマートフォン(iPhone/Android)アプリを
作成する機会がありました。

フリックで行を動かしたりページを変えてみたりしたのですが、
なんとこれでページのスクロールができなくなってしまいました!

原因は、touchstart、touchmove、touchendに紐づけていた
関数で利用したpreventDefault()。

touchイベントでpreventDefault()を使うと、
デフォルトのスクロールが効かなくなってしまうんですね!(@▽@)


これを回避するために、今回iScrollというものを使ってみました。


え?そもそもpreventDefault()使うのが間違っている?

おっしゃるとおりなんですが、画面の上をスワイプしたりページをAJAX通信で
変更させてみたりするときにpreventDefault()を使わざるをえなかったんですorz

----------

では、iScrollの基本的な使い方を解説していきます。

■この記事の対象者■
下記を満たす方
  • jQuery を触ってみたことがある
  • html を書いてみたことがある
  • cssでの「#hoge」や「.hoge」といった
    書き方が何を意味しているか分かる


■作成するページ■
ページの一部をスクロールできるページ



まずはiScroll 4から iscroll-4.zip をダウンロードします。

ダウンロードしたzipを解凍して、iscroll.jsがあるのを確認します。

iscroll.jsを入手できたら、htmlとcssを準備します。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title></title>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="application/javascript" src="./src/iscroll.js"></script>
<style type="text/css" media="all">
/* iscrollとは関係ないスタイル */
div {
margin: 0;
padding: 0;
}
#wrapper {
padding: 10px;
background-color: #ffaaff;
}
#wrapper-scroll {
height: 100px;
background-color: #ffffff;
}
#layer01 {
height: 150px;
background-color: #aaffff;
}
#layer02 {
height: 150px;
background-color: #ffffaa;
}
</style>
</head>
<body>
<div id="wrapper">
<div id="wrapper-scroll"> <!-- wrapper -->
<div id="layer01"> <!-- scroller -->
<script type="text/javascript">
for(var i = 1; i <= 9; i++) {
document.write(i + "行目<br />");
}
</script>
</div>
<div id="layer02">
<script type="text/javascript">
for(var i = 1; i <= 9; i++) {
document.write(i + "行目<br />");
}
</script>
</div>
</div>
</div>
</body>
</html>


見た目はこうなります。
iscroll:htmlとcss


1つ1つ説明していきますネ。

■プラグインへのリンク
<head>内で jQuery と flickSimple にリンクを張ります。

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="application/javascript" src="./src/iscroll.js"></script>

iScroll は jQuery を使用しているので、
iScroll の前に jQuery にリンクを張ってあげてください。

iScroll のスクリプトのパスは、どこに iScroll をダウンロードしたかで変わります。


■html

<div id="wrapper">
<div id="wrapper-scroll"> <!-- wrapper -->
<div id="layer01"> <!-- scroller -->
<script type="text/javascript">
for(var i = 1; i <= 9; i++) {
document.write(i + "行目<br />");
}
</script>
</div>
<div id="layer02">
<script type="text/javascript">
for(var i = 1; i <= 9; i++) {
document.write(i + "行目<br />");
}
</script>
</div>
</div>
</div>

id が「wrapper-scroll」の中身をスクロールできるように組んでいます。
iScroll適用後にスクロールしているのが分かりやすいよう、
wrapper-scroll の中身が wrapper-scroll より大きくなるように
CSSで設定しています。

Google Chrome の Developer tools で確認すると、wrapper-scroll の位置が分かりますネ。
iscroll:wrapper


スクロール時に見えている高さを決める wrapper-scroll 部分は
ページ全体で一意に決まる要素になっている必要があります。
なので、id名をふってあげましょう。


■iScroll を適用する。
細かい説明は後回しにして、iScroll を適用します。

<head>内に下記を追加してください。

<script type="text/javascript">
$(window).load(function(e) {
new iScroll("wrapper-scroll");
});
</script>

new iScroll()の引数にはフリックさせる範囲を示す要素の id 名を指定します。


iScroll を適用すると、見た目がこのように変わります。
iscroll:適用

一番下までスクロールするとこんな感じ。
iscroll:スクロール

iScroll 適用前と見た目がだいぶ変わりましたね。
id が layer02 の要素は見えもしません。

オマケに生成された html を Developer tools で確認すると、
なんだかごちゃごちゃしているのが分かります。
iscroll:適用後のhtml


ここで、iScroll の仕組みを説明しましょう。

iScroll は new iScroll() の引数で指定した要素をスクロールの表示画面に、
その要素の1番目の子供を実際にスクロールして見たい html とみなします。

なので、new iScroll() の引数に指定した id="wrapper-scroll" の要素の
範囲のみが見えるようになりました。

そして、1番目の子供の id="layer01" の要素をスクロールして見れるようになっています。

2番目の子供は無視されてしまうので、下までスクロールしても見えません。

でも、消されたわけではないので、ちゃんといます。
iscroll:2番目以降の子供


iScroll は実際にスクロールしたい要素を動かしてスクロールしているように見せかけています。
なので、id="layer01" に指定された style の値はスクロールする度に変化します。

また、iScroll は独自のスクロールバーを出すので
id="wrapper-scroll" の最後にスクロールバー用の<div>が追加されています。

スマフォではスクロール時だけスクロールバーが見えるようになります。

----------

この状態では画面の一部分しかスクロールできませんが、
wrapper-scroll と 1番目の子供を画面全体を囲む div にしてあげれば、
画面全体をスクロールすることができます。


■iScroll 注意点
iScroll を適用すると、長押し(ロングタップ)でコピー・ペーストダイアログが表示されなくなります。
これは、touchstart を受け取った場合に preventDefault() を実行しているためです。

長押し(ロングタップ)を無効化したくない場合は、
iscroll の iScroll = function・・・ 内を下記のように改造します。

onRefresh : null,
onBeforeScrollStart : function(e) {
// e.preventDefault(); // comment out : 長押し有効化のため
},
onScrollStart : null,
// onBeforeScrollMove: null, // comment out
onBeforeScrollMove : function(e) { // add : デフォルトスクロール無効化のため
e.preventDefault();
},



----------
では、今回はここまで!
この記事は「flickSimpleでフリック!」の3回目です。


本記事の第1回目
「flickSimple を使うと Android でスクロールができなくなる」
と書きました。

これは、flickSimple 中でクライアントが Android の場合に
event.preventDefault() を実行しているためです。
これによりデフォルトのスクロール機能が無効になってしまいます。

じゃぁ、デフォルト以外の方法でスクロールを実現すればいいんじゃないの?
ということで、私は iScroll というライブラリを使ってみました。

iScroll の基本的な使い方は「iScrollでスマフォスクロール!」で紹介していますので、
ここではページ全体をスクロール可能にする部分のみご説明します。

----------

まずは、サンプルの見た目とコードをお見せします。

見た目
flickSimple : iscrollでスクロール

<meta charset="UTF-8">
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="./jquery.flicksimple.js"></script>
<script type="text/javascript" src="../../スクロール/iscroll-4/src/iscroll.js"></script>
<style>
/*-- 見た目のためのスタイル --*/
.p1 > div {
background-color:#ffffaa;
}
.p2 > div {
background-color:#ffaaff;
}
/* clearfix */
.flick-visible:after {
display: block;
clear: both;
height: 0px;
visibility: hidden;
content: ".";
}

/*-- flicksSimple用スタイル --*/
.flick-visible {
width: 200px;
margin: 10px;
border: red 1px solid;
}
.flick-visible > ul {
display: block;
margin: 0;
padding: 0;
width: 200%;
list-style-type: none;
}
.flick-visible > ul > li {
display: table-cell;
margin: 0;
padding: 0;
width: 200px;
line-height: 500%;
float: left;
}

/*-- iscroll用スタイル --*/
body {
margin: 0;
padding: 0;
}
/* 見えている部分を示す要素 */
#wrapper {
margin: 0;
padding: 0;
width: 100%;
}
/* スクロールさせる範囲 */
#scroller {
margin: 0;
padding: 0;
padding-bottom: 10px; /* 微調整 */
width: 100%;
}
</style>
</head>
<body>
<div id="wrapper">
<div id="scroller">
<div id="flick1" class="flick-visible">
<ul>
<li class="p1"><div>1ページめ</div></li>
<li class="p2"><div>2ページめ</div></li>
</ul>
</div>
<div id="flick2" class="flick-visible">
<ul>
<li class="p1"><div>1ページめ</div></li>
<li class="p2"><div>2ページめ</div></li>
</ul>
</div>
<div id="flick3" class="flick-visible">
<ul>
<li class="p1"><div>1ページめ</div></li>
<li class="p2"><div>2ページめ</div></li>
</ul>
</div>
<div id="flick4" class="flick-visible">
<ul>
<li class="p1"><div>1ページめ</div></li>
<li class="p2"><div>2ページめ</div></li>
</ul>
</div>
<div id="flick5" class="flick-visible">
<ul>
<li class="p1"><div>1ページめ</div></li>
<li class="p2"><div>2ページめ</div></li>
</ul>
</div>
</div>
</div>
</body>
</html>

$(window).load(function(e) {
for (var i = 1; i <= 5; i++) {
$("#flick" + i).flickSimple();
}
new iScroll("wrapper");
});



iScroll でページ全体をスクロールさせる部分にフォーカスして説明します。


■ページ全体を囲むDIV要素

<body>
<div id="wrapper">
<div id="scroller">
<div id="flick1" class="flick-visible">
<!-- 省略 -->
</div>
</div>
</div>
</body>

BODY要素の直下にユーザーに見える範囲を示すDIV要素(#wrapper)、
その下にスクロール範囲を示すDIV要素(#scroller)をつくります。

ここで、#scroller の高さを iScroll を適用した結果を見ながら調整しました。

/* スクロールさせる範囲 */
#scroller {
margin: 0;
padding: 0;
padding-bottom: 10px; /* 微調整 */
width: 100%;
}

iScroll は #scroller の top プロパティの値を変更することで、
スクロールしているように見せています。

iScroll を適用すると、#scroller の右にスクロールバー全体を表わすDIV要素が挿入されます。
この挿入されたDIV要素の clientHeight と、iScroll により挿入されたスクロールバーの差を
#scroller の top プロパティに指定する値のMAX値としています。

このMAX値、私たちがスクロールしてほしい範囲よりも小さくなってしまうことがあります。
(float プロパティを使うと正確なサイズを取得できないのは、よくあることですね^^;)

なので、ちょっとした高さ調整が必要になります。


■ iScroll による回避策の問題点
flickSimple でフリックもできたし、iScroll でスクロールもできました。
でも、実はこの組み合わせで問題が発生しました。

一部のAndroid端末にて、右方向にフリック中に一瞬ページ全体が右にずれるんですね。
残念ながら原因の特定にはいたっておりません。。。

このときは flickSimple ではなく flipsnap という別のプラグインを改造して
フリックを実現させました。


flipsnap については別の機会にご説明したいと思います。



では、今回はここまで!