5

Ich habe ein Fragment mit einer Methode setName(), die einen EditText-Text mit Hilfe der Funktion setText ändert.Zugriff auf eine Methode eines Fragments aus der ViewPager-Aktivität

Wie kann diese Methode am besten von der Aktivität aufgerufen werden, die dieses Fragment über einen ViewPager hostet?

Mit anderen Worten, wie kann ich auf die Methoden eines Fragments zugreifen (die zum Beispiel das Layout des Fragments ändern) von der Aktivität, die dieses Fragment mit Hilfe eines ViewPagers hostet?

Ich frage das, weil ich mehrere Möglichkeiten versucht habe, aber immer mit Fehlern.

+0

Sie können versuchen, eine Instanzvariable des Fragment zu erstellen mit den 's etName() 'Methode in Ihrer Aktivitätsklasse. Weisen Sie die Variable dem Fragment zu, wenn Sie es instanziieren. Sie können dann 'fragment.setName()' aus Ihrer Aktivität aufrufen – Scott

+0

Ich habe dieses Problem, aber das Aufrufen von fragment.setName() über einen gespeicherten Verweis darauf, ist nicht das Problem. Das Problem besteht darin, dass getActivity() vom Fragment den Wert null zurückgibt, sodass auf Sichten nicht zugegriffen werden kann. Ich kann jedoch auf die Ansichten von der Aktivität zugreifen, und das Fragment konnte Informationen in die Ansichten, die zu dem Fragment bei der Konfiguration gehören, setzen. Aber später gibt die Funktion getActivity() null zurück und könnte es etwas sein, bei dem der viewPager die Kontrolle über den Kontext übernimmt, so dass getActivity tatsächlich nicht gültig ist? Also müsste man die Ansicht vom Viewpager anfordern? Ich frage. – carl

Antwort

3

Sie können auf öffentliche Methoden innerhalb der Fragmente zugreifen, die von Ihrer ViewPager gehalten werden. Sie müssen entweder (1) einen Verweis auf die Fragment speichern, wenn Sie ihn erstellen, und ihn der Liste hinzufügen, die Ihren Pager-Adapter unterstützt, oder (2) Sie müssen einen Verweis auf das Fragment vom Pager-Adapter selbst erhalten. Zum Beispiel:

Fragment fragmentA = null; //instance variable 

fragmenA = new Fragment(); //whereever you instantiate your fragment 

Wenn Ihre Methode ist

public void setName(String args){ 
    //do something 
} 

alles, was Sie tun würde, ist diese Methode aus dem Verweis auf das Fragment von Ihrem ViewPager

fragmentA.setName(args); 

Sie passieren unabhängig Argumente gehalten rufen Sie brauchen nur eine normale Methode aufzurufen. Beachten Sie, dass dies NUR funktioniert, wenn Sie eine Methode innerhalb eines Fragments aufrufen, das ViewPager oder FragmentActivity enthält. Wenn Sie den umgekehrten Vorgang ausführen wollen, müssen Sie ein inerface verwenden.

+0

Ja, das weiß ich schon. Aber was, wenn ich versuche, es zu instantiieren, indem ich etwas wie Frag1 fragment = (Frag1) mAppSectionsAdapter.getItem (0) verwende; Wie soll ich die Methode dann ohne die Nullzeiger-Ausnahme verwenden? – JZweige

+0

Es ist wie fragment.getView() ist immer null! – JZweige

+0

Sie möchten die Referenz von Ihrem Adapter bekommen? Ich bin nicht an meinem Computer, aber ich kann später Code eingeben, wenn das das Problem ist. – Rarw

8

Ich weiß, das ist ein bisschen spät, aber ich lief auf das gleiche Problem und vielleicht wird es anderen helfen, wenn Sie es bereits gelöst haben.

Das erste Problem mit ViewPager ist, dass es fast unmöglich ist, einen Verweis auf ein Fragment zu erhalten. Die Fragmente werden dynamisch in getItem() erstellt und daher können Sie keine ID setzen und sie werden automatisch vom swicher gelöscht, so dass Sie sie auch nicht per Tag finden können. Es gibt einige Möglichkeiten, dies zu tun, aber sie sind alle Workarounds. (Update data in ListFragment as part of ViewPager)

Die Art, wie ich es löste, benutzte im Wesentlichen einen doppelten Rückruf. Fragment A hat eine Schnittstelle, die durch die Hauptaktivität implementiert wird, die Hauptaktivität hat eine Schnittstelle, die durch Fragment B implementiert wird. Ein Button klickt in Fragment A die Callback-Funktion in Main Activity an, die wiederum den Callback in Fragment B aufruft. Schau dir den folgenden Code an. Ich hoffe ich habe alles gepostet und es wird helfen. Übrigens, ich habe das nur mit einem ViewPager versucht, aber ich nehme an, es würde mit jeder Art von Fragment-Kommunikation funktionieren.

Haupt avtivity java:

import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentActivity; 
import android.support.v4.app.FragmentManager; 
import android.support.v4.app.FragmentPagerAdapter; 
import android.support.v4.view.ViewPager; 

public class MainActivity extends FragmentActivity implements FragmentA.Caller { 

    SectionsPagerAdapter mSectionsPagerAdapter; 
    ViewPager mViewPager; 
    PassCallToB passOnToB = null; 
    FragmentManager myManager = null; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); 
     mViewPager = (ViewPager) findViewById(R.id.pager); 
     mViewPager.setAdapter(mSectionsPagerAdapter); 
    } 

    public class SectionsPagerAdapter extends FragmentPagerAdapter { 

     public SectionsPagerAdapter(FragmentManager fm) { 
      super(fm); 
      MyManager = fm; 
     } 

     @Override 
     public Fragment getItem(int position) { 
      Fragment fragment = null; 
      if(position == 0) { 
       fragment = new FragmentA(); 
      } else if (position == 1) { 
       fragment = new FragmentB(); 
       passOnToB = (PassCallToB)fragment; 
      } 
      return fragment; 
     } 

     @Override 
     public int getCount() { 
      return 2; 
     } 

     @Override 
     public CharSequence getPageTitle(int position) { 
      switch (position) { 
      case 0: 
       return "Frag A"; 
      case 1: 
       return "Frag B"; 
      } 
      return null; 
     } 

     public void setCallback() { 
      List<Fragment> frags = myManager.getFragments(); 
      for(Fragment fragment : frags) { 
       if(fragment instanceof FragmentB){ 
        passOnToB = (PassCallToB)fragment; 
       } 
      } 
     } 
    } 

    public interface PassCallToB { 
     public void passItOn(); 
    } 

    @Override 
    public void CallB() { 
     if(passOnToB instanceof Fragment) 
      passOnToB.passItOn(); 
     else { 
      mSectionsPagerAdapter.setCallback(); 
      passOnToB.passItOn(); 
     } 
    } 
} 

Hauptaktivität xml:

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/pager" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    tools:context=".MainActivity" > 

    <android.support.v4.view.PagerTitleStrip 
     android:id="@+id/pager_title_strip" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_gravity="top" 
     android:background="#33b5e5" 
     android:paddingBottom="4dp" 
     android:paddingTop="4dp" 
     android:textColor="#fff" /> 

</android.support.v4.view.ViewPager> 

Fragment A java:

import android.app.Activity; 
import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentActivity; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.view.ViewGroup; 
import android.widget.Button; 

public class FragmentA extends Fragment { 

    Button btnCallB = null; 

    Caller listener = null; 

    public FragmentA() { 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle inState) { 
     View rootView = inflater.inflate(R.layout.fragment_a, container, false); 

     btnCallB = (Button)rootView.findViewById(R.id.btnCallB); 
     btnCallB.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View view) { 
       listener.CallB(); 
      } 

     }); 

     return rootView; 
    } 

    public interface Caller { 
     public void CallB(); 
    } 

    @Override 
    public void onAttach(Activity activity) { 
     super.onAttach(activity); 
     if (activity instanceof FragmentActivity) { 
      listener = (Caller) activity; 
     } else { 
      throw new ClassCastException(activity.toString() + " must implemenet listener"); 
     } 
    } 

    @Override 
     public void onDetach() { 
     super.onDetach(); 
     listener = null; 
     } 
} 

Fragment A xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 


    <TextView 
     android:id="@+id/textView1" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentTop="true" 
     android:text="This is Fragment A" /> 

    <Button 
     android:id="@+id/btnCallB" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_below="@+id/textView1" 
     android:text="Call Fragment B" /> 

</RelativeLayout> 

Fragment B Java:

import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.Toast; 

public class FragmentB extends Fragment implements MainActivity.PassCallToB { 

    public FragmentB() { 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle inState) { 
     View rootView = inflater.inflate(R.layout.fragment_b, container, false); 
     return rootView; 
    } 

    @Override 
    public void passItOn() { 
     Toast.makeText(getActivity(), "Hello from B", Toast.LENGTH_SHORT).show(); 

    } 
} 

Fragment B xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

    <TextView 
     android:id="@+id/textView1" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentTop="true" 
     android:text="This is Fragment B" /> 

</RelativeLayout> 
+0

Dies funktioniert nicht, wenn Sie drehen. Wenn Sie die Aktivität drehen und Fragmente neu erstellt werden, wird auch Ihr SectionsPagerAdapter neu erstellt, aber getItem wird nie aufgerufen (Android erstellt die Fragmente neu, ohne getItem aufzurufen), dh passOnToB bleibt null. – rve

+0

Ich habe meinen Code bearbeitet, damit er nach der Bildschirmdrehung funktioniert. Der Trick besteht darin, den Callback nicht nur in getItem() zu setzen, sondern auch eine benutzerdefinierte Methode in den Pager-Adapter aufzunehmen, die die Fragmente durchsuchen und den Callback manuell setzen, wenn das korrekte Fragment gefunden wird. Jetzt müssen Sie nur noch prüfen, ob der Callback gesetzt ist, und diesen Wert setzen, wenn Sie nicht in der passOn-Methode sind. Ich hoffe, das ist etwas klar. – ckn

+0

Irgendeine Idee mit meiner? http://stackoverflow.com/questions/39907625/why-is-accessing-textview-of-a-fragment-inside-activity-throwing-an-error – Si8

1

Fragment

private static FragmentName instance; 

public static synchronized FragmentName getInstance() 
{ 
    return instance; 
} 

@Override 
public void onCreate(@Nullable Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
instance=this; 
.... 
} 

public void methodName() 
{...} 

Aktivität

FragmentName.getInstance().methodName();