Pages

2013年4月8日月曜日

ViewPagerで画面数に合わせた背景画像の移動を実現する(前編)

Androidアプリで、ホーム画面のように左右のフリックで画面が切り替わり、その画面移動に追随して背景を移動させたい。

たったコレだけの事にアホみたいに時間を費やしてしまいました。

背景をページ数で割ってそれぞれのページの背景画像として設定したらいいじゃん。って簡単な話ではなかったんですよ、コレが。

今回、困ったのが次の仕様。
・画面数が動的に増減する。
・背景に使う画像のサイズは特に決まっていない。デザインによってサイズが違う。

この条件で、最初のページから最後のページまでの移動で、ぴったり画像の端から端まで移動させたい。

イメージはこんな感じ。

画面切り替えはViewPagerを使います。
んで、背景画像はアスペクト比をそのままに画面の高さに合わせることにします。

ViewPagerの詳細な使い方はググってください。
とりあえず、背景に画像を設定し、その上に簡単なViewPagerを重ねてみます。
ただし、背景を見えるようにしたいので、ViewPagerの背景は透明としています

public class CustomAdapter extends PagerAdapter {
    private Context mContext;
    private ArrayList mList;
 
    public CustomAdapter(Context context) {
        mContext = context;
        mList = new ArrayList();
    }
 
    public void add(Integer item) {
        mList.add(item);
    }
 
    @Override
    public Object instantiateItem(View container, int position) {
        // リストから取得
        Integer item = mList.get(position);
 
        // View を生成
        TextView textView = new TextView(mContext);
        textView.setText(position + "ページ");
        textView.setTextSize(50);
        textView.setTextColor(item);
        textView.setGravity(Gravity.CENTER);
        
        // コンテナに追加
        ((ViewGroup) container).addView(textView);

        // 背景を透明にする(第一引数が0ならOK)
        container.setBackgroundColor(Color.argb(0, 0, 0, 0));
        
        return textView;
    }
 
    @Override
    public void destroyItem(View container, int position, Object object) {
        ((ViewGroup) container).removeView((View) object);
    }
 
    @Override
    public int getCount() {
        // リストのアイテム数を返す
        return mList.size();
    }
 
    @Override
    public boolean isViewFromObject(View view, Object object) {
        // Object 内に View が存在するか判定する
        return view == (TextView) object;
    }
}


public class MainActivity extends Activity {

 private ImageView imageView;
 private Bitmap img;
 
 private float displayW;
 private float displayH;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // カスタム PagerAdapter を生成
        CustomAdapter 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);
        
        // アスペクト比をそのままに、どの端末でも同じように表示させる(縦に合わせる)
        int bmpNativeHeight = options.outHeight;
        float dpiRatio = bmpNativeHeight / displayH;
        float calcDpi = metrics.densityDpi * dpiRatio;
        if (img == null || img.isRecycled()) {
            options.inJustDecodeBounds = false;
            options.inDensity = (int) calcDpi;
            img = BitmapFactory.decodeResource(getResources(), R.drawable.wall, options);
        }
        imageView = new ImageView(this);
        imageView.setImageBitmap(img);
        imageView.setScaleType(ScaleType.MATRIX);
        addContentView(imageView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        
        // ViewPager を生成
        ViewPager viewPager = new ViewPager(this);
        viewPager.setAdapter(adapter);
        addContentView(viewPager, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    }

ここでのポイントは、
・ViewPagerの背景を透明にする
・背景画像のImageViewのScaleTypeをMATRIXに指定する
となります。

背景は動きませんが、とりあえず動かしたい背景画像の上にViewPagerを乗せてみました。
ちなみにAndroidアプリをほどんど開発した事が無い私は、この「背景をどの端末でも同じに見えるようにdpiを合わせる」というのにも悩みまくりました。
これをしないと端末によって背景が拡大表示されたりするので注意してください。

次はViewPagerでページを切り替える度に背景が移動していく箇所を実装していきます。


0 件のコメント:

コメントを投稿