ViewPager, Fragments

P

Panikmeister

Neues Mitglied
0
Hallo Leute,

ich habe da ein kleines Problem.

Meine MainActivity steuert mit einem ViewPager 3 Fragments(kombiniert mit nem TabAdapter).

Diese Fragments enthalten jeweils ListViews, welche mit einem ArrayAdapter befüllt werden.

Bsp: Fragment1 : Einkaufslistenübersicht.

Nun muss bei einem Klick auf Einkaufsliste XY ein neues Fragment geöffnet werden, welches die in der Einkaufsliste enthaltenen Artikel anzeigt.

Wie soll ich dieses Fragment erstellen?
Callbacks zur MainActivity sind schon erstellt und funktionieren auch.

Der Viewpager selber steuert ja nur die 3 "Hauptfragments"...

UND: Wie kann kann ich das aktuell angezeigte Fragment herausfinden? Über den Fragmentmanager, nehme ich an..aber welche Methode?


Wäre super, wenn Ihr mir weiterhelfen könntet.

Viele Grüße,

Jan



Anbei das Layout.



Und hier Code-Snippets:

MainActivity:

Code:
public class Main extends FragmentActivity implements ListeOverviewAdapter.OnListeSelectedListener,
        RezeptOverviewAdapter.OnRezeptSelectedListener, VorratOverviewAdapter.OnVorratSelectedListener {

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

        final ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        final ViewPager pager = (ViewPager) findViewById(R.id.viewPager);
        pager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));

        pager.setOnPageChangeListener(
                new ViewPager.SimpleOnPageChangeListener() {
                    @Override
                    public void onPageSelected(int position) {
                        getActionBar().setSelectedNavigationItem(position);
                    }
                });

        ActionBar.TabListener tabListener = new ActionBar.TabListener() {
            @Override
            public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
                pager.setCurrentItem(tab.getPosition());
            }

            @Override
            public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {

            }

            @Override
            public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {

            }
        };

        actionBar.addTab(actionBar.newTab().setText("Einkaufslisten").setTabListener(tabListener));
        actionBar.addTab(actionBar.newTab().setText("Rezepte").setTabListener(tabListener));
        actionBar.addTab(actionBar.newTab().setText("Vorrat").setTabListener(tabListener));
    }
Code:
    // Callbacks der Fragmente

    // EK-Liste. (Fragment 1)
    @Override
    public void onListeSelected(int message, int position) {
        switch(message) {
            case Global.MSG_SELECT:
                Toast.makeText(this, "SELECT Liste" + position, Toast.LENGTH_SHORT).show();
                break;
            case Global.MSG_EDIT:
                Toast.makeText(this, "EDIT Liste" + position, Toast.LENGTH_SHORT).show();
        }
    }
Code:
 private class MyPagerAdapter extends FragmentPagerAdapter {

        public MyPagerAdapter(FragmentManager fm) {
            super(fm);
        }



        @Override
        public android.support.v4.app.Fragment getItem(int pos) {
            switch(pos) {
                // Neues Fragment erstellen und Tag geben.
                // Fragment fragment = getFragmentManager().findFragmentByTag("yourstringtag");
                case 0: return ListeOverviewFragment.newInstance("ListeOverviewFragment");
                case 1: return RezeptOverviewFragment.newInstance("RezeptOverviewFragment");
                case 2: return VorratOverviewFragment.newInstance("VorratOverviewFragment");
                default: return ListeOverviewFragment.newInstance("ListeOverviewFragment");
            }
        }

        @Override
        public int getCount() {
            return 3;
        }
    }
Fragment 1:

Code:
public class ListeOverviewFragment extends Fragment {

    private Context context;
    private Datasource datasource;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.listeoverview_fragment, container, false);
        this.context = getActivity();
        this.datasource = new Datasource(getActivity());

        ListView lv = (ListView) v.findViewById(R.id.listeOverview_listView);
        lv.setAdapter(new ListeOverviewAdapter(context, this.datasource.getListeOverviewData()));

        return v;
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

    }


    public static ListeOverviewFragment newInstance(String text) {

        ListeOverviewFragment f = new ListeOverviewFragment();
        Bundle b = new Bundle();
        b.putString("TAG", text);

        f.setArguments(b);


        return f;
    }

}
Adapter für Fragment 1:

Code:
public class ListeOverviewAdapter extends ArrayAdapter<ListeOverviewModel> {

    Context context;
    List<ListeOverviewModel> data;
    OnListeSelectedListener mListener;

    public ListeOverviewAdapter(Context con, List<ListeOverviewModel> objects) {
        super(con, R.layout.listeoverview_adapter , objects);

        this.context = con;
        this.data = objects;

        try {
            mListener = (OnListeSelectedListener) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString() + " must implement OnArticleSelectedListener");
        }
    }


    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        // Get the data item for this position
        ListeOverviewModel ekListe = getItem(position);
        // Check if an existing view is being reused, otherwise inflate the view
        ViewHolder viewHolder;

        if (convertView == null) {

            viewHolder = new ViewHolder();

            convertView = LayoutInflater.from(getContext()).inflate(R.layout.listeoverview_adapter, parent, false);

            viewHolder.tvName = (TextView) convertView.findViewById(R.id.listeOverview_tvName);
            viewHolder.tvProgress = (TextView) convertView.findViewById(R.id.listeOverview_tvProgress);
            viewHolder.btEdit = (Button) convertView.findViewById(R.id.listeOverview_btEdit);
            viewHolder.tvSubtitle = (TextView) convertView.findViewById(R.id.listeOverview_tvSubtitle);
            convertView.setTag(viewHolder);
        }
        else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        viewHolder.tvName.setText(ekListe.getName());
        viewHolder.tvProgress.setText(ekListe.getProgress());
        viewHolder.tvSubtitle.setText(ekListe.getKategorie());

        viewHolder.tvName.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mListener.onListeSelected(Global.MSG_SELECT, position);
            }
        });

        viewHolder.btEdit.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mListener.onListeSelected(Global.MSG_EDIT, position);
            }
        });
        // Return the completed view to render on screen
        return convertView;
    }

    public interface OnListeSelectedListener {
        public void onListeSelected(int message, int position);
    }


    private static class ViewHolder {

        TextView tvName;
        TextView tvProgress;
        TextView tvSubtitle;
        Button btEdit;

    }

}
 
Wie soll ich dieses Fragment erstellen?
Es gibt, wie so oft, mehr als nur eine Möglichkeit. Zwei davon wären:

Deine MainActivity hält ein BaseFragment, welches den Viewpager mit seinen drei Fragmenten hält (per childFragmentManager).
Dann sagst du der MainActivity einfach, dass sie das fragment austauschen soll. Dabei packst du das auf den backstack, so dass du zurück kannst, ohne dabei das Programm zu beenden.

Die zweite Möglichkeit ist, einfach eine neue Aktivität zu starten, die dann das DetailFragment lädt. Diese Variante wird auf Telefonen öfter genutzt, weil sie eben so simple ist.

aktuell angezeigte Fragment herausfinden
über den ViewPager natürlich: onPageSelected(int position) via OnPageChangeListener.
 
tuppy schrieb:
Es gibt, wie so oft, mehr als nur eine Möglichkeit. Zwei davon wären:

Deine MainActivity hält ein BaseFragment, welches den Viewpager mit seinen drei Fragmenten hält (per childFragmentManager).
Dann sagst du der MainActivity einfach, dass sie das fragment austauschen soll. Dabei packst du das auf den backstack, so dass du zurück kannst, ohne dabei das Programm zu beenden.

Die zweite Möglichkeit ist, einfach eine neue Aktivität zu starten, die dann das DetailFragment lädt. Diese Variante wird auf Telefonen öfter genutzt, weil sie eben so simple ist.

über den ViewPager natürlich: onPageSelected(int position) via OnPageChangeListener.

Danke erstmal für die schnelle Antwort!

Die erste Möglichkeit hört sich gut an, werde ich mal ausprobieren.:thumbup:
 
Noch eine kleine Frage:

Ich möchte meinen ListView-Items am rechten Rand einn Spinner spendieren, der 3-4 Einträge zeigt beim Klick auf ihn.

Allerdings soll er kein Standarditem anzeigen, es soll wie auf dem Bild aussehen. Ich kriege das leider nicht hin :( :(



Und erst beim Klick darauf, sollen die Einträge angezeigt werden. Bei Auswahl der Einträge soll etas ausgeführt werden und der Spinner wieder in seinen Ursprungszustand (wie auf dem Bild) zurückgehen.




EDIT:

Ich möchte eine Löschfunktion implementieren, die auf Knopfdruck Löschsymbole vor jeder Row einer ListView anzeigt (wie auf dem Bild).

Wie mache ich das am besten?

Nachträglich Buttons einfügen ginge sicher nur über ein erneutes Ablaufen
von getView() meines Adapters -> zeitaufwendig.

Anfangs versteckte Buttons, die beim Aktivieren der Löschfunktion sichtbart werden, nehmen von Anfang an Platz ein -> auch nicht schön. :confused2:
(Es geht nur um das kleine Symbol links.)

wecker-300x128.png
 
Zuletzt bearbeitet:
Es gibt Möglichkeiten, einem Spinner zu einem leeren "Starteintrag" zu zwingen. Ist allerdings nicht Sinn und Zweck eines Spinners.

Wie wäre es mit einem Button mit einem von dir gewählt Hintergrund und bei onClick geht stattdessen ein PopupMenu auf? Ist auch in der v7er support library drin.

Zu deiner Löschfunktion. Ich weiß nun nicht, was du genau basteln möchtest, aber um mal allgemein zu bleiben:

Es gibt in Android akzeptierte, den Designrichtlinien konformen Möglichkeiten.

Eine Möglichkeit:
"Swipe to delete" - ein nach links oder rechts "wegwischen" der Einträge mit anschließendem "undo-Toast". Dies funktioniert natürlich nicht in einem ViewPager.

Zweite Möglichkeit:
Der Gebrauch der kontextsensitiven ActionBar.
-> LongPress auf einen Eintrag makiert diesen und startet den ActionMode.


Sind dir diese Möglichkeiten bekannt / kommt die zweite für dich in Frage?


Noch am Rande: Deine Bilder sind nicht aussagekräftig. Um es eindeutiger zu machen, wäre es sehr hilfreich, das komplette list item zu sehen. Halt mit dummy daten.
 
Es geht auch ein bisschen einfacher:

Einfügen eines items

Code:
mArrayAdapter.add(myData); 
mArrayAdapter.notifyDataSetChanged();
 spinner.setSelection(mArrayAdapter.getPosition(myData))
Entfernen eines items:

Code:
mArrayAdapter.remove(myData);
mArrayAdapter.notifyDataSetChanged();
Du muss den ArrayAdapter so umschreiben, das er eine ViewGroup mit einen ImageView einfügt (z.B. ein LinearLayout). Das ImageView blendest du aus, mit der Methode setVisibility(View.GONE). Um da Bild anzuzeigen, holst du dir den betreffenden View mit spinner.getChildAt(index). Dann suchst du das betreffende View mit findViewById(...). Und machst den ImageView mit setVisibility(View.VISIBLE) sichtbar.
 
tuppy schrieb:
Es gibt Möglichkeiten, einem Spinner zu einem leeren "Starteintrag" zu zwingen. Ist allerdings nicht Sinn und Zweck eines Spinners.

Wie wäre es mit einem Button mit einem von dir gewählt Hintergrund und bei onClick geht stattdessen ein PopupMenu auf? Ist auch in der v7er support library drin.

Zu deiner Löschfunktion. Ich weiß nun nicht, was du genau basteln möchtest, aber um mal allgemein zu bleiben:

Es gibt in Android akzeptierte, den Designrichtlinien konformen Möglichkeiten.

Eine Möglichkeit:
"Swipe to delete" - ein nach links oder rechts "wegwischen" der Einträge mit anschließendem "undo-Toast". Dies funktioniert natürlich nicht in einem ViewPager.

Zweite Möglichkeit:
Der Gebrauch der kontextsensitiven ActionBar.
-> LongPress auf einen Eintrag makiert diesen und startet den ActionMode.


Sind dir diese Möglichkeiten bekannt / kommt die zweite für dich in Frage?


Noch am Rande: Deine Bilder sind nicht aussagekräftig. Um es eindeutiger zu machen, wäre es sehr hilfreich, das komplette list item zu sehen. Halt mit dummy daten.

Das mit dem Popup-Menu werde ich dann machen.

Das Löschen habe ich jetzt mit dem zusätzlichen ImageButton gemacht, der bei Bedarf eingeblendet wird (siehe Foto).

Einen Viewpager werde ich nachträglich einbauen, um zwischen den Fragmenten zu navigieren per Swipe.

Danke nochmal, Leute ;)

 
Hi,

wenn die App für Deinen Gebrauch ist, ist alles okay. Wenn Du die App Veröffentlichen möchtest, solltest du besser kein Popup-Menu verwenden.

Jeder Anwender vermutet dort ein Menü, kein Anwender eine Liste. Es ist immer besser, die Designelemente zu verwenden, die auch alle anderen Apps verwenden. Der User ist in der Regel eine Gewohnheitstier, und eine Liste erwartet er nicht im Popup-Menu. Im Endeffekt wird der User die App deinstallieren, weil er ein anderes Verhalten erwartet. Am besten benutzt du ein ListView für deine Aufzählung.
(Bei Apple wäre es ein Grund, die App abzuweisen. Google ist da wesentlich toleranter.)

Am besten hältst Du dich an der Doku von Android. Und dort ist das Popup-Menu eben ein Menu.
Es gibt eine Doku für den Use-Case von Apps.

Patterns | Android Developers

Design | Android Developers
 
getCurrentItem() angewandt auf den ViewPager gibt Dir den Index des aktuellen Fragments zurück. ;)
 
Nabend Leute,

klitzekleine Frage:

Bei Klick auf Button XY möchte ich eine neue Einkaufsliste erstellen.
Diese kriegt nur einen Namen verpasst, den der User eingeben kann.

Dafür eine neue Activity, die den gesamten Bildschirm einnimmt, halte ich für übertrieben.

Gibt es ne Möglichkeit, dass ein Minifenster aufpoppt mit der Textbox zum reinschreiben und 2 Buttons ?
 
Ahh perfekt, danke!

Und gleich noch ne Frage:

Ich habe verschiedene Adapter, die alle von ArrayAdapter erben.

Nun muss man ja immer ein object übergeben.

Code:
public class RezeptOverviewAdapter extends ArrayAdapter<[B]RezeptOverviewModel[/B]>


Nun würde ich diese Adapter gern übergeben.


Code:
    public class PopupItemListener implements PopupMenu.OnMenuItemClickListener {

        private RezeptOverviewAdapter adapter;
        private int position;

        public PopupItemListener(RezeptOverviewAdapter ad, int pos) {
            this.position = pos;
            this.adapter = ad;
        }

        @Override
        public boolean onMenuItemClick(MenuItem item) {

            switch(item.getItemId()) {
                case R.id.rezeptOverview_menu_edit:
                    mListener.onRezeptSelected(Global.MSG_EDIT, position, [B]adapter[/B]);
                    break;
                default:
                    break;
            }

            return true;
        }
    }

Im Moment habe ich in allen Adaptern so einen PopUpListener, der immer dasselbe macht, implementiert.
Allerdings übergibt der jeweils einen anderen Adapter.

Ich würde den PopUpListener gern zentralisieren. Wie kann ich es erreichen, dass man dem Listener nen Adapter übergibt, wo der Parameter erst zur Laufzeit feststeht (RezeptOverviewModel, ArtikelModel usw) ?

Man müsste sicherlich eine Oberklasse für die verschiedenen Adapter bilden, die dann davon erben und dann diese Oberklasse dem PopUpListener übergeben und dann jeweils casten.

Code:
    public class PopupItemListener implements PopupMenu.OnMenuItemClickListener {

        private OberklasseDesAdapters adapter;
        private int position;

        public PopupItemListener(OberklasseDesAdapters ad, int pos) {
            this.position = pos;
            this.adapter = ad;
        }

Wie kann ich denn diesen OberklassenAdapter bauen? Da muss es doch so ein Schlüsselwort geben?

Code:
public class RezeptOverviewAdapter extends OberklasseAdapter<[B]?[/B]>

Geht das überhaupt?
 
Man kann mittels <? extends BaseModel> abstrahieren. Aber ob das reicht, hängt von deinem Anwendungsfall ab.
 
Hallöchen,

habe nun mit AutoCompleteTextView herumgespielt (für eine Suche).
Ich habe einen eigenen ArrayAdapter der 2 Objekte pro Zeile zurückliefert:
Name-Textview und Imagebutton(um den jeweiligen Eintrag hzinzuzufügen), der einen Listener bekommt.

Nun will das Ding keine Vorschläge liefern. Ich denke es liegt daran, dass er bei einem normalen String-Array die Strings durchforstet für Vorschläge.

Bei meinem Artikel-Model, weiß er vll nicht, welches Objekt er durchforsten soll. Wie kann ich ihm das mitteilen?

Viele Grüße,

Jan


Code:
ActionBar actionBar = getActionBar();
        actionBar.setCustomView(R.layout.actionbar_search);

        AutoCompleteTextView searchView = (AutoCompleteTextView) actionBar.getCustomView().findViewById(R.id.search);


        SearchViewAdapter adapter = new SearchViewAdapter(this, this.datasource.getArtikelDBData(),Global.ARTIKEL_DB);
        searchView.setAdapter(adapter);
        searchView.setDropDownAnchor(R.id.searchview_tvName);


Adapter-Layout
Code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >

<TextView
    android:id="@+id/searchview_tvName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="aaa"
    android:textSize="30sp" >
</TextView>

<ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:paddingBottom="15dp"
    android:paddingTop="15dp"
    android:background="@drawable/ic_action_new"
    android:id = "@+id/searchview_ibAdd"/>

</RelativeLayout>

Adapter:

Code:
public class SearchViewAdapter extends ArrayAdapter<Artikel_Model>  {


    protected Context context;
    protected SearchViewAdapter adapter;
    protected List<Artikel_Model> data;
    protected List<ViewHolder> holderList;
    protected int tag;

    public SearchViewAdapter(Context con, List<Artikel_Model> objects, int _tag) {
        super(con, R.layout.searchview_adapter , objects);

        this.context = con;
        this.data = objects;
        this.adapter = this;
        this.holderList = new ArrayList<ViewHolder>();
        this.tag = _tag;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {

        Artikel_Model artikelListe = getItem(position);

        ViewHolder viewHolder;

        if (convertView == null) {

            viewHolder = new ViewHolder();

            convertView = LayoutInflater.from(getContext()).inflate(R.layout.searchview_adapter, parent, false);

            viewHolder.tvName = (TextView) convertView.findViewById(R.id.searchview_tvName);
            viewHolder.ibAdd = (ImageButton) convertView.findViewById(R.id.searchview_ibAdd);

            convertView.setTag(viewHolder);
        }
        else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        viewHolder.tvName.setText(artikelListe.getName());


        viewHolder.ibAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context, "Artikel hinzugefügt", Toast.LENGTH_SHORT);
            }
        });


        this.holderList.add(viewHolder);

        return convertView;
    }

    public static class ViewHolder {

        public TextView tvName;
        public ImageButton ibAdd;

    }
}
 
Zuletzt bearbeitet:

Ähnliche Themen

Tiefkuehlpizza
Antworten
2
Aufrufe
954
Tiefkuehlpizza
Tiefkuehlpizza
M
Antworten
2
Aufrufe
863
jogimuc
J
W
Antworten
1
Aufrufe
847
jogimuc
J
Zurück
Oben Unten