概要
タイトルだけだと何のこっちゃという話ですが、例えばTwitterとかでフォローするボタンがあるじゃないですか。で、ViewPager管理下の各Fragmentにフォローするボタンを置いてどこかでフォローするを押したら、押したページ以外にも押された結果を反映させたいという話です。ViewPagerを使っていなければデータを引き回すなりしてonCreateViewあたりでデータに合わせてViewを編集すればいいのですが、ViewPagerを使ってるとスワイプする時に今見ているページと次に表示するページの両方を作るので、1ページ目でフォローする→スワイプで2ページ目に行く、というアクションをすると2ページ目はすでに1ページ目の表示時に作成済なのでonCreateViewを通らずに未フォローの状態のままになってしまいます。
作ってみた
んで、Observerパターンを使うとすっきり作ることができました。フォロアーリストのModelを作ってそいつのObserverとして各フラグメントを登録することでデータが変更されたらObserverとして観測中のFragmentは変更の通知をキャッチしてViewを変更するようにします。
ActivityとPagerAdaptor
デフォルトで作成されるPager付きのActivityからいらないものを削ってFragmentを差し替えただけです。
PagerSampleActivity.java
package me.rei_m.androidsample.activitiy; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.content.Context; import android.content.Intent; import android.support.v13.app.FragmentPagerAdapter; import android.os.Bundle; import android.support.v4.view.ViewPager; import me.rei_m.androidsample.R; import me.rei_m.androidsample.fragment.PagerItemFragment; public class PagerSampleActivity extends Activity { public static Intent createIntent(Context context) { return new Intent(context, PagerSampleActivity.class); } SectionsPagerAdapter mSectionsPagerAdapter; ViewPager mViewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_pager_sample); mSectionsPagerAdapter = new SectionsPagerAdapter(getFragmentManager()); mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mSectionsPagerAdapter); } public class SectionsPagerAdapter extends FragmentPagerAdapter { public SectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return PagerItemFragment.newInstance(position); } @Override public int getCount() { return 4; } @Override public CharSequence getPageTitle(int position) { return String.valueOf(position) + "枚目"; } } }
Fragment
フラグメントはこんな見た目でページ番号が変わる以外は全部同じです。
PagerItemFragment.java
package me.rei_m.androidsample.fragment; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import java.util.Observable; import java.util.Observer; import me.rei_m.androidsample.R; import me.rei_m.androidsample.entity.FollowerEntity; import me.rei_m.androidsample.model.FollowerListModel; import me.rei_m.androidsample.model.ModelLocator; public class PagerItemFragment extends Fragment implements Observer, View.OnClickListener { // Modelからの通知を受け取る必要があるのでObserverを実装する private static final String ARG_PAGE_NO = "pageNo"; public static PagerItemFragment newInstance(int pageNo) { Bundle args = new Bundle(); args.putInt(ARG_PAGE_NO, pageNo); PagerItemFragment fragment = new PagerItemFragment(); fragment.setArguments(args); return fragment; } private FollowerEntity mUser; private int mPageNo; private TextView mTextView; private Button mButton; private FollowerListModel mFollowerListModel; public PagerItemFragment() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ページ番号を取得 mPageNo = getArguments().getInt(ARG_PAGE_NO); // ModelのObserverにインスタンスを登録 mFollowerListModel = ModelLocator.getInstance().getFollowerListModel(); mFollowerListModel.addObserver(this); // 仮のユーザを設定 mUser = new FollowerEntity(); mUser.setId("0000001"); mUser.setName("ほげー"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_pager_item, container, false); // TextViewとButtonを取得 mTextView = (TextView) view.findViewById(R.id.text_pager_item_title); mTextView.setText(String.valueOf(mPageNo)); mButton = (Button) view.findViewById(R.id.button_pager_item); mButton.setOnClickListener(this); // 初期表示の設定。対象のユーザーをフォロー済かどうかで表示を変える if(mFollowerListModel.hasFollower(mUser)){ setFollowedStyle(); }else{ setUnFollowedStyle(); } return view; } @Override public void onDestroy() { super.onDestroy(); // ModelのObserverからインスタンスを解除 mFollowerListModel.deleteObserver(this); } @Override public void onDetach() { super.onDetach(); mTextView = null; mButton = null; mFollowerListModel = null; mUser = null; } @Override public void update(Observable observable, Object data) { // Modelからフォロアーリストの更新通知が来たら走る処理 if(data instanceof FollowerListModel.ChangeFollowerListEvent){ FollowerListModel.ChangeFollowerListEvent event = (FollowerListModel.ChangeFollowerListEvent) data; // フォローアクションの状態によって表示を変える if(event.getIsAdded()){ setFollowedStyle(); }else{ setUnFollowedStyle(); } } } @Override public void onClick(View v) { switch (v.getId()){ case R.id.button_pager_item: // フォロアーリストを確認して、追加済であれば削除、未追加であれば追加 // ボタンのイベントではViewの表示は変えない if(mFollowerListModel.hasFollower(mUser)){ mFollowerListModel.removeFollower(mUser); }else{ mFollowerListModel.addFollower(mUser); } break; } } // フォロー済の状態に表示を変更する private void setFollowedStyle(){ mButton.setText(mUser.getName() + "をふぉろーしてるよ"); mTextView.setBackgroundColor(getResources().getColor(R.color.active)); } // 未フォローの状態の表示を変更する private void setUnFollowedStyle(){ mButton.setText(mUser.getName() + "はまだふぉろーしてないよ"); mTextView.setBackground(null); } }
ModelとEntity
Obserbleを実装したModelを作ってデータに変更があったら更新の通知を送るように実装します。Entitiyは適当。
FollowerListModel.java
package me.rei_m.androidsample.model; import java.util.EventObject; import java.util.HashMap; import java.util.Observable; import me.rei_m.androidsample.entity.FollowerEntity; public class FollowerListModel extends Observable{ public static FollowerListModel createInstance(){ FollowerListModel instance = new FollowerListModel(); instance.mFollowerList = new HashMap<>(); return instance; } private FollowerListModel(){} private HashMap<String, FollowerEntity> mFollowerList; public HashMap<String, FollowerEntity> getFollowerList() { return mFollowerList; } // フォロー済か確認する public boolean hasFollower(FollowerEntity target){ return mFollowerList.containsKey(target.getId()); } // フォロアーリストに追加する public void addFollower(FollowerEntity target){ mFollowerList.put(target.getId(), target); notifyEvent(true); } // フォロアーリストから削除する public void removeFollower(FollowerEntity target){ mFollowerList.remove(target.getId()); notifyEvent(false); } // フォロアーリストの更新通知をObserverに対して送る private void notifyEvent(boolean isAdded){ ChangeFollowerListEvent event = new ChangeFollowerListEvent(this); event.setIsAdded(isAdded); setChanged(); notifyObservers(event); } // 通知用のEventObject public static class ChangeFollowerListEvent extends EventObject { public ChangeFollowerListEvent(Object source){ super(source); } private boolean isAdded; public boolean getIsAdded() { return isAdded; } public void setIsAdded(boolean isAdded) { this.isAdded = isAdded; } } }
FollowerEntity.java (適当。IDと名前だけ持ってる。)
package me.rei_m.androidsample.entity; import java.io.Serializable; public class FollowerEntity implements Serializable { private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
こんな感じでしょうか。これで1ページ目でフォローする→スワイプで2ページ目に行くとやっても2ページ目はちゃんとフォロー済の表示になりました。変なとこがあればご指摘ください〜
コードはこちら