[Java] Creare una sequenza di immagini nella stessa activity
Ciao ragazzi! Non so se questa sia la sezione giusta.
Sto facendo un'applicazione come progetto di ricerca dell'università.
In questa applicazione dovrei mostrare una sequenza di immagini per un determinato periodo di tempo (l'app si compone in due parti, che si differenziano per il tempo di visualizzazione dell'immagine). Quando l'immagine sparisce dovrei visualizzare un EditText dove si inserisce la valutazione dell'immagine; questa sequenza si ripeterà per un pò d'immagini (il numero si deciderà in seguito).
Prima di ogni immagine dovrò visualizzare una croce rossa a forma di X e dopo ogni immagine si dovrà visualizzare un'immagine detta "maschera" per qualche millisecondo.
L'idea è di mettere tutte le immagini che mi servono dentro la cartella "drawable".
Quello che vorrei capire è come creare questa activity o, se mi conviene creare un'attività per immagine. Oppure se è necessario utilizzare i "fragment" o le "custom view".
Spero di essere stato abbastanza chiaro.
Grazie!
Sto facendo un'applicazione come progetto di ricerca dell'università.
In questa applicazione dovrei mostrare una sequenza di immagini per un determinato periodo di tempo (l'app si compone in due parti, che si differenziano per il tempo di visualizzazione dell'immagine). Quando l'immagine sparisce dovrei visualizzare un EditText dove si inserisce la valutazione dell'immagine; questa sequenza si ripeterà per un pò d'immagini (il numero si deciderà in seguito).
Prima di ogni immagine dovrò visualizzare una croce rossa a forma di X e dopo ogni immagine si dovrà visualizzare un'immagine detta "maschera" per qualche millisecondo.
L'idea è di mettere tutte le immagini che mi servono dentro la cartella "drawable".
Quello che vorrei capire è come creare questa activity o, se mi conviene creare un'attività per immagine. Oppure se è necessario utilizzare i "fragment" o le "custom view".
Spero di essere stato abbastanza chiaro.
Grazie!
Risposte
Sarebbe utile fornire qualche dettaglio aggiuntivo sul progetto. Non mi è infatti chiaro che cosa tu intenda con i termini "activity", "fragment" e "custom view". Quale libreria/framework stai usando nel tuo progetto? Di che tipo di applicazione si tratta? Stai sviluppando una app per Android?
Sto sviluppando un'applicazione android per un progetto di ricerca dell'università. In questa applicazione viene visualizzato una schermata (immagine in formato .png) di un'interfaccia di un'altra applicazione per vari millisecondi, dopodiché questa sparisce per fare posto ad un EditText nel quale si inserirà la valutazione della precedente immagine. Questa sequenza continuerà per varie immagini (numero ancora da definire). Facendo delle ricerche online c'è anche la possibilità di utilizzare le librerie OpenGl.
Immagino che una singola Activity sia la soluzione migliore. Quello che viene visualizzato viene invece gestito da una "macchina a stati" che determina quello che viene visualizzato. Non credo che le OpenGL siano utili nel tuo caso.
Anche io avevo pensato di usare una singola attività, anche perchè se dovessi utilizzare 40 immagini dovrei creare almeno 40 attività.
Comunque, da dove posso partire per creare questa "macchina a stati"? Devo usare i fragment?
Comunque, da dove posso partire per creare questa "macchina a stati"? Devo usare i fragment?
La macchina a stati di cui parlavo è una entità astratta, nel senso che non corrisponde necessariamente ad una singola classe o funzione o altro della tua implementazione. Quello che intendo dire è che devi definire bene quali sono gli stati in cui si può trovare la tua applicazione e quali gli eventi che causano una transizione tra questi diversi stati. Avrai quindi per esempio uno stato corrispondente alla visualizzazione di una particolare immagine e uno stato per la parte in cui si richiede l'input da parte dell'utente. La transizione tra la visualizzazione di una immagine alla richiesta di un feedback dell'utente sarà legato probabilmente ad un qualche tipo di timer che viene fatto partire quando si entra nello stato di visualizzazione della immagine. L'altra transizione sarà invece probabilmente fatta partire alla pressione di un tasto o altro. Nel passaggio tra il feedback e l'immagine ci sarà la sostituzione dell'immagine corrente. Ma tutto questo discorso è solo teorico. In pratica potresti avere due fragments e passare da uno all'altro quando richiesto (quando si passa da uno stato al successivo).
Ho deciso implementare la sequenza di immagini con due fragment; nel primo è presente una ImageView mentre nel secondo è presente un EditText. Ecco il codice dell'activity che contiene i due fragment:
Però la sequenza che crea questo codice è: Cross -> Maschera -> Screenshot, ma dovrebbe essere Cross -> Screenshot -> Maschera.
Perchè?
public class Step1 extends Activity { ImageFragment myImageFragment; InputFragment myInputFragment; Drawable cross; ImageView myImageView; int i; int[] screenshots = { R.drawable.googleplaybooks2 }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.step1); initUI(); startThread(); } private void initUI(){ myImageFragment = (ImageFragment)getFragmentManager().findFragmentById(R.id.imageFragment); myInputFragment = (InputFragment)getFragmentManager().findFragmentById(R.id.inputFragment); myImageView = (ImageView)myImageFragment.getView().findViewById(R.id.screenshotImageView); myImageView.setImageResource(R.drawable.cross300x300);; myInputFragment.getView().setVisibility(View.GONE); } private void startThread(){ Runnable r1 = new Runnable() { public void run() { myImageView.setImageResource(R.drawable.noise); myImageView.getLayoutParams().width = LayoutParams.MATCH_PARENT; myImageView.getLayoutParams().height = LayoutParams.MATCH_PARENT; } }; Runnable r = new Runnable() { public void run() { myImageView.setImageResource(screenshots[i]); myImageView.getLayoutParams().width = LayoutParams.MATCH_PARENT; myImageView.getLayoutParams().height = LayoutParams.MATCH_PARENT; } }; myImageView.postDelayed(r, 500); myImageView.postDelayed(r1, 100); } @Override public void onBackPressed() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Attenzione") .setMessage("Sei sicuro/a di voler uscire dall'applicazione?\n" + "Confermando uscirai dall'applicazione e perderai \n" + "tutti i dati raccolti finora.") .setCancelable(false) .setNegativeButton("No",new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }) .setPositiveButton("Si", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } }); AlertDialog alert = builder.create(); alert.show(); } }
Però la sequenza che crea questo codice è: Cross -> Maschera -> Screenshot, ma dovrebbe essere Cross -> Screenshot -> Maschera.
Perchè?
Sono riuscito a risolvere cambiando il timer di ogni Runnable:
"r2" si occupa si far sparire l'ImageView e far comparire l'EditText.
Adesso però sorge un altro problema: questa sequenza (Cross, Screeshot e Maschera) deve continuare per un determinato numero di volte. Come posso fare ciò? In particolare come faccio a passare al passo successivo quando viene premuto il tasto "Invio" della tastiera?
myImageView.postDelayed(r, 250); myImageView.postDelayed(r1, 750); myImageView.postDelayed(r2, 1000);
"r2" si occupa si far sparire l'ImageView e far comparire l'EditText.
Adesso però sorge un altro problema: questa sequenza (Cross, Screeshot e Maschera) deve continuare per un determinato numero di volte. Come posso fare ciò? In particolare come faccio a passare al passo successivo quando viene premuto il tasto "Invio" della tastiera?
In realtà, l'idea che avevo in mente io era un po' diversa. In ogni momento solo una delle attività deve a mio parere essere attiva, le altre devono essere messe in pausa. Quando si passa da una attività all'altra si cambia l'attività che è in esecuzione e si mettono in pausa le altre.
Infatti, una sola attività è attiva; ciò che cambia in questo caso sono i fragment.
Ecco il codice dell'attività:
Ecco il codice dell'attività:
public class Step1Training extends Activity { ImageFragment myImageFragment; InputFragment myInputFragment; Drawable cross; ImageView myImageView; EditText myEditText; int i, length; String rating; Handler handler; boolean continueTask; int[] screenshots = { R.drawable.googleplaybooks2, R.drawable.aldiko1, R.drawable.chaton2, R.drawable.cinetrailer1, R.drawable.fanpage1 }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.step1); handler = new Handler(); i = 0; length = screenshots.length; // continueTask = false; initUI(); startThread(); } private void initUI(){ myImageFragment = (ImageFragment)getFragmentManager().findFragmentById(R.id.imageFragment); myInputFragment = (InputFragment)getFragmentManager().findFragmentById(R.id.inputFragment); myImageView = (ImageView)myImageFragment.getView().findViewById(R.id.screenshotImageView); myImageView.setImageResource(R.drawable.cross300x300); myEditText = (EditText)myInputFragment.getView().findViewById(R.id.ratingEditText); myEditText.setVisibility(View.GONE); } private void startThread(){ handler.postDelayed(new TaskScreenshot(i), 250); handler.postDelayed(new TaskNoise(), 750); handler.postDelayed(new TaskEditText(), 1000); myEditText.setOnKeyListener(new View.OnKeyListener(){ public boolean onKey(View v, int keyCode, KeyEvent event) { if((keyCode == KeyEvent.KEYCODE_ENTER)) { if(myEditText.getText().toString().equals("")){ Toast.makeText(getApplicationContext(), "Inserire un numero da 1 a 9", Toast.LENGTH_SHORT).show(); return false; } else if (Integer.parseInt(myEditText.getText().toString()) >= 1 && Integer.parseInt(myEditText.getText().toString()) <= 9){ return true; } } return false; } }); } @Override public void onBackPressed() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Attenzione") .setMessage("Sei sicuro/a di voler uscire dall'applicazione?\n" + "Confermando uscirai dall'applicazione e perderai \n" + "tutti i dati raccolti finora.") .setCancelable(false) .setNegativeButton("No",new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }) .setPositiveButton("Si", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } }); AlertDialog alert = builder.create(); alert.show(); } class TaskScreenshot implements Runnable{ int j; public TaskScreenshot(int _i){ this.j = _i; } @Override public void run() { myEditText.setVisibility(View.GONE); myImageFragment.getView().setVisibility(View.VISIBLE); myImageView.setImageResource(screenshots[j]); myImageView.getLayoutParams().width = LayoutParams.MATCH_PARENT; myImageView.getLayoutParams().height = LayoutParams.MATCH_PARENT; } } class TaskNoise implements Runnable{ @Override public void run() { myImageView.setImageResource(R.drawable.noise); myImageView.getLayoutParams().width = LayoutParams.MATCH_PARENT; myImageView.getLayoutParams().height = LayoutParams.MATCH_PARENT; } } class TaskEditText implements Runnable{ @Override public void run() { myEditText.setVisibility(View.VISIBLE); myImageFragment.getView().setVisibility(View.GONE); } } }
You are thus using the time argument of postDelayed as a timer for the transitions? You should probably add a button to exit from the TaskEditText and start the following iteration.
Ho provato a mettere un ciclo while e dei vari System.out:
Su telefono viene visualizzato l'ultimo screenshot dell'array e su logcat viene stampato questo:
private void startThread(){ while(i<length){ handler.postDelayed(new TaskScreenshot(i), 250); handler.postDelayed(new TaskNoise(), 750); handler.postDelayed(new TaskEditText(), 1000); myEditText.setOnKeyListener(new View.OnKeyListener(){ public boolean onKey(View v, int keyCode, KeyEvent event) { if((keyCode == KeyEvent.KEYCODE_ENTER)) { if(myEditText.getText().toString().equals("")){ Toast.makeText(getApplicationContext(), "Inserire un numero da 1 a 9", Toast.LENGTH_SHORT).show(); return false; } else if (Integer.parseInt(myEditText.getText().toString()) >= 1 && Integer.parseInt(myEditText.getText().toString()) <= 9){ return true; } } return false; } }); System.out.println(i); i++; } }
class TaskScreenshot implements Runnable{ int j; public TaskScreenshot(int _i){ this.j = _i; } @Override public void run() { System.out.println("Screenshot"); myEditText.setVisibility(View.GONE); myImageFragment.getView().setVisibility(View.VISIBLE); myImageView.setImageResource(screenshots[j]); myImageView.getLayoutParams().width = LayoutParams.MATCH_PARENT; myImageView.getLayoutParams().height = LayoutParams.MATCH_PARENT; } } class TaskNoise implements Runnable{ @Override public void run() { System.out.println("Noise"); myImageView.setImageResource(R.drawable.noise); myImageView.getLayoutParams().width = LayoutParams.MATCH_PARENT; myImageView.getLayoutParams().height = LayoutParams.MATCH_PARENT; } } class TaskEditText implements Runnable{ @Override public void run() { System.out.println("EditText"); myEditText.setVisibility(View.VISIBLE); myImageFragment.getView().setVisibility(View.GONE); } }
Su telefono viene visualizzato l'ultimo screenshot dell'array e su logcat viene stampato questo:
0 1 2 3 4 Screenshot Screenshot Screenshot Screenshot Screenshot Noise Noise Noise Noise Noise EditText EditText EditText EditText EditText
Prima di far partire il ciclo successivo devi aspettare che l'utente abbia validato il tuo edittext.. Questo non succede nel tuo ciclo.. Appena hai creato la prima sequenza di schermate, il ciclo viene subito eseguito creando le altre schermate (che verranno quindi visualizzate in pratica in contemporanea a quelle della sequenza precedente).
La validazione non dovrebbe avvenire con
myEditText.getText().toString()?
Non intendevo quello, la validazione dell'utente.. nel senso l'invio dei dati con la pressione del tasto. Finché l'utente non richiede la nuova immagine non dovresti far partire le nuove activity.
Sono riuscito più o meno a creare la sequenza che volevo:
Ma succede qualcosa di strano: la prima immagine viene visualizzata correttamente, viene premuto il tasto "Enter", compare la seconda immagine e successivamente la terza; viene premuto di nuovo il tasto "Enter" e vengono visualizzate la quarta e la quinta immagine in sequenza.
Non riesco a capire perchè avviene questa situazione.
private void startThread(final int i){ if(i < length){ handler.postDelayed(new TaskScreenshot(i), i*1500 + 250); handler.postDelayed(new TaskNoise(), i*1500 + 750); handler.postDelayed(new TaskEditText(), i*1500 + 1000); myEditText.setOnKeyListener(new View.OnKeyListener(){ public boolean onKey(View v, int keyCode, KeyEvent event) { if((keyCode == KeyEvent.KEYCODE_ENTER)) { if(myEditText.getText().toString().equals("")){ Toast.makeText(getApplicationContext(), "Inserire un numero da 1 a 9", Toast.LENGTH_SHORT).show(); return false; } else if (Integer.parseInt(myEditText.getText().toString()) >= 1 && Integer.parseInt(myEditText.getText().toString()) <= 9){ System.out.println(i); startThread(i+1); return true; } } return false; } }); } }
class TaskScreenshot implements Runnable{ int j; public TaskScreenshot(int _i){ this.j = _i; } @Override public void run() { System.out.println("Screenshot"); myEditText.setText(""); myEditText.setVisibility(View.GONE); myImageFragment.getView().setVisibility(View.VISIBLE); myImageView.setImageResource(screenshots[j]); myImageView.getLayoutParams().width = LayoutParams.MATCH_PARENT; myImageView.getLayoutParams().height = LayoutParams.MATCH_PARENT; } } class TaskNoise implements Runnable{ @Override public void run() { System.out.println("Noise"); myImageView.setImageResource(R.drawable.noise); myImageView.getLayoutParams().width = LayoutParams.MATCH_PARENT; myImageView.getLayoutParams().height = LayoutParams.MATCH_PARENT; } } class TaskEditText implements Runnable{ @Override public void run() { System.out.println("EditText"); myEditText.setVisibility(View.VISIBLE); myImageFragment.getView().setVisibility(View.GONE); } }
Ma succede qualcosa di strano: la prima immagine viene visualizzata correttamente, viene premuto il tasto "Enter", compare la seconda immagine e successivamente la terza; viene premuto di nuovo il tasto "Enter" e vengono visualizzate la quarta e la quinta immagine in sequenza.
Non riesco a capire perchè avviene questa situazione.
Ho letto al volo la tua domanda, e posso dirti come potresti fare. Un'activity per ogni immagine sarebbe uno spreco, e scorretto dal punto di ciò che dovrebbe rappresentare un'activity all'interno di un'applicazione.
La cosa piu corretta è utilizzare un'unica activity, contenente un fragment. Nel fragment inserisci l'immagine corrente che vuoi visualizzare, e successivamente mostri i widget successivi che servono per valutare l'immagine. Una volta fatto ciò, ti salvi il riferimento all'immagine con relative valutazioni, e passi a quella successiva (inserendola all'interno dello stesso fragment di prima).
La cosa piu corretta è utilizzare un'unica activity, contenente un fragment. Nel fragment inserisci l'immagine corrente che vuoi visualizzare, e successivamente mostri i widget successivi che servono per valutare l'immagine. Una volta fatto ciò, ti salvi il riferimento all'immagine con relative valutazioni, e passi a quella successiva (inserendola all'interno dello stesso fragment di prima).
"DamianFox":
Anche io avevo pensato di usare una singola attività, anche perchè se dovessi utilizzare 40 immagini dovrei creare almeno 40 attività.
Comunque, da dove posso partire per creare questa "macchina a stati"? Devo usare i fragment?
Fragment sono per gestione UI su tablet

"Luc@s":
[quote="DamianFox"]Anche io avevo pensato di usare una singola attività, anche perchè se dovessi utilizzare 40 immagini dovrei creare almeno 40 attività.
Comunque, da dove posso partire per creare questa "macchina a stati"? Devo usare i fragment?
Fragment sono per gestione UI su tablet

Sono nati per quello scopo, ma sono comunque molto utili ed utilizzati anche per le applicazioni per device "non tablet"

Esempio pratico di questo utilizzo dei fragment, sono le swipe views, ovvero il sistema utilizzato nel play store nella sezione giochi, che ti permette di navigare tra "schermate" vicine tramite un semplice swipe a destra o a sinistra. In questo, caso ogni schermata è un fragment che vive all'interno di una singola activity
Grazie per il chiarimento e l'esempuo
