QA@IT

[Titanium]ダブルタップやピンチ操作で画像を拡大・縮小させる方法

6276 PV

Titanium Mobile にて、iPhone にデフォルトでインストールされている「写真アプリ」みたいにダブルタップやピンチイン・ピンチアウトで画像の拡大・縮小させる実装方法を教えてください。

実現したいこと

  1. ピンチインで拡大、ピンチアウトで縮小
  2. 画像を拡大した状態でスクロールして、
  3. ダブルタップで拡大/縮小

(1) と (2) については、下記の記事を参考にして、scrollView 上に imageView を載せることで、実現させています。

しかし、(3) については、zoomToRect がTitaniumでは用意されていないため、

ダブルタップを検出した後、プログラムで拡大処理を行う必要がある。UIScrollViewにはその為のメソッドが用意されているのでこれを使う。
zoomToRect:animated:

[引用元]: Cocoaの日々: 簡易スライドビューア [3] ダブルタップで拡大
http://cocoadays.blogspot.jp/2010/09/3.html

代替案として、下記のようにダブルタップされたときに、画像のサイズが拡大率最小の場合、最大サイズに拡大して、タップされた座標にスクロールし、画像のサイズが拡大中(拡大率最小でない)の場合、最小サイズに縮小して、ベースの座標にスクロールするという実装をしています。

scrollView = Ti.UI.createScrollView({
    maxZoomScale: 2.0,
    minZoomScale: 1.0
});
imageView = Ti.UI.createImageView({
    image : 'images/example.jpg'
});

// ダブルタップで画像を拡大する
imageView.addEventListener('doubletap', function(e){
    var scrollView = e.source.getParent();
    var minZoomScale = scrollView.minZoomScale;
    var maxZoomScale = scrollView.maxZoomScale;
    if (scrollView.zoomScale === minZoomScale){
        var newX = e.x;
        var newY = e.y;
        scrollView.setZoomScale(maxZoomScale);
        scrollView.contentOffset = {x:newX, y:newY};
    }else{
        scrollView.setZoomScale(minZoomScale);
        scrollView.contentOffset = {x:0, y:0};
    }
});

scrollView.add(imageView);

しかし、この実装だとダブルタップしたときのズームインの動きがスムーズではなく、zoomToRect を使用して実装したいと考えています。

こういう場合、Titanium Mobile には、現状 zoomToRect に対応するものが用意されていないようなので、自分で iPhone 用のモジュールを Objective-C で書くしかないでしょうか?

よろしくお願いします。

回答

imageViewに2DMatrixを使ってみました。初期状態では画像はwindowの中央に表示されています。ダブルタップしたら画像をズームインしてタップした位置を中心に変更します。(手元にあったアン・ハサウェイの画像でテストしているので188x300の画像を扱っています)

function ApplicationWindow(title) {
  var self = Ti.UI.createWindow({
    title:title,
    backgroundColor:'white'
  });

  var imageView = Ti.UI.createImageView({
      top:100,
      height:188,
      width:300,
      image : '/images/example.jpg'
  });

  var scrollView = Ti.UI.createScrollView({
    maxZoomScale:2.0,
    minZoomScale:1.0,
    contentWidth:imageView.width * 4,
    contentHeight:imageView.height * 4,
    top:0,
    bottom: 0,
    showVerticalScrollIndicator:true,
    showHorizontalScrollIndicator:true,
    height:Ti.UI.FILL,
    width:Ti.UI.FILL
  });
  //self.add(imageView);
  scrollView.add(imageView);
  self.add(scrollView);
  scrollView.scrollTo(440, 0);

  // 元の位置に戻すときに使う。描画しないと値が入らない
  var orig_center = {x:0, y:0};

  self.addEventListener('open', function(e){
    // 描画したので実際の値を入れる
    orig_center = {x:imageView.animatedCenter.x, y:imageView.animatedCenter.y};
  });

  var zoomScale = true;

  // ダブルタップで画像を拡大する
  imageView.addEventListener('doubletap', function(e){
    var t = Ti.UI.create2DMatrix();
    if (zoomScale){    
      var newX = imageView.animatedCenter.x - (e.x - imageView.width / 2) * 2;
      var newY = imageView.animatedCenter.y - (e.y - imageView.height / 2) * 2;      
      var center = {x:newX, y:newY};
      t = t.scale(2.0, 2.0);
      imageView.animate({
        transform:t,
        center:center,
        duration:300
      });
      zoomScale = false;
    }else{
      imageView.animate({transform:t, center:orig_center, duration:300});
      scrollView.scrollTo(440, 0);
      zoomScale = true;
    } 
  }); 
  return self;

編集 履歴 (3)
  • ありがとうございます。2DMatrixを使った方法も自分で実装してみたのですが、これだと拡大した状態でスクロールして拡大した以外の箇所を見ることってできないですよね? -
  • scrollViewにaddして、contentHeightやcontentWidthを調整すればスクロールしますよ。 -
  • いい加減といえばいい加減ですが、scrollViewのcontentWidthを調整したり面倒なことが多いので、ざっくり画像の大きさから最初にcontentWidthを広めに確保しておいて動作させる方法にしてみました。 -
  • ありがとうございます。確認が遅くなりすみません。
    近々、組み込んでみます!
    -
  • 組み込んでみましたが、最初にcontentWidth を広めに確保してしまうと、スクロールバーが余分に出てしまいますね。iPhoneの写真アプリみたいな実装って難しいのだなと痛感しております。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。