English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
前書き
Android開発では、Viewは常にAndroid開発者の悩みの種でした。一方で上達を望んでいる一方で、上達を恐れているというのは、AndroidのViewは上達への道の上で最大の障害物です。なぜなら、その関わるものが多すぎるからです。例えば、今回書く予定のViewの移動、さらにViewのタッチイベントの伝達やカスタムViewの作成など、非常に重要で避けられない困難な課題が含まれています。しかし、どんなに困難であれ、今克服しない困難は将来必ず困難にされると言えます。
その前に、Android座標系の定義規則やViewの位置パラメータについてまず理解しておきましょう。
Android座標系
Viewの位置とサイズはleft、top、right、bottomの4つのパラメータによって決定されます。そして、これらの4つのパラメータはすべて親Viewに対して相対的です。
int width = right-left; int height = bottom-top;
Activityのレイアウトが完了した後、これらのパラメータ情報を取得するためにViewの一部のメソッドを使用できます:
//left,top,right,bottomの値の取得 int left = getLeft(); int top = getTop(); int right = getRight(); int bottom = getBottom();
さらにAndroid 3.0以降にx、y、translationX、translationYなどのパラメータを追加します。(x,y)はViewGroup内のViewの左上角のx、yの値を示し、translationX、translationYはViewを平移するために使用されます。デフォルトではすべて0で、ViewのsetTranslationX()が呼び出された後は0に変更されます。/setTranslationY()の後に変更が発生します。
//x,y,translationX,translationYパラメータの取得 int x = getX(); int y = getY(); int translationX = getTranslationX(); int translationY = getTranslationY();
PS:ViewのsetTranslationX()とsetTranslationY()メソッドを呼び出すと、Viewは指定された距離を平移することができますが、このプロセスは瞬時に完了します。Viewの移動をより滑らかにするために、Viewの属性アニメーションを使用してtranslationXとtranslationYを指定することができます。
ObjectAnimator valueAnimator = ObjectAnimator.ofFloat(textView, "translationX", 200); valueAnimator.setDuration(2000); valueAnimator.start();
また、ViewにsetTranslationX()とsetTranslationY()を設定した場合、設定された値が変更されていない場合、その値は一度だけ移動します。ソースコードを確認すると、その理由がわかります。設定値の後、設定された値と現在のtranslationX、translationYを比較し、異なる場合にのみ移動します。
Viewの基本的なパラメータについて理解した後、Viewの3つの移動方法について見てみましょう。
一、Androidシステムが提供するscrollTo()を使用する/scrollBy()メソッドはViewの移動を実現します。
scrollTo()やscrollBy()の移動の本質はViewです。/ViewGroupの中の内容です。その移動プロセスは瞬時に完了します。したがって、より良い移動効果を実現するために、Scrollerクラスと組み合わせて使用する必要があります。また、上記のTranslationとは異なり、View自体を移動するため、これはよく理解する必要があります。
scrollTo()とscrollBy()はViewの中のメソッドであり、Scrollerの中のメソッドではありませんが、Viewのスムーズな移動を制御するにはScrollerクラスと密接に関連しています。
scrollTo():これは絶対的な位置への移動を指します。位置が変更されていない場合、多次に呼び出しても効果がありません。
scrollTo移動プロセス図
scrollBy():その本質はscrollTo()を呼び出すことです。現在の場所と設定された距離の合計をscrollTo()に呼び出し、その結果、多次に呼び出すと、それぞれの回で一段ずつ移動するようになります。これはscrollTo()の本質との違いです。
scrollBy移動プロセス図
PS:上記の2枚の図について、実際には私自身も相対的および絶対的な概念が完全には理解できていませんでした。したがって、手図がより理解しやすくなるかもしれません。また、scrollTo()とscrollBy()の移動方向についても、上記でAndroidの座標系を描画しましたが、x軸は左から右に正、y軸は上から下に正です。しかし、これはscrollToとscrollByには適用されません。scrollToとscrollByは逆です。x軸は左から右に負、y軸は上から下に負です。これは非常に困ったことです。
Scrollerクラスの分析:なぜScrollerクラスのメソッドを使用してViewを/ViewGroupの内容をどう移動させるのでしょうか?以下に分析してみます。
まず
ScrollerクラスのオブジェクトmScrollerを生成します。
次に
Viewを指定された時間内に指定された位置に移動させるために、startScroll()メソッドを呼び出します。startScroll()はScrollerクラスのメソッドですが、Scrollerクラスにはfiling()メソッドというよく使用されるメソッドもあります。このメソッドは滑動の滑らかさを処理し、一般的にスライドの後の慣性効果を生成し、Viewの移動をよりリアルにします。次に、startScroll()のソースコードを見てみましょう:
//それが四つの/五つのパラメータがあります。durationが設定されていない場合、デフォルトの値が使用されます。これらの四つのパラメータは理解しやすいので、ここでは説明を省略します。 public void startScroll(int startX, int startY, int dx, int dy, int duration) { ... }
私たちがこのメソッドを呼び出した後は、一般的にViewのinvalidate()を呼び出します。このメソッドはViewのdraw()メソッドをトリガーします。draw()メソッドではcomputeScroll()が呼び出されます。ソースコードを確認すると、computeScroll()は空のメソッドであることが分かります。これがcomputeScroll()メソッドをオーバーライドする必要がある理由です。実際の移動操作はcomputeScroll()メソッド内で行われます。
@Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); //ViewのpostInvalidate()を呼び出す必要があります。/invalidate()を呼び出さないと、Viewの移動は最初のフレームのみになります。 postInvalidate(); } super.computeScroll(); }
上記ではScrollerクラスにcomputeScrollOffset()メソッドがあることを見ましたが、それは何をしているのでしょうか?主な役割はmCurrXとmCurrYが変更されているかどうかを判断し、変更がある場合はtrueを、ない場合はfalseを返すことです。このメソッドの判断を通じて、scrollTo()を呼び出してViewを移動する必要があるかどうかを決定できます。さらに、scrollTo()を使用してViewを指先の動きに合わせて移動させる例を示します:
public class CuView extends LinearLayout { private float mStartX; private float mStartY; private Scroller mScroller; /** * 最初のスライドが完了したかどうか */ private boolean isFirstFinish; public CuView(Context context) { super(context); init(context); } public CuView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context) { mScroller = new Scroller(context); } public CuView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public CuView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context); } /** * Viewを指先に追従させます * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: /** * 最初の移動が完了した後、再度始めの位置を取得する必要はありません。それでは、Viewが最初に移動する位置が変わります。 */ if (!isFirstFinish) { mStartX = event.getRawX(); mStartY = event.getRawY(); } break; case MotionEvent.ACTION_MOVE: scrollTo((int) (mStartX - event.getRawX()), (int) (mStartY - event.getRawY()); break; case MotionEvent.ACTION_UP: //最初の移動が完了しました isFirstFinish = true; break; } return true; } /** * startScrollのテスト */ public void startScroll() { /** * Scrollerの移動方向に注意してください。 */ 2 2 -500, -500, 5000); invalidate(); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate(); } super.computeScroll(); } }
2. アニメーションを使ってViewを移動する。
ここにはViewのTween Animationも含まれます。/Frame Animation、および30.0以降に追加されたProperty Animation。これはViewの映像を移動しますが、View自体の位置やサイズは何も変わっていません。
3. ViewのLayoutParamsを設定してViewを移動する
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) textView.getLayoutParams(); layoutParams.leftMargin = 50; textView.requestLayout();
まとめ
これでAndroid Viewの動きのまとめは以上です。3すべての内容をここにまとめました。この記事の内容が皆様のAndroid開発に役立つことを願っています。何か疑問があれば、コメントで交流してください。