Je construis une application qui utilise Fragment et un seul MainActivity
qui montre différents fragments dans le même ViewPager pour reproduire le comportement d'une application MVC typique.
Le problème est que je n'ai pas compris comment mettre à jour le fragment par programme pour mettre à jour le ViewPager
avec les nouvelles modifications du fragment
Par exemple, j'ai ce Fragment
qui montre un graphique, (dans mon intention) lorsque j'appelle setFragment(int interval, Point[] snodePoint)
à partir du principal, le graphique doit être mis à jour dans 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;
}
}
En quelques mots, je dois
Comment pourrais-je faire ça?
L'activité principale avec le 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) {
}
}
}
La première fois que je crée le fragment, l'activité principale passe avec succès les paramètres au fragment par le biais de la fonction getItem(int position)
remplacée, mais si j'essaie de modifier les données, également si j'essaie d'appeler notifyDataSetChanged()
sur l'adaptateur mMyFragmentAdapter
, rien ne se passe et les fragments dans ViewPager
continuent d'utiliser les mêmes données transmises lors de la création.
MODIFIER
Après un code partiel vu dans une autre question sur la mise à jour du fragment, j'ai également essayé
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();
}
}
En supposant que 0 est l'id du premier fragment Fragment-Tab (je ne suis pas sûr de ce type d'opération), mais fragment.updateDisplay();
n'est pas invoqué.
Dans votre adaptateur, remplacez getItemPosition
@Override
public int getItemPosition(Object object) {
// POSITION_NONE makes it possible to reload the PagerAdapter
return POSITION_NONE;
}
Après ça
viewPager.getAdapter().notifyDataSetChanged()
devrait marcher.
J'ai besoin de comprendre comment le Fragment peut faire passer les données par le principal, peut-être que je manque quelque chose mais vraiment je n'ai pas compris comment pourrais-je faire cela.
De cela, il semble que vous souhaitiez transmettre les données au moment de la création du Fragment
. Si c'est ce que vous voulez, vous ne devez pas créer de constructeur personnalisé (et généralement pour un Fragment
, vous ne devriez avoir que le constructeur sans argument par défaut (car la plate-forme en a besoin pour recréer le Fragment
à certains moments)).
Au lieu de cela, vous devez soit passer les données dans un 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;
//...
}
}
Cela ne fonctionnera que si les données peuvent être placées dans un Bundle
(voir la méthode put...
De la classe Bundle
, toutes les primitives + objets qui sont Parcelable
). Dans le fragment, vous pouvez ensuite récupérer les arguments à l'aide de getArguments()
.
Vous pouvez également faire en sorte que Fragment
récupère les données directement à partir de Activity
:
// in the lifecycle method where you want the data
((MainActivity)getActivity()).getDataForFragment(); // use the data
Par exemple, j'ai ce fragment qui montre un graphique, (dans mon intention) lorsque j'appelle setFragment (int interval, Point [] snodePoint) à partir du principal, le graphique doit être mis à jour dans ViewPager
Vous semblez vous contredire. Pour cela, utilisez le code de la question à laquelle j'ai lié, bien sûr, le simple fait d'appeler votre méthode setFragment()
actuelle ne fera rien car vous mettez simplement à jour la valeur de deux variables, vous devrez informer l'interface utilisateur de le changement (comme appeler une autre méthode pour recréer la hiérarchie des vues, définir les nouvelles valeurs sur la vue graphique et appeler invalidate()
etc).
Modifier:
Le code utilisé dans la question à laquelle j'ai lié devrait fonctionner, mais vous n'utilisez pas le bon code. Vous avez un FragmentStatePagerAdapter
mais vous utilisez le code d'un FragmentPagerAdapter
qui ne fonctionnera pas:
FragmentStatePagerAdapter a = (FragmentStatePagerAdapter) mViewPager.getAdapter();
LineFragment f = (LineFragment) a.instantiateItem(pager, thePositionYouWant);
Gardez à l'esprit que le code ci-dessus ne fonctionnera que pour le fragment visible plus 1 fragment de chaque côté, les autres fragments ne seront pas disponibles (et comme l'utilisateur ne les voit pas ou ne peut pas les déplacer immédiatement, ils ne devraient pas '' t être mis à jour).
#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
}
très simple pour remplacer la méthode dans le fragment
@Passer outre
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
actionView();
}
else{
//no
}
}