Android Viewのスクロールscroll、android.widget.Scrollerと属性translationX/Y


Viewでのscroll関連メソッド
public void computeScroll(){//空実装、サブview書き換え時にスクロールを計算してスクロール動作を実現するために使用される}
public void scrollTo(int x,int y){//viewの(left,top)1点(x,y)賦値までスクロール
        if (mScrollX != x ||mScrollY != y) {
            int oldX = mScrollX;
            int oldY = mScrollY;
            mScrollX = x;
            mScrollY = y;
            invalidateParentCaches();
            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
            if (!awakenScrollBars()) {
                postInvalidateOnAnimation();
            }
        }
}
public void scrollBy(int x,int y){//viewの(left,top)スクロールする必要がある距離は(x,y)累計
     scrollTo(mScrollX + x, mScrollY + y); 
}
public finalint getScrollX() {
     return mScrollX;//最後にスクロールしたleft座標値
}
public finalint getScrollY() {
     return mScrollY;//最後にスクロールしたtop座標値
}
scrollスクロール結果の説明:
scrollToでもscrollByでも最後はある点までスクロール(x,y)
インタフェースに現れる変化は,コンテンツ領域(x,y)の位置を画面の(0,0)座標に移動することである.
SlidingMenuでは、一般的にscrollTo(leftMenuWidth,0)が先行し、x=leftMenuWidth,y=0の座標点まで右方向にスクロールすることを示す
このとき、この座標点以降の内容を画面の(0,0)位置に移動して表示します
>Viewの内容を左にスクロールする場合は、scrollXが正数を入力します.逆に負を伝えて右へ転がす
>Viewのコンテンツを上にスクロールする場合、scrollYは正数を入力します.逆に負を伝えて下へ転がす
イメージはこう言います.
最初は、スクロール(Scroll)とViewの内容の左頂点が重なる.
スクロールのx,yが変化すると、例えばx=100となり、その時点でスクロールの位置(100,0)がViewの(0,0)点となり、
viewのx方向には-100の内容が見えなくなった.つまり左にスクロールして
総じて言えば、viewのスクロール方向が画面座標方向とは逆です
computeScrollについて:
ビューを呼び出すinvalidate(); メソッドがトリガーされます.
この方法を書き換える場合、内部にはandroidが一般的に使用される.widget.スクロールを処理するためにScroller
android.widget.Scroller
Viewのコンテンツスクロールは、View自体の位置を変えることなく、コンテンツをスクロールするだけです
構築方法:
   public Scroller(Context context) {
        this(context, null);
    }
public Scroller(Context context,Interpolator interpolator){//補間器Interpolatorを使用
        this(context, interpolator,
                context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);
    }
   public Scroller(Context context, Interpolator interpolator,boolean flywheel) {
        mFinished = true;
        mInterpolator = interpolator;
        mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
        mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
        mFlywheel = flywheel;
        mPhysicalCoeff = computeDeceleration(0.84f);//look and feel tuning
    }
一般的には2つ目の構造方法を使用すれば、スクロール効果があまりにも突兀ではなく、InterpolatorがLinearInterpolator(均一な運動)に伝わればよい.
いくつかの重要な方法:
/*
*スクロール開始
*startX,startY:スクロール開始x,y方向のオフセット量;正数は左から始まる
*距離dx,dy:正数が左に移動
 */
public void startScroll(int startX,int startY,int dx,int dy) {
        startScroll(startX, startY, dx, dy, DEFAULT_DURATION);
    }
//スクロール開始(,,,,,スクロール継続時間)
public void startScroll(int startX,int startY,int dx,int dy,int duration) {
        mMode = SCROLL_MODE;
        mFinished = false;//スクロールが終わるか
        mDuration = duration;
        mStartTime = AnimationUtils.currentAnimationTimeMillis();
        mStartX = startX;
        mStartY = startY;
        mFinalX = startX + dx;//スクロールする必要がある最終点x
        mFinalY = startY + dy;//スクロールする必要がある最終点y
        mDeltaX = dx;  
        mDeltaY = dy;
        mDurationReciprocal = 1.0f/(float)mDuration;
    }
//ジェスチャーベースのスライド
public void fling(int startX,int startY,int velocityX,int velocityY,
            int minX, int maxX, int minY, int maxY) {
    ...}
public boolean computeScrollOffset() {
        if (mFinished) {
            return false;
        }

        int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
    
        if (timePassed < mDuration) {
            switch (mMode) {
            case SCROLL_MODE:
                float x = timePassed * mDurationReciprocal;
    
                if (mInterpolator == null)
                    x = viscousFluid(x); 
                else
                    x = mInterpolator.getInterpolation(x);
    
                mCurrX = mStartX + Math.round(x * mDeltaX);
                mCurrY = mStartY + Math.round(x * mDeltaY);
                break;
            case FLING_MODE:
                final float t = (float) timePassed / mDuration;
                final int index = (int) (NB_SAMPLES * t);
                float distanceCoef = 1.f;
                float velocityCoef = 0.f;
                if (index < NB_SAMPLES) {
                    final float t_inf = (float) index / NB_SAMPLES;
                    final float t_sup = (float) (index + 1) / NB_SAMPLES;
                    final float d_inf = SPLINE_POSITION[index];
                    final float d_sup = SPLINE_POSITION[index + 1];
                    velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
                    distanceCoef = d_inf + (t - t_inf) * velocityCoef;
                }

                mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;
                
                mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
                // Pin to mMinX <= mCurrX <= mMaxX
                mCurrX = Math.min(mCurrX, mMaxX);
                mCurrX = Math.max(mCurrX, mMinX);
                
                mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
                // Pin to mMinY <= mCurrY <= mMaxY
                mCurrY = Math.min(mCurrY, mMaxY);
                mCurrY = Math.max(mCurrY, mMinY);

                if (mCurrX == mFinalX && mCurrY == mFinalY) {
                    mFinished = true;
                }

                break;
            }
        }
        else {
            mCurrX = mFinalX;
            mCurrY = mFinalY;
            mFinished = true;
        }
        return true;
    }

computeScrollOffsetスクロールのオフセットを計算するには、次の手順に従います.
2つのスクロールモード:
  1.scroll-mode
スクロールのターゲット距離が分かる場合、startScrollメソッドを呼び出すと、このモードになります.
挿入器Interpolator(あれば)により、一定時間内にスクロールする必要がある距離を算出し、
最後に、スクロールされた目標点x,yは、mCurrxおよびmCurrYに格納される.
  2.fling-mode
スクロールの目標距離が分からない場合、ListView、GridView、ScrollViewなど、
指がスライドして跳ね上がる速度に基づいて目標の転がり距離を計算します.
最後に、スクロールされた目標点x,yは、mCurrxおよびmCurrYに格納される.
Scroller自身はviewをスクロールすることはできませんが、viewのスクロール値を計算するために使用されます.
 1.scroll-mode一般使用フロー
onToucheventでは、スクロールする距離dx,dyを算出してscrollerを呼び出すことができる.startScroll(...);view.invalidate();
viewのcomputeScrollでif(scroller.computeScrollOffset(){//スクロール未完了
       //1.算出された一定時間内にスクロールする必要があるターゲットポイントを取り出す
        int x = scroller.getCurrX();
        int y = scroller.getCurrY();
//スクロールの実行
        view.scrollTo(x, y);
        invalidate();
     }
invalidate後、viewが再度実行されます.computeScroll(); 最終的に必要なターゲットポイントまでスクロール
     
 2.fling-mode一般使用フロー
onTouchEventでscrollerを算出することができる.fling(...)必要ないくつかのパラメータ.
レート値は、VelocityTrackerクラスのcomputeCurrentVelocity()メソッドで計算できます.
GestureDetectorでtoucheventをリスニングし、GestureDetectorが初期化されたときにonFling()を書き換えることもできます.
すなわちジェスチャープローブは,flingの動作を検出するとトリガーされる.
scrollerを呼び出す.fling()後、スクロールしたターゲットポイントを算出します.またviewでcomputeScrollで使用します.使い方は同じです.
属性translationX/Y
//    
private void coordinatorRelation() {
    getLeft(); //view            
    getTop();
    getRight();
    getBottom();
//        setLeft(); //      set   

    getX(); //x = left + translationX;  view          x   
    getY(); //y = top + translationY;   view          y   
//        setX(); //      set   
    getTranslationX(); //          x       
    getTranslationY(); //          y       
//        setTranslationX(); //      set   
}
このオフセット属性を変更してスクロールするには、アニメーションに合わせる必要があります.
アニメーションは3.0以降にプロパティアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーションアニメーション
Animationを使うと、Viewの位置は変わりません
3.0のアニメーションに対応するライブラリ:
https://github.com/JakeWharton/NineOldAndroids
http://nineoldandroids.com/