画像が大きいと、ドラッグでスクロールとか、
フリックで慣性っぽいスクロールとかよくあるので
できるかやってみました。
参考サイト様はこちら
使うのは、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をオーバーライドしていた箇所で 変なことをやってたみたいです。。。なんでこんなことやってたんだろ? アホの子か俺は。
0 件のコメント:
コメントを投稿