前回の続きで、ViewPagerでページを切り替える度に背景が移動していく箇所を実装します。
ここでの大雑把な仕様は、
・最初のページは全ページの真ん中のページ(例えば全5ページなら3ページが初期位置)
・背景画像は必ず横長の画像
・背景は横にしか移動しない
ということにします。
ちなみに私はAndroidに関しては素人なので、この実装よりもいいやり方があれば是非是非教えて頂きたい。
というか、こんな実装を必要とする人っているのか??
それでは、とりあえず実装後のMainActivityはこんな感じとなります。
public class MainActivity extends Activity {
private CustomAdapter adapter;
private ViewPager mViewPager;
private ImageView mImageView;
private Bitmap mBitmap;
private float displayW;
private float displayH;
// -----追記
private Matrix matrix;
private float currentBmpX;
private int maxMoveBmpX;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// カスタム PagerAdapter を生成
adapter = new CustomAdapter(this);
adapter.add(Color.RED);
adapter.add(Color.GREEN);
adapter.add(Color.BLUE);
adapter.add(Color.BLACK);
adapter.add(Color.WHITE);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
displayW = metrics.widthPixels;
displayH = metrics.heightPixels;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 画像そのものは読み込まない
BitmapFactory.decodeResource(getResources(), R.drawable.wall, options);
// dpi計算
int bmpNativeHeight = options.outHeight;
float dpiRatio = bmpNativeHeight / displayH;
float calcDpi = metrics.densityDpi * dpiRatio;
if (mBitmap == null || mBitmap.isRecycled()) {
options.inJustDecodeBounds = false;
options.inDensity = (int) calcDpi;
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.wall, options);
}
mImageView = new ImageView(this);
mImageView.setImageBitmap(mBitmap);
mImageView.setScaleType(ScaleType.MATRIX);
addContentView(mImageView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
// ViewPager を生成
mViewPager = new ViewPager(this);
mViewPager.setAdapter(adapter);
// -----追記
matrix = new Matrix();
currentBmpX = (mBitmap.getScaledWidth(metrics) / 2) - (displayW / 2);
maxMoveBmpX = (int) (mBitmap.getScaledWidth(metrics) - displayW);
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
private int currentPage;
@Override
public void onPageSelected(int pageNumber) {
currentPage = pageNumber;
currentBmpX = getAbsPositionX(pageNumber);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (positionOffsetPixels == 0) {
return;
}
//page移動中の処理
float scaledOffsetPixels = positionOffsetPixels * getScaleValue();
// ページ毎の始点のx座標
float absolutePosition = getAbsPositionX(position);
currentBmpX = absolutePosition + scaledOffsetPixels;
mImageView.setImageMatrix(getMatrix(matrix, -currentBmpX));
mImageView.invalidate();
}
@Override
public void onPageScrollStateChanged(int state) {
}
protected float getAbsPositionX(int page) {
return (maxMoveBmpX / (adapter.getCount() - 1)) * page;
}
});
addContentView(mViewPager, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}
@Override
protected void onResume() {
super.onResume();
mViewPager.setCurrentItem((adapter.getCount()/2), true);
mImageView.setImageMatrix(getMatrix(matrix, -currentBmpX));
}
protected Matrix getMatrix(Matrix matrix, float xPosition) {
if (xPosition > 0) {
xPosition = 0;
}
if (Math.abs(xPosition) > maxMoveBmpX) {
xPosition = -maxMoveBmpX;
}
matrix.setTranslate(xPosition, 0);
return matrix;
}
public float getScaleValue() {
float displayWidth = getWindowManager().getDefaultDisplay().getWidth();
float fullScreenSize = displayWidth * (adapter.getCount()-1);
return maxMoveBmpX / fullScreenSize;
}
}
前回と比較して、onCreate()で今回追加実装した箇所には「// -----追記」とコメントしています。
上の行番号で言うと、
11〜14行目
59〜96行目
その他のメソッドは今回追加実装してます。
まぁ、これだけで読む気も失せてくるんですが、説明を(今後の自分の為にも)。
まず、61行目と62行目の
currentBmpX = (mBitmap.getScaledWidth(metrics) / 2) - (displayW / 2);
maxMoveBmpX = (int) (mBitmap.getScaledWidth(metrics) - displayW);
ですが、
currentBmpXは、画像の左上を原点としたときの、現在画面に表示されている背景画像の左上のX座標です。
これの初期位置(つまり、中央のページで表示される背景画像の左上のX座標)を計算しています。
分かりにくいけど、計算で出しているのは上の画像の赤い点の位置ですね。
次に、maxMoveBmpXですが、これは最後のページで表示される背景画像のX座標の位置となります。
まぁ、このへんは特にポイントでも何でもないです。
今回のポイントとなる実装はViewPagerの
setOnPageChangeListenerですね。
上記コードの63行目〜96行目の部分です。
このListnerはページが動いているときにその状態を通知しまくってくれるので、その情報を使って背景画像の位置を
ImageView.setImageMatrixでズラしていくって感じですね。
OnPageChangeListenerでのポイントといえばポイントなんですが、
ページが進むと背景画像がマイナス方向(左方向)に移動する点。
何か、感覚的に理解しにくいのは私だけ??
それ以外は特にポイントってものは無いですね。実装も大したことしてないし。
あとポイントじゃないけど74行目〜76行目のif文。
別にこれなくても普通に動くんですけど、ページ移動中にそのときの移動距離が引数で渡ってくるんですが(positionOffsetPixels)、ページ移動が完了してからも何故かしばらく0が渡ってくるので、余計な処理を省く為に入れてます。
まぁ、なんとなくです。いらない気がしますね。。。。
長々と書きましたが、これでそれなりの動きになるはずです。
備忘録ついでに誰かのお役に立てれば幸いかと。
あ、変数名やメソッド名はあまり突っ込まないでね。