2011年8月18日木曜日

ImageViewでスクロール

Androidアプリの画像閲覧ソフトで、
画像が大きいと、ドラッグでスクロールとか、
フリックで慣性っぽいスクロールとかよくあるので
できるかやってみました。

参考サイト様はこちら


使うのは、Scrollerというクラスです。ScrollViewは使いません。
コードは結構適当なので注意してください。

public class ScrollImageView extends ImageView implements OnGestureListener,OnDoubleTapListener{
  private GestureDetector gesDetector;
  private Scroller viewScroller = null;
  //ビューの最大/最小 X座標
  private int _limitX;
  //ビューの最大/最小 Y座標
  private int _limitY;
  //画像の幅
  private int _imageWidth;
  //画像の高さ
  private int _imageHeight;

  public ScrollImageView(Context context,AttributeSet attrs) {
    super(context,attrs);
    this.setClickable(true);
    //Scrollerの生成
    //DecelerateInterpolatorで、徐々に減速する動作になる
    viewScroller = new Scroller(getContext(),new DecelerateInterpolator());
    gesDetector = new GestureDetector(this.getContext(),this);
    gesDetector.setIsLongpressEnabled(true);
    gesDetector.setOnDoubleTapListener(this);
    this.setOnTouchListener(new View.OnTouchListener() {
      @Override
      public boolean onTouch(View v, MotionEvent event) {
        if(gesDetector.onTouchEvent(event)){
          return true;
        }
        return false;
      }
    });
  }

  //画像の大きさを記録するため、setImageBitmapをオーバーライドする
  @Override
  public void setImageBitmap(Bitmap image){
    //画像を設定する際に、幅と高さを記憶しておく
    _imageWidth = image.getWidth();
    _imageHeight = image.getHeight();
    super.setImageBitmap(image);
  }

  @Override
  public void computeScroll() {
    //現在のスクロール位置をシミュレートする?
    if ( viewScroller.computeScrollOffset() ) {
      //スクロール位置を取得
      int setX = viewScroller.getCurrX();
      int setY = viewScroller.getCurrY();

      if(setX > _limitX){
        //右端の座標を越えていないかチェック
        setX = _limitX;
      }
      else if(setX < -_limitX){
        //左端の座標を越えていないかチェック
        setX = -_limitX;
      }
      if(setY > _limitY){
        //下端の座標を越えていないかチェック
        setY = _limitY;
      }
      else if(setY < -_limitY){
        //上端の座標を越えていないかチェック
        setY = - _limitY;
      }
      //setX,setYの絶対座標へスクロールする
      scrollTo(setX, setY);
    }
  }

  @Override
  public boolean onDown(MotionEvent e) {
    //スクリーンダウン時に境界値を再計算する
    //機体の向き変更とかに対応するため、だが、
    //タッチ時に一々再計算が入るので、別の位置に入れたい・・・
    refreshLimit();
    return false;
  }

  @Override
  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    //フリック時の挙動
    int currentX = getScrollX();
    int currentY = getScrollY();
    int targetX = 0;
    int targetY = 0;

    targetX = currentX - (int)velocityX / 2;
    targetY = currentY - (int)velocityY / 2;
    viewScroller.startScroll(currentX, currentY, targetX - currentX, targetY - currentY,500);
    invalidate();
    return true;
  }

  @Override
  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    //ドラッグ時のスクロール
    //移動距離取得
    int setX = (int)distanceX;
    int setY = (int)distanceY;
    //移動後の座標位置を計算
    int afterX = this.getScrollX() + setX;
    int afterY = this.getScrollY() + setY;

    //はみ出てないかチェック
    if(afterX > _limitX || afterX < -_limitX){
      //はみ出す場合、移動距離を0にする
      setX = 0;
    }
    if(afterY > _limitY || afterY < -_limitY){
      setY = 0;
    }
    //ビューのスクロール(相対距離指定)
    scrollBy(setX, setY);
    return true;
  }

  //座標の限界値を計算する
  private void refreshLimit(){

    //画像サイズから、移動範囲を計算する
    //ScaleTypeがCENTERだからか、画像の中心が(0,0)のため、
    //X座標は、画像の幅/2の数値が右端、-(画像の幅/2)の数値が左端となる
    //Y座標も同様
    //また、ビュー自体のサイズも関係するため、
    //ビューが移動できる座標の限界値は、
    // (画像幅 - ビュー幅) /2 になる
    if(_imageWidth < getWidth()){
    _limitX = 0;
    }
    else{
      _limitX = (_imageWidth - getWidth())/2;
    }
    if(_imageHeight < getHeight()){
      _limitY = 0;
    }
    else{
      _limitY = (_imageHeight - getHeight())/2;
    }
  }

}

こんな感じです。 今作成中のやつから必要なところを抜粋してきたので、 このままだと動作しないかもしれません。

次は慣性スクロール中にドラッグしたときに 慣性スクロールを止めるやり方を調べます。

8/21追記

スクロールの中断は、上記参考サイト様に載ってましたね。 viewScroller.forceFinished(true); で止められます。

onDownにのrefreshLimit()の前にforceFinished(true) を追加でストップできました。

11/06追記

持ってる実機がAsusのタブレットなのでandroid3.0向けにコードを書いているんですが、 ためしにandroid2.1のエミュレータで実行してみたところ、画像が表示されないことがわかりました。 3.0や4.0のエミュレータだと表示されるんですが。。。うーん、原因がわかりません。

12/19追記

やっと原因がわかりました。 というか、上に挙げてるコードだと問題ないですね。 抜粋元(自分で実装した)のコード内にあった、onMeasureをオーバーライドしていた箇所で 変なことをやってたみたいです。。。なんでこんなことやってたんだろ? アホの子か俺は。

2011年8月16日火曜日

取りあえず



作成中のアプリの記録を残しておこうと思います。

取りあえず、今のところは、

フォルダ階層の移動


Windowsの論理ドライブ表示


画像表示とフリックでの次の画像へ移動


ZIPファイル内のファイル表示(UTF8で固めていないと化けます)と画像ファイルの表示
MP3とZIP内のMP3の再生(するだけ。。。)

が可能な感じ。
バグ多し。でかい画像読むとOutOfMemory吐かれます。。。

先は長い。

2011年8月15日月曜日

ObjectInputStreamの進捗を知りたい

早速メモ1つ目。。。

Socketでの通信で、ダウンロードの進捗をプログレスで出したい時の方法です。

読み込みのループ処理で、読み込みバイト数をカウントする方法もありますが、
ObjectInputStreamのreadObjectでは使えないので。。。


結論から言うと、CountingInputStreamを使用します。
CountingInputStreamは、org.apache.commons.ioパッケージにありますので、
この辺から入手してください。
http://commons.apache.org/io/

使い方は簡単です。
例えば、ObjectInputStreamの読み込み状況を知りたいときは、以下のように書きます。

private CountingInputStream cis = null;
.
.
.
public void readObjectBySocket(InetAddress address, int port){
  try{
    Socket sock = new Socket(address,port);
    cis = new CountingInputStream(sock.getInputStream());
    ObjectInputStream inStream = new ObjectInputStream(cis);
    receiveObject = inStream.readObject();
 
    inStream.close();
    cis.close();
    sock.close();
  }
  catch(Exception e){
    e.printStackTrace();
  }
}

//cisからダウンロード完了したバイトサイズを取得するには、getByteCountを使用します。
public long getCount(){
  if(cis==null){
    return 0;
  }
  return cis.getByteCount();
}


こんな感じ。例外とかは適当です。
ただし、readObject()で受信完了待ちになるので、
別スレッドなどから
cisにアクセスしましょう。
3.0からは、通信処理は、AsyncTaskでやる必要があるので、ちょうどいいです。

多分これで取得できるはず。。。

久々に更新

久々にメモ。

6月末に ASUS Eee Pad Transformer TF101 を購入しました。
ので、今Androidのアプリ側のプログラムをセコセコ楽しんでます。

作っているのは、
画像再生+音楽再生機能を持ったアプリですが、
デスクトップPC側に自作のJavaサーバプログラムを仕込んで、
PC側に繋げて、ネットワーク経由でPCのファイルをワサワサと閲覧しよう。
というアプリです。
Androidの中のファイルは見れませんが。

というわけで、現在、Android側と、Java側のプログラムを
モサモサと作成中です。


ちょくちょく詰まるので、メモを残そうと思います。

2008年12月30日火曜日

諦めが肝心ですよね

とりあえずideaPadにFedora入れたんですが
KDEだからか知らんが重い重い。

結局uhbuntuに戻しちゃいましたよ。

まぁubuntuでも無線の認識方法は同じなのでここにメモっときます。
ってもndiswrapper入れて認識させるだけですがね。

補足)ここから先色々と書いてますが,適当にネットをブラついていたところ,どうやらubuntuのアップデートかけるだけで無線LANは認識することができるようです。俺,無駄な作業乙。
Fedoraの場合はどうかわからないし,せっかくなので残しときます。



ubuntuは普通にapt-getで楽に入るんですが,
Fedora10のyumで入れようとしたのですがなかなか入ってくれません。
なんで

http://atrpms.net/dist/f10/ndiswrapper/

ここからrpmを落っことして入れましょう。
後は

http://www-06.ibm.com/jp/domino05/pc/download/download.nsf/jtechinfo/MIGR-71123

ここからwindowsXP用の無線LANのドライバ(54wg03ww.exe)を落として,
exeを解凍します。

ここでめんどいことにlhzでもunzipでもうまく解凍できなかったので
windows上でexeを実行して解凍させました。

後はndiswrapperで解凍したDriverディレクトリのbcmwl5.infをrootで

#ndiswrapper -i bcmwl5.inf

でもって

#modprobe ndiswrapper

これで無線LANが使えるはず。

ただ,Fedora10だと起動時に認識させるには
/etc/modprobe.confになんか書き加えるらしいんですが
どうにもうまくいかない。

alias wlan0 ndiswrapper

とか色々やったんですがダメでした。
いちいち起動した後
#modprobe ndiswrapper
とやるのがめんどくせぇ。
それにコンソールの挙動もなんだかおかしい。複数のタブを開いて
どれか閉じるとどうにも入力できなくなる。
新しいタブを開くとまた入力できるのですが・・・。
それに動作がモサモサだ。

なんで結局ubuntuに戻しました。
でもこれだとwindマシンと同じだしなぁ。
むつかしいですよね・・・。

ああ,ちなみにEkiga入れてみて試したところ,
一応WebカメラはFedoraでも使えましたよ。

そろそろほとぼりも冷めたと思うのでNOINDEXを外しました。

2008年12月24日水曜日

lenovo ideaPad + fedora

1個前にubuntuでも入れるかと書きましたが
やっぱりfedoraを入れてみました。

どうにもインストールDVDの読み込みがうまくいかないみたいで
ディスクチェックで引っかかる。

しかたないのでライブCDから入れました。
デスクトップ環境は、ubuntuはgnomeなんでKDEにしてみました。
まぁ重いんですけどね。


とりあえず入ったものの調子がよろしくなくて
何回か入れ直しました。

気になるのは無線とbluetoothとwebカメラの認識状況か。
正直bluetooth機器持ってないので青歯は確認できてない。

無線はndiswrapperでかましてできました。
webカメラは・・・うーん
一応認識はしてるみたいですがKDEのインスタントメッセンジャー
だとうまく映ってなかったです。

その内他のアプリ使って確認してみよう。

無線の詳しい手順はその内書きます。

2008年12月22日月曜日

入れ直し

ubuntuを8.10にしてみました。
クリーンインストールなんで
入れた後2.6.27-7から2.6.27-9にアップグレードしました。


まぁいつもの様に入れただけでは無線LANは認識してくれません。


ただ、今回は前の様にめんどい作業はしないて
公式のフォーラム?からドライバ持ってきましたよ。

参考サイト様
ふらんす滞在記@らんだむそーつ


http://forums.msiwind.net/debian/rtl8187se-drivers-for-ubuntu-and-deb-packages-t4954.html

ここから
http://boskastrona.ovh.org/download/linux-rtl8187se-modules-1023@2.6.27.7.11.deb (Intrepid, official release)
を落としてインスコ

2.6.27-9に上げて、上のさっき入れた奴を抜いてから
http://boskastrona.ovh.org/download/linux-rtl8187se-modules-1023.2@2.6.27.9.19.deb (Intrepid, 2.6.27.9 kernel, official release)
をインスコしました。

有線で繋げられるなら2.6.27-7の方は入れる必要はないです。



lenovoのideaPadを手に入れてみました。
こっちにはFedora10でも入れてみようかと思いましたが色々面倒くさそう
なんでとりあえずはubuntuでも入れておきます。