Fragmentと単一のMainActivity
を使用して、同じViewPagerで異なるフラグメントを表示するアプリを作成して、典型的なMVCアプリケーションの動作を再現しています。
問題は、フラグメントをプログラムで更新して、新しいフラグメントの変更でViewPager
を更新する方法を理解していないことです。
たとえば、チャートを表示するこのFragment
があります(意図的に)メインからsetFragment(int interval, Point[] snodePoint)
を呼び出すと、チャートはViewPager
で更新されます
public class LineFragment extends Fragment {
static int interval;
static Point snodePoints[];
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_linegraph, container,
false);
Bundle bundle = this.getArguments();
ChartConfig cg = bundle.getParcelable("FragmentData");
snodePoints = cg.getPoints();
interval= cg.getInterval();
Line l = new Line();
for(int i=0; i<snodePoints.length; i++){
LinePoint p = new LinePoint();
Point sp=snodePoints[i];
p.setX(sp.getX());
p.setY(sp.getY());
l.addPoint(p)
}
l.setColor(getResources().getColor(R.color.green));
LineGraph li = (LineGraph) v.findViewById(R.id.linegraph);
li.addLine(l);
li.setRangeY(0, interval);
li.setLineToFill(0);
li.setOnPointClickedListener(new OnPointClickedListener() {
@Override
public void onClick(int lineIndex, int pointIndex) {
// TODO Auto-generated method stub
}
});
return v;
}
}
いくつかの言葉で私がする必要がある
どうすればこれができますか?
FragmentAdapterを使用した主なアクティビティ
public class MainActivity extends FragmentActivity {
ViewPager mViewPager;
MyFragmentAdapter mMyFragmentAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.view_pager);
final ActionBar bar = this.getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
LineFragment lineFrag = new LineFragment();
BarFragment barFrag = new BarFragment();
PieFragment pieFrag = new PieFragment();
mMyFragmentAdapter = new MyFragmentAdapter(this, mViewPager);
mMyFragmentAdapter.addTab(bar.newTab().setText("Line"), LineFragment.class,
null, lineFrag);
mMyFragmentAdapter.addTab(bar.newTab().setText("Bar"), BarFragment.class,
null, barFrag);
mMyFragmentAdapter.addTab(bar.newTab().setText("Pie"), PieFragment.class,
null, pieFrag);
mViewPager.setOffscreenPageLimit(mMyFragmentAdapter.getCount() - 1);
}
public static class MyFragmentAdapter extends FragmentStatePagerAdapter implements
ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final MainActivity mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
private final ArrayList<Fragment> mFrag = new ArrayList<Fragment>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public MyFragmentAdapter(MainActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args,
Fragment frag) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mFrag.add(frag);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
Bundle args = new Bundle();
ChartConfig cg = new ChartConfig(interval, snodePoint);
args.putParcelable("FragmentData", cg);
Fragment f = mFrag.get(position);
f.setArguments(args);
return f;
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
public void onTabSelected(Tab tab, Android.app.FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
public void onTabUnselected(Tab tab, Android.app.FragmentTransaction ft) {
}
@Override
public void onTabReselected(Tab tab, Android.app.FragmentTransaction ft) {
}
}
}
フラグメントを初めて作成したとき、メインアクティビティはオーバーライドされたgetItem(int position)
を介してフラグメントにパラメータを正常に渡しますが、データを変更しようとした場合、またはnotifyDataSetChanged()
を呼び出した場合もアダプタmMyFragmentAdapter
では何も起こらず、ViewPager
のフラグメントは作成時に渡された同じデータを引き続き使用します。
[〜#〜] edit [〜#〜]
フラグメントの更新に関する他の質問に見られる部分的なコードに続いて、私もこれを試しました
public void update() {
try{
LineFragment fragment =
(LineFragment) getSupportFragmentManager().findFragmentByTag(
"Android:switcher:"+R.id.view_pager+":0");
if(fragment != null)
{
if(fragment.getView() != null)
{
fragment.updateDisplay();
}
}
}
catch(RuntimeException e){
e.printStackTrace();
}
}
0が最初のFragment-TabフラグメントのIDであると仮定しますが(この種の操作についてはわかりません)、fragment.updateDisplay();
は呼び出されません。
アダプタでgetItemPositionをオーバーライドします
@Override
public int getItemPosition(Object object) {
// POSITION_NONE makes it possible to reload the PagerAdapter
return POSITION_NONE;
}
その後
viewPager.getAdapter().notifyDataSetChanged()
動作するはずです。
フラグメントがメインから渡されるデータを取得する方法を理解する必要があります。おそらく何かが欠けているかもしれませんが、実際にこれを行う方法を理解していません。
これから、Fragment
の作成時にデータを渡したいようです。これが必要な場合は、カスタムコンストラクターを作成しないでください(通常、Fragment
に対しては、デフォルトの引数なしのコンストラクターのみを使用する必要があります(特定の時点でプラットフォームがFragment
回))。
代わりに、データを Bundle
で渡す必要があります。
@Override
public Fragment getItem(int position) {
switch (position) {
//...
Bundle args = new Bundle();
args.put("a_string_representing_theKey", data)
LineFragment f = new LineFragment();
f.setArguments(args);
return f;
//...
}
}
これは、データをBundle
に入れることができる場合にのみ機能します(Bundle
クラスのput...
メソッド、すべてのプリミティブ+ Parcelable
であるオブジェクトを参照)。フラグメントでは、getArguments()
を使用して引数を取得できます。
Fragment
からActivity
から直接データを取得することもできます。
// in the lifecycle method where you want the data
((MainActivity)getActivity()).getDataForFragment(); // use the data
たとえば、メインからsetFragment(int interval、Point [] snodePoint)を呼び出すと、グラフを表示するこのフラグメントがあります(グラフはViewPagerで更新する必要があります)。
あなたは自分自身に矛盾するようです。これには、私がリンクした質問のコードを使用します。もちろん、現在のsetFragment()
メソッドを呼び出しても、2つの変数の値を更新するだけなので、UIに変更を通知する必要があります。 (別のメソッドを呼び出してビュー階層を再作成する、チャートビューで新しい値を設定する、invalidate()
などを呼び出すなど)。
編集:
リンクした質問で使用したコードは動作するはずですが、適切なコードを使用していません。 FragmentStatePagerAdapter
がありますが、使用できないFragmentPagerAdapter
のコードを使用しています:
FragmentStatePagerAdapter a = (FragmentStatePagerAdapter) mViewPager.getAdapter();
LineFragment f = (LineFragment) a.instantiateItem(pager, thePositionYouWant);
上記のコードは、目に見えるフラグメントと各側に1つずつのフラグメントに対してのみ機能し、他のフラグメントは使用できないことに注意してください(そして、ユーザーはそれらを表示しないか、すぐに移動できないため、更新される)。
#How to update-refresh Fragment in ViewPager by Main Activity programmatically
#after long struggle I find proper solution
tablayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
refreshTab(tab.getPosition());// create a method
viewpager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
private void refreshTab(int position) {
switch (position) {
case 0:
break;
case 1:
CompaniesInterest comP1 = (CompaniesInterest) viewpager.getAdapter().instantiateItem(viewpager, viewpager.getCurrentItem());
comP1.refreshpage();
break;
case 2:
TotalSelectedCompanies toTal = (TotalSelectedCompanies) viewpager.getAdapter().instantiateItem(viewpager, viewpager.getCurrentItem());
toTal.refreshpage();
}
}
// Create a interface for refresh data for fragmen
public interface Refreshpage {
void refreshpage();
}
// implements Refreshpage interface in both fragment TotalSelectedCompanies and CompaniesInterest
//
@Override`enter code here`
public void refreshpage() {
// do what you want to refresh
}
フラグメント内のメソッドをオーバーライドするのは非常に簡単です
@オーバーライド
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
actionView();
}
else{
//no
}
}