English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
この記事では、Android ListViewのトップ画像をドラッグして大きくする具体例のコードを共有し、以下の内容を提供します。
Gitで素晴らしい人のコードを見てみると、他人のコードを逆コンパイルしていることが判明しました。コメントはまだ追加されていませんし、コードも完全にはコンパイルされていません。したがって、ここでは簡単なコメントを追加し、学習用に提供しています。
変数の説明
ここには、カスタムリターンアニメーション加速度、カスタムアニメーションスレッド、ヘッダー画像ビュー、最終的なy座標、作成した比率、大きくした比率などが含まれています。
private static final String TAG = "PullToZoomListView"; private static final int INVALID_VALUE = -1;//リセット値 //カスタム加速度アニメーション private static final Interpolator sInterpolator = new Interpolator() { public float getInterpolation(float interpolator) { float f = interpolator - 1.0F; return 1.0F + f * (f * (f * (f * f))); } }; private int mActivePointerId = INVALID_VALUE;//現在の手のID private FrameLayout mHeaderContainer;//ヘッダー private int mHeaderHeight;//ヘッダー画像の高さ private ImageView mHeaderImage;//ヘッダー画像 float mLastMotionY = INVALID_VALUE;//最終y座標 float mLastScale = INVALID_VALUE;//最終の比率 float mMaxScale = INVALID_VALUE;//最大の比率 private OnScrollListener mOnScrollListener;//スライドリスナー private ScalingRunnalable mScalingRunnalable;//アニメーションスレッド private int mScreenHeight;//スクリーン高さ private ImageView mShadow;//影マスク
カスタムViewの初期化:ヘッダーのヘッダーとマスクを設定し、リスナーを設定しました。
/** * 初期化 * @param paramContext */ private void init(Context paramContext) { DisplayMetrics metrics = new DisplayMetrics(); ((Activity) paramContext).getWindowManager().getDefaultDisplay().getMetrics(metrics); this.mScreenHeight = metrics.heightPixels;//スクリーン高さを設定 this.mHeaderContainer = new FrameLayout(paramContext);//ヘッダー this.mHeaderImage = new ImageView(paramContext);//ヘッダー画像 int screenWidth = metrics.widthPixels;//スクリーン幅 //ヘッダービューのスタイルを設定 スクリーンの幅を設定し、最大スタイルの高さはスクリーンの高さの9/16 setHeaderViewSize(screenWidth, (int) (9.0F * (screenWidth / 16.0F))); this.mShadow = new ImageView(paramContext);//シェード FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); layoutParams.gravity = Gravity.CENTER; this.mShadow.setLayoutParams(layoutParams);//シェードのスタイルを設定 //ヘッダーにViewを追加 this.mHeaderContainer.addView(this.mHeaderImage); this.mHeaderContainer.addView(this.mShadow); //ヘッダーを追加 addHeaderView(this.mHeaderContainer); //戻るアニメーションを初期化 this.mScalingRunnalable = new ScalingRunnalable(); //リスナーを設定 super.setOnScrollListener(this); }
アニメーションを開始:現在のヘッダーレイアウトの下部の位置が画像の初期高度を超えているかどうかを判断。
/** * アニメーションを開始 */ private void endScraling() { if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) { Log.d(TAG, "この.mScalingRunnalable.startAnimation("200L)"); this.mScalingRunnalable.startAnimation(200L); } }
マルチタッチ時、0番目の手を割り当てます。
/** * マルチタッチのときに押下され、0番目の手が指を上げた後、再び指を押下すると、押下されたイベントの手が指の指番号を現在の手が指の指番号として設定します。 * * @param motionEvent */ private void onSecondaryPointerUp(MotionEvent motionEvent) { Log.d(TAG, "onSecondaryPointerUp motionEvent.getPointerId(0) = "); + motionEvent.getPointerId(0)); Log.d(TAG, "onSecondaryPointerUp this.mActivePointerId = "); + this.mActivePointerId); if (motionEvent.getPointerId(0) == this.mActivePointerId) { this.mLastMotionY = motionEvent.getY(0); this.mActivePointerId = motionEvent.getPointerId(0); } Log.d(TAG, "onSecondaryPointerUp mLastMotionY = "); + mLastMotionY); Log.d(TAG, "onSecondaryPointerUp mActivePointerId = "); + mActivePointerId); }
すべてのデータをリセットします。
/** * すべてのデータをリセットします。 */ private void reset() { this.mActivePointerId = INVALID_VALUE; this.mLastMotionY = INVALID_VALUE; this.mMaxScale = INVALID_VALUE; this.mLastScale = INVALID_VALUE; }
上にスクロールしたときにレイアウトスタイルを変更します。
@Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { Log.d(TAG, "onScroll"); float bottomSpacing = this.mHeaderHeight; - this.mHeaderContainer.getBottom(); Log.d(TAG, "onScroll bottomSpacing = ") + bottomSpacing); if ((bottomSpacing > 0.0F) && (bottomSpacing < this.mHeaderHeight)) {//もし上にスクロールするとき int toUpScroll = (int) (0.65D * bottomSpacing); this.mHeaderImage.scrollTo(0, -toUpScroll); Log.d(TAG, "onScroll 向上スクロール toUpScroll = "); + toUpScroll); } else if (this.mHeaderImage.getScrollY() != 0) { Log.d(TAG, "onScroll this.mHeaderImage.getScrollY() = "); + this.mHeaderImage.getScrollY()); this.mHeaderImage.scrollTo(0, 0); } if (this.mOnScrollListener != null) { this.mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } }
異なるイベント処理、レイアウトスタイルの変更
@Override public boolean onTouchEvent(MotionEvent motionEvent) { switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_OUTSIDE: case MotionEvent.ACTION_DOWN: if (!this.mScalingRunnalable.mIsFinished) { this.mScalingRunnalable.abortAnimation(); } this.mLastMotionY = motionEvent.getY(); //最初の指の指識別子を取得します this.mActivePointerId = motionEvent.getPointerId(0); this.mMaxScale = (this.mScreenHeight / this.mHeaderHeight); this.mLastScale = (this.mHeaderContainer.getBottom() / this.mHeaderHeight); Log.d(TAG, "onTouchEvent ACTION_DOWN mLastMotionY = " + mLastMotionY); Log.d(TAG, "onTouchEvent ACTION_DOWN mActivePointerId = " + mActivePointerId); Log.d(TAG, "onTouchEvent ACTION_DOWN mMaxScale = " + mMaxScale); Log.d(TAG, "onTouchEvent ACTION_DOWN mLastScale = " + mLastScale); break; case MotionEvent.ACTION_MOVE: Log.d(TAG, "onTouchEvent ACTION_MOVE mActivePointerId" + mActivePointerId); //現在のIDのスマートフォン指針を取得 int pointer = motionEvent.findPointerIndex(this.mActivePointerId); //指針が空でないか確認 if (pointer == INVALID_VALUE) { Log.e(TAG, "Invalid pointerId=" + this.mActivePointerId + " in onTouchEvent"); } else { //もし初期値が設定されていない場合、設定する必要があります if (this.mLastMotionY == INVALID_VALUE) { this.mLastMotionY = motionEvent.getY(pointer); } if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) { //取得ヘッダースタイル ViewGroup.LayoutParams headerParams = this.mHeaderContainer.getLayoutParams(); float currentScale = ((motionEvent.getY(pointer) - this.mLastMotionY + this.mHeaderContainer.getBottom()) / this.mHeaderHeight - this.mLastScale) / 2.0F + this.mLastScale; if ((this.mLastScale <= 1.0D) && (currentScale < this.mLastScale)) { //最後の倍率がデフォルトより小さくて、現在の倍率が前回の倍率より小さい場合、ヘッダーの高さを変更します headerParams.height = this.mHeaderHeight; this.mHeaderContainer.setLayoutParams(headerParams); return super.onTouchEvent(motionEvent); } else { //そうでない場合は、現在の倍率を最後の倍率に設定します this.mLastScale = Math.min(Math.max(currentScale, 1.0F), this.mMaxScale); headerParams.height = ((int) (this.mHeaderHeight * this.mLastScale)); //変更後の高さがスクリーンの高さより小さいかどうかを判断します if (headerParams.height < this.mScreenHeight) { this.mHeaderContainer.setLayoutParams(headerParams); } //最後のy座標を記録します this.mLastMotionY = motionEvent.getY(pointer); return true; } } this.mLastMotionY = motionEvent.getY(pointer); } break; case MotionEvent.ACTION_UP: Log.d(TAG, "onTouchEvent ACTION_UP リセット"); //リセット reset(); //指が離れたとき、伸びの計算を行い、アニメーションの開始を判断します endScraling(); break; case MotionEvent.ACTION_CANCEL: int actionIndex = motionEvent.getActionIndex();//現在の最上位の指を取得します this.mLastMotionY = motionEvent.getY(actionIndex);//最後のy座標を取得します this.mActivePointerId = motionEvent.getPointerId(actionIndex);//最上位の指の指先を取得します Log.d(TAG, "onTouchEvent ACTION_CANCEL actionIndex = ") + actionIndex + " mLastMotionY = " + mLastMotionY + " mActivePointerId = " + mActivePointerId); break; case MotionEvent.ACTION_POINTER_DOWN: //第二の指が押下またはリリースされた場合にこのイベントをトリガーする onSecondaryPointerUp(motionEvent); this.mLastMotionY = motionEvent.getY(motionEvent.findPointerIndex(this.mActivePointerId)); Log.d(TAG, "onTouchEvent_Po ACTION_POINTER_DOWN mLastMotionY = " + mLastMotionY); break; case MotionEvent.ACTION_POINTER_UP: //第二の指が押下またはリリースされた場合 Log.d(TAG, "onTouchEvent_Po ACTION_POINTER_UP "); break; } return super.onTouchEvent(motionEvent); }
上に戻る際のアニメーション
/** * 上に戻るアニメーション */ class ScalingRunnalable implements Runnable { long mDuration;//持続時間 boolean mIsFinished = true;//終了 float mScale;//比率 long mStartTime;//開始時間 ScalingRunnalable() { } /** * アニメーション中止 */ public void abortAnimation() { this.mIsFinished = true; } /** * 中止 * * @return */ public boolean isFinished() { return this.mIsFinished; } public void run() { Log.d(TAG, "ScalingRunnalable mIsFinished = " + this.mIsFinished + " this.mScale = " + this.mScale); float currentScale; ViewGroup.LayoutParams mHeaderContainerParams;//ヘッダースタイル //中止判断およびスライドがオーバーサイズしたデフォルトサイズの確認 if ((!this.mIsFinished) && (this.mScale > 1.0D)) { float currentTime = ((float) SystemClock.currentThreadTimeMillis() - (float) this.mStartTime) / (float) this.mDuration; currentScale = this.mScale - (this.mScale - 1.0F) * PullToZoomListView.sInterpolator.getInterpolation(currentTime); Log.d(TAG, "スケーリングランナブル currentTime = " + currentTime + " currentScale = " + currentScale); mHeaderContainerParams = PullToZoomListView.this.mHeaderContainer.getLayoutParams(); if (currentScale > 1.0F) { Log.d(TAG, "スケーリングランナブル currentScale > 1.0 -- ヘッダー高さを変更); mHeaderContainerParams.height = PullToZoomListView.this.mHeaderHeight; mHeaderContainerParams.height = ((int) (currentScale * PullToZoomListView.this.mHeaderHeight)); PullToZoomListView.this.mHeaderContainer.setLayoutParams(mHeaderContainerParams); PullToZoomListView.this.post(this);//ループで実行 } else { Log.d(TAG, "スケーリングランナブル currentScale < 1.0 -- 中止); this.mIsFinished = true; } } } public void startAnimation(long paramLong) { Log.d(TAG, "スケーリングランナブルがアニメーションを開始"); this.mStartTime = SystemClock.currentThreadTimeMillis(); this.mDuration = paramLong; this.mScale = ((float) (PullToZoomListView.this.mHeaderContainer.getBottom()) / PullToZoomListView.this.mHeaderHeight); this.mIsFinished = false; Log.d(TAG, "ScalingRunnalable this.mStartTime = "); + this.mStartTime); Log.d(TAG, "ScalingRunnalable this.mDuration = "); + this.mDuration); Log.d(TAG, "ScalingRunnalable this.mScale = "); + this.mScale); Log.d(TAG, "ScalingRunnalable this.mIsFinished = "); + this.mIsFinished); PullToZoomListView.this.post(this); } }
これで本文のすべての内容が終わります。皆様の学習に役立つことを願っています。また、ナイアラトレーニングのサポートを多くいただければ幸いです。
声明:本文の内容はインターネットから取得しており、著作権者は所有者であり、インターネットユーザーが自発的に貢献し、自己でアップロードしたものであり、本サイトは所有権を持ちません。また、人工的な編集は行われておらず、関連する法的責任も負いません。著作権侵害を疑う内容がある場合は、以下のメールアドレスまでご連絡ください:notice#oldtoolbag.com(メールを送信する際には、#を@に変更してください。侵害を報告する場合は、関連する証拠を提供し、確認がとれた場合、本サイトは即座に侵害を疑う内容を削除します。)