[OFFEN] DialogFragment dynamisch mit RecyclerView füllen

deka

deka

Dauergast
351
Hallo zusammen, es geht um folgendes:
Der Nutzer scannt mithilfe der App ein Formular ein, auf dem Sachen wie Name, Adresse, PLZ usw. stehen. Anschließend zeige ich einen Ladebildschirm, da das ganze nun verarbeitet wird (Texterkennung). Sobald alles geladen wurde, erstelle ich ein DialogFragment und stelle das Ergebnis dar. Das wären dann beispielsweise 10 Felder. Das ganze dauert leider etwas und daher wäre folgendes die optimale Lösung für mich:
Sobald der Nutzer das Formular gescannt hat, erstelle ich direkt das (leere) DialogFragment und fülle es dynamisch in einer festen Reihenfolge auf, sobald ein Ergebnis da ist. Beispiel:

Name: (noch nicht ermittelt)
Adresse: (noch nicht ermittelt)
PLZ: 74080 (wird gefüllt, da es bereits ermittelt wurde)
Telefon: (noch nicht ermittelt)
...

Das ganze will ich nun natürlich mit einem RecyclerView umsetzen. Die Frage ist nur wie genau das funktionieren soll.
Kann mir jemand ein paar Tipps dazu geben?

Danke euch!
 
Moin deka,

ich habs nicht ganz verstanden :)

Die Zeit des Scannes und der Lesung kannst du m.E, nicht verkürzen , oder bin ich jetzt auf dem
falschen Dampfer ?

Was das ReycleView betrifft : Wenn ich das richtig verstanden habe , dann willst du leere Items erzeugen , das Ding rödelt noch im Hintergrund und macht seine Recognition fertig- und wenn der fertig ist , soll der das leere Feld dann mit den Erkannten füllen ?
 
Hey :) Es geht mir nicht darum die Zeit zu verkürzen, sondern darum, dass ich wenn ich einen Teil erkannt habe, es direkt anzeige. Im Moment ist es ja so, dass das Fragment erst erzeugt wird wenn ALLES komplett ermittelt wurde. Beispielsweise 10 Elemente. Und dann wartet der Benutzer hier ca. 15 Sekunden. Ich möchte es jedoch so machen, dass direkt nach dem Scannen das FragmenDialog angezeigt wird und wenn von den 10 Elementen das erste erkannt wird, es direkt anzeigen. Und dann das zweite, das dritte usw.. Also quasi die Anzeige dynamisch auffüllen.

Ich brauche dann in dem Fall auch vordefinierte TextViews mit Name, Vorname usw.. Wüsste jedoch nicht wie ich das anstellen soll mit dem RecyclerView.
 
Okkkeee, dann gehen wir mal schritt für schritt vor ...

erste frage : Dein Scan/Recognition Ablauf ist in einem Task/Thread ??
Dann könntest du ja in der Zeit Anzeigen was du magst - nebenbei noch tetris spielen
 
Die Ermittlung erfolgt in einem Task.
 
Ich glaube ich komme jetzt dahinter , was du meinst . :)

Es geht dir vordergründig gar nicht um den Scan , sondern darum
"Wie erstelle ich ein leeres Item in einem RecycleView , zeige es an und wenn ich es updaten will , wie ändere ich die Daten ?"

Richtig ?

Du kannst dir einen ReycleView bauen und dem z.b. mit einem ArrayAdapter CardViews hinzufügen.

Dein ArrayDapter (List) behinhaltet dann einen Datensatz , der vordefiniert gefüllt ist
Dazu solltest du dir einen CustomAdapter bauen

Wenn dein Scann da ist , nimmst du dir dann das DatenArray des Adapters , holst dir dann den Datensatz raus (get)
tauschst den Inhalt und setzt ihn neu (set)
Und danach machst du ein notifyDataChange auf den Adapter
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: deka
Genau das habe ich vor :) Ich habe mal mit dem Adapter und Holder angefangen. Soll ich jetzt meinen Adapter in einen ArrayAdapter umändern? Meinen Holder habe ich so definiert, dass er nur eine TextView enthält. Das wäre ja dann mein Ergebnistext. Aber ich verstehe nicht wie ich diesen vorgefüllten Datensatz erzeugen soll und an welcher Stelle. Kannst du mal ein Beispiel zeigen?

Mein Holder:
Code:
public class ResultHolder extends RecyclerView.ViewHolder {

    TextView tvResult;

    public ResultHolder(View itemView) {
        super(itemView);
        tvResult = (TextView) itemView.findViewById(R.id.tv_item);
    }

}

Mein Adapter:
Code:
public class ResultAdapter extends RecyclerView.Adapter<ResultHolder> {

    private String[] results;

    @Override
    public ResultHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.result_list_item, viewGroup, false);
        ResultHolder resultHolder = new ResultHolder(view);
        return resultHolder;
    }

    @Override
    public void onBindViewHolder(ResultHolder resultHolder, int position) {
        resultHolder.tvResult.setText(results[position]);
    }

    @Override
    public int getItemCount() {
        return results.length;
    }

    public void setResults(String[] results) {
        this.results = results;
        notifyDataSetChanged();
    }
}

EDIT:

In meinem DialogFragment mache ich bisher nur das hier:
Code:
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_result_dialog, container, false);
        rvResults = (RecyclerView) v.findViewById(R.id.rv_results);
        rvResults.setLayoutManager(new LinearLayoutManager(getActivity()));

        ResultAdapter adapter = new ResultAdapter();
        rvResults.setAdapter(adapter);

        return v;
    }
 
_screen_1.png

Sowas willste machen ? - Kommt aus meiner app
 
Kommt darauf an wie das umgesetzt ist :) In meinem Fall will ich nur Text anzeigen.
Wird das bei dir nach und nach reingeladen?
 
okeee, jetzt kommen wir der Sache immer näher , sieht schon mal gut aus :)

Anstatt nur einem TextView kannst du ja auch eine Struckturklasse übergeben , die halt aus 5 Textfeldern besteht

z.b.
Code:
public class FRAGMENT_ORDER
{
    public String  text1 ;
    public String  text1 ;
    public FRAGMENT_ORDER()
    {
        text1          = "";
        text2          = "";
    }
}


Und deine Datenliste deklarierst du

ArrayList < FRAGMENT_ORDER> fg = new ArrayList <FRAGMENT_ORDER> ();
FRAGMENT_ORDER ff = new FRAGMENT_OREDR()
ff.text1 = "älkjälkjäljäljälk";
ff.text2 = "älkjälkjäljälkj";
fg.add (ff);

Und diese Array kannst du anstatt dem Textview an den Adapter geben
 
Ok, jetzt stehe ich etwas auf dem Schlauch. Das heißt, ich definiere da jetzt meine 5 festen Textfelder (Name, Adresse usw.) und gebe sie dem Adapter mit. Ersetze damit die TextView. Aber die TextView brauche ich doch für jedes einzelne Element oder nicht?
 
Du machst dir erst eine Arraylist mit mehreren strukturklassen - siehe oben
Diese übergibst du dem Adapter.
(Die struktur hat dann schon dein 5 felder) - oder wie oben nur 2


Willst du einen datendatz ändern willst kannst du die elemente aus der Arraylist herausnehmen ( get) , ändern (set)
und rufts ein notifyDataChanged auf den ADapter auf .

Im Adapter selbst setzt du dann in das Textview die Daten

Hier als Anhaltpunkt das reycleView zum obigen screenshot.
(Nur copy & paste) damit du im groben nachvollziehen kannst


Code:
public class EPUBBookList_Adapter extends RecyclerView.Adapter<EPUBBookList_Adapter.MyViewHolder>
{
    private Context                         mContext;
    private List<EPUBBook_Struct> albumList;
    private OnClickListener       onClickListener;
    private int                         mCurrentMenuPosition = -1;

    ////////////////////////////////////////////////////////////////////////////////////////
    public interface OnClickListener
    {
        public void onClick(int position);
        public void onNeedReload(int position, Boolean refreshList);
    }

    ////////////////////////////////////////////////////////////////////////////////////////
    public void setOnClickListener(OnClickListener listener)
    {
        onClickListener = listener;
    }

    ////////////////////////////////////////////////////////////////////////////////////////
    public class MyViewHolder extends RecyclerView.ViewHolder
    {
        public TextView title, count;
        private String mItem;
        public ImageView thumbnail, overflow,checkreaded;

        public MyViewHolder(View view)
        {
            super(view);
            title = (TextView) view.findViewById(R.id.title);

            count = (TextView) view.findViewById(R.id.count);
            thumbnail = (ImageView) view.findViewById(R.id.thumbnail);
            overflow = (ImageView) view.findViewById(R.id.overflow);
            checkreaded = (ImageView) view.findViewById(R.id.check_readed);
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////
    public EPUBBookList_Adapter(Context mContext, List<EPUBBook_Struct> albumList)
    {
        this.mContext = mContext;
        this.albumList = albumList;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        LayoutInflater mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View itemView = mInflater.inflate(R.layout.epub_album_card,null);
        return new MyViewHolder(itemView);

    }
    ////////////////////////////////////////////////////////////////////////////////////////
    @Override
    public void onBindViewHolder(final ViewHolder holder, int position)
    {
        EPUBBook_Struct album = albumList.get(position);

        final int pos = position;

        holder.title.setText(album.title);
        holder.count.setText(album.author);

        // loading album cover using Glide library
        if (album.coverurl.equals("default"))
            Glide.with(mContext).load(R.drawable.epub_nocover).into(holder.thumbnail);
        else
            Glide.with(mContext).load(album.coverurl).into(holder.thumbnail);


        if (album.percent.equals("100"))
        {
            holder.checkreaded.setVisibility(View.VISIBLE);
            holder.checkreaded.bringToFront();
        }
        else
            holder.checkreaded.setVisibility(View.INVISIBLE);



        holder.overflow.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {  mCurrentMenuPosition = pos;
                showPopupMenu(holder.overflow);
            }
        });
        holder.thumbnail.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                if (onClickListener != null) onClickListener.onClick(pos);
                //Toast.makeText(mContext,"clicked="+ pos,Toast.LENGTH_SHORT).show();
            }
        });


    }


INIT


Code:
  albumList = new ArrayList<>();
  adapter = new EPUBBookList_Adapter(act, albumList);
recyclerView.setAdapter(adapter);

//   Hier albumlist  füllen  / ändern

adapter.notifyDataSetChanged();

:
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: deka
Danke dir. Jetzt hänge ich an einer anderen Stelle. Undzwar erzeuge ich dieses DialogFragment aus einem anderen Fragment heraus. Dieses Fragment hat die ganzen Listener und bekommt eben auch mit wenn die Ermittlung fertig ist. Es werden immer zwei Seiten gescannt. Wenn Seite 1 fertig ist soll er das nun dem DialogFragment mitteilen und anschließend auch die Fertigstellung von Seite 2. Wie teile ich das meinem DialogFragment nun mit?
Mach ich das mit einem Bundle oder muss ich onCreateView aufrufen? Oder doch ganz anders?
 
Es gibt verschiedene Möglichkeiten
So genau kenne ich halt deinen Aufbau nicht .

Diese drei Dinge verwende ich recht häufig
a) Callback-Listener ( siehe auch im Source oben)
b) Broadcast Messages
c) SingleTons

Bevor du deine Klassenstruktur umbauen musst , würde ich in deinem Falle
zu einem Broadcast hin tendieren.
Ansonsten für die Zukunft eher Listener
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: deka

Ähnliche Themen

J
Antworten
5
Aufrufe
930
swa00
swa00
E
Antworten
2
Aufrufe
777
ekaya999
E
M
  • maksimilian
Antworten
3
Aufrufe
1.125
maksimilian
M
Zurück
Oben Unten