2013年10月27日日曜日

ViewPagerを使ってみる(動的に更新・追加・削除)

前回のViewPagerを使ってみるの続きでViewPagerについてになります。

前回は初期化されたアダプターのデータを表示させただけでした、
今度は動的にViewPagerのビューの中身を変更したり、
ビューの更新、追加を行いたいと思います。(`・ω・´)シャキーン
(削除は微妙になってしまいました・・・orz)

■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.viewpager2"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="8" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.viewpager2.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
■res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">ViewPager</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    <string name="prev">前へ</string>
    <string name="next">次へ</string>
    <string name="first">最初へ</string>
    <string name="last">最後へ</string>
    <string name="change">変更</string>
    <string name="add">追加</string>
    <string name="delete">削除</string>
</resources>

■activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center" >
        
        <Button
            android:id="@+id/btn_change"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:tag="@string/change"
            android:text="@string/change"/>
        
        <Button
            android:id="@+id/btn_add"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:tag="@string/add"
            android:text="@string/add"/>

        <Button
            android:id="@+id/btn_delete"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:tag="@string/delete"
            android:text="@string/delete"/>

    </LinearLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center" >

        <Button
            android:id="@+id/btn_start"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:tag="@string/first"
            android:text="@string/first"/>

        <Button
            android:id="@+id/btn_prev"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:tag="@string/prev"
            android:text="@string/prev"/>

        <Button
            android:id="@+id/btn_next"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:tag="@string/next"
            android:text="@string/next"/>

        <Button
            android:id="@+id/btn_last"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:tag="@string/last"
            android:text="@string/last"/>
    </LinearLayout>

</LinearLayout>

■MainActivity.java
注意点としては、アダプターを追加・削除した後には、
notifyDataSetChangedを実行してアダプターを更新してあげないといけないみたいです。
※ViewPagerのビューの内容の変更時には実行する必要がない。

これを実行せずにViewPagerをスワイプなどして動かすと次のエラーが発生してしまうようでした(´;ω;`)ブワッ
java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 7, found: 8 Pager id: com.example.viewpager2:id/viewpager Pager class: class android.support.v4.view.ViewPager Problematic adapter: class com.example.viewpager2.CustomPagerAdapter
package com.example.viewpager2;

import java.util.ArrayList;

import android.app.Activity;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.SimpleOnPageChangeListener;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {

 private ArrayList<Button> mButtonList = new ArrayList<Button>();
 private ViewPager mViewPager = null;
 private CustomPagerAdapter mPagerAdapter;
 private int mCurrentPageIndex = 0;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // 各ボタンを保持する
  mButtonList.add((Button) findViewById(R.id.btn_start));
  mButtonList.add((Button) findViewById(R.id.btn_prev));
  mButtonList.add((Button) findViewById(R.id.btn_next));
  mButtonList.add((Button) findViewById(R.id.btn_last));
  mButtonList.add((Button) findViewById(R.id.btn_change));
  mButtonList.add((Button) findViewById(R.id.btn_add));
  mButtonList.add((Button) findViewById(R.id.btn_delete));
  // ボタンにクリックイベントを設定する
  for (Button btn : mButtonList) {
   btn.setOnClickListener(this);
  }
  // ViewPagerを取得する
  mViewPager = (ViewPager) findViewById(R.id.viewpager);
  // アダプターを設定する
  mPagerAdapter = new CustomPagerAdapter(this);
  // アダプター経由でViewPagerに追加する
  mPagerAdapter.add(Color.BLACK);
  mPagerAdapter.add(Color.RED);
  mPagerAdapter.add(Color.GREEN);
  mPagerAdapter.add(Color.BLUE);
  mPagerAdapter.add(Color.CYAN);
  mPagerAdapter.add(Color.MAGENTA);
  mPagerAdapter.add(Color.YELLOW);

  // リスナーの設定
  mViewPager.setOnPageChangeListener(new PageChangeListener());
  // アダプターを設定する
  mViewPager.setAdapter(mPagerAdapter);
 }

 /**
  * ViewPagerのリスナー用のクラス
  */
 class PageChangeListener extends SimpleOnPageChangeListener {

  /**
   * 移動中に発生する。
   * 
   * @see android.support.v4.view.ViewPager.SimpleOnPageChangeListener#onPageScrolled(int,
   *      float, int)
   */
  @Override
  public void onPageScrolled(int position, float positionOffset,
    int positionOffsetPixels) {
   Log.d("PageChangeListener.onPageScrolled",
     String.valueOf(position) + ":"
       + String.valueOf(positionOffset) + ":"
       + String.valueOf(positionOffsetPixels));
  }

  /**
   * 現在表示しているViewの番号
   * 
   * @see android.support.v4.view.ViewPager.SimpleOnPageChangeListener#onPageSelected(int)
   */
  @Override
  public void onPageSelected(int position) {
   // Page change Operation!
   Log.d("PageChangeListener.onPageSelected", String.valueOf(position));
   mCurrentPageIndex = position;

  }

  /**
   * ViewPagerの状態の検知
   * 
   * @see android.support.v4.view.ViewPager.SimpleOnPageChangeListener#onPageScrollStateChanged(int)
   */
  @Override
  public void onPageScrollStateChanged(int state) {
   Log.d("PageChangeListener.onPageScrollStateChanged",
     String.valueOf(state));
   if (state == ViewPager.SCROLL_STATE_SETTLING) {
    int page = mViewPager.getCurrentItem();
    /*
     * textView.setText(String.valueOf(page));
     */
   }
  }
 }

 /*
  * ボタンクリック時の動作
  */
 public void onClick(View v) {

  Log.d("ボタン", (String) v.getTag());
  //
  Resources res = getResources();
  //
  if (v.getTag().equals((String) res.getString(R.string.first))) {
   mViewPager.setCurrentItem(0);
  } else if (v.getTag().equals((String) res.getString(R.string.last))) {
   mViewPager.setCurrentItem(mPagerAdapter.getCount() - 1);
  } else if (v.getTag().equals((String) res.getString(R.string.prev))) {
   mViewPager.arrowScroll(View.FOCUS_LEFT);
   // mViewPager.setCurrentItem(mViewPager.getCurrentItem() - 1);
  } else if (v.getTag().equals((String) res.getString(R.string.next))) {
   mViewPager.arrowScroll(View.FOCUS_RIGHT);
   // mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1);
  } else if (v.getTag().equals((String) res.getString(R.string.change))) {
   onPagerChange();
  } else if (v.getTag().equals((String) res.getString(R.string.add))) {
   onPagerAdd();
  } else if (v.getTag().equals((String) res.getString(R.string.delete))) {
   onPagerDelete();
  }
 }

 /**
     * 更新する
     */
 public void onPagerChange() {
  Log.d("onPagerChange", "");
  mPagerAdapter.changeColor(getColor());
 }

 /**
     * 追加する
     */
 public void onPagerAdd() {
  Log.d("onPagerAdd", "");
  // ランダムに色を設定する
  mPagerAdapter.add(getColor());
  // アダプターの更新を通知する
  mPagerAdapter.notifyDataSetChanged();
 }

 /**
     * 削除する
     */
 public void onPagerDelete() {
  Log.d("onPagerDelete", "");
  mPagerAdapter.remove(mCurrentPageIndex);
  //
  mPagerAdapter.notifyDataSetChanged();
 }

 /**
     * カラーコードを生成する
     */
 public static int getColor() {
  // ランダムに色を追加する
  int R = (int) (Math.random() * 256);
  int G = (int) (Math.random() * 256);
  int B = (int) (Math.random() * 256);
  return Color.rgb(R, G, B);
 }
}
■CustomPagerAdapter.java
package com.example.viewpager2;

import java.util.ArrayList;

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class CustomPagerAdapter extends PagerAdapter {

 /** コンテキスト. */
 private Context mContext;

 /** リスト. */
 private ArrayList<Integer> mList;

 public TextView primaryLayout;

 /**
  * コンストラクタ.
  */
 public CustomPagerAdapter(Context context) {
  mContext = context;
  mList = new ArrayList<Integer>();
 }

 /**
  * リストにアイテムを追加する.
  * 
  * @param item
  *            アイテム
  */
 public void add(Integer item) {
  Log.d("CustomPagerAdapter", "add");
  mList.add(item);

 }

 /**
  * アイテムを追加するときに呼ばれる。このメソッド内で View をコンテナに追加する。
  * 
  * @see android.support.v4.view.PagerAdapter#instantiateItem(android.view.ViewGroup,
  *      int)
  */
 @Override
 public Object instantiateItem(ViewGroup container, int position) {
  Log.d("CustomPagerAdapter", "instantiateItem");
  // リストから取得
  Integer item = mList.get(position);

  // View を生成
  TextView textView = new TextView(mContext);
  textView.setText("Page:" + position);
  textView.setTextSize(30);
  textView.setTextColor(item);
  textView.setGravity(Gravity.CENTER);

  // コンテナに追加
  container.addView(textView);
  return textView;
 }

 /**
  * アイテムを削除するときに呼ばれる。このメソッド内で View の削除をおこなう。 postion番目のViweを削除するために利用
  * 
  * @param container
  *            : 削除するViewのコンテナ
  * @param position
  *            : インスタンス削除位置
  * @param object
  *            : instantiateItemメソッドで返却したオブジェクト
  * @see android.support.v4.view.PagerAdapter#destroyItem(android.view.ViewGroup,
  *      int, java.lang.Object)
  */
 @Override
 public void destroyItem(ViewGroup container, int position, Object object) {
  // コンテナから View を削除
  container.removeView((View) object);
 }

 /**
  * ViewPager に登録する全アイテム数を返す。
  * 
  * @see android.support.v4.view.PagerAdapter#getCount()
  */
 @Override
 public int getCount() {
  // リストのアイテム数を返す
  return mList.size();
 }

 /**
  * Object に View が含まれているか判定する。 第2引数のobjectに第1引数のviewが含まれているか、判定する。
  * 正しく比較をしないと挙動がおかしくなった・・・orz スワイプ中のページ送りのフォーカスや表示調整に使っている?
  * 
  * @see android.support.v4.view.PagerAdapter#isViewFromObject(android.view.View,
  *      java.lang.Object)
  */
 @Override
 public boolean isViewFromObject(View view, Object object) {
  // Object 内に View が存在するか判定する
  // コンテナに入っているViewを取り出して個別に比較する処理
  return view == (TextView) object;
  // return view.equals(object);
 }

 /**
  * 現在表示してるViewを取得する
  * 
  * @see android.support.v4.view.PagerAdapter#setPrimaryItem(android.view.ViewGroup,
  *      int, java.lang.Object)
  */
 @Override
 public void setPrimaryItem(ViewGroup container, int position, Object object) {
  primaryLayout = (TextView) object;
  super.setPrimaryItem(container, position, object);
 }
 /**
  * この記述をしておくとViewPagerのビューを更新してくれる?
  * これを書いておくとアダプターで要素をremoveした後に更新を正しくしてくれるようになった。(追加には関係ない)
  * 
  * @see android.support.v4.view.PagerAdapter#getItemPosition(java.lang.Object)
  */
 @Override
 public int getItemPosition(Object object) {
  return POSITION_NONE;
 }
 /**
  * 表示されているViewを取得する
  * 
  * @return 表示されているView
  */
 public TextView getPrimaryView() {
  return primaryLayout;
 }

 /**
  * 色を変更する
  */
 public void changeColor(int item) {

  TextView viewText = getPrimaryView();
  viewText.setTextColor(item);

 }

 /**
     * 
     */
 public void remove(int position) {
  if (position < 0 || position >= mList.size()) {
   return;
  }
  Log.d("remove", String.valueOf(position));
  mList.remove(position);
 }

}
削除の挙動が変な感じ・・・(; ・`д・´)
表示されているViewを消してるけど、そのタイミングでは消えていなくて、
ViewPagerを動かすと反映される感じ(´;ω;`)ウッ…

ただし消し方ってどうやるんだろう?

追記。こちらのViewPagerでViewを強制的に更新する方法のように
getItemPositionをオーバーライドして、POSITION_NONEを返したら、
消した直後に更新されるようになった(゚д゚)!



以上です(`・ω・´)ゞビシッ!!

参考URL

0 件のコメント:

コメントを投稿