JavascriptProva

venerdì 23 dicembre 2016

VIew Pager e fragments con adapter

Creo un fragment.
public class Frammento extends Fragment {

    OnFragmentInteractionListener mListener;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View v=inflater.inflate(R.layout.frammento,container,false);
        return v;
    }

    @Override
    public void onAttach(Context context){
        super.onAttach(context);
        if(context instanceof com.antonello.frammenti.OnFragmentInteractionListener){
            mListener=(OnFragmentInteractionListener)context;
        }
    }

    public interface OnFragmentInteractionListener{
        public void onFragmentInteraction();
    }

}
Questo è lo scheletro essenziale per creare un fragment.
Ora voglio aggiungervi un Button programmaticamente.
public class Frammento extends Fragment {

    Button button;
    LinearLayout mainLayout;
    OnFragmentInteractionListener mListener;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View v=inflater.inflate(R.layout.frammento,container,false);
        button=new Button(v.getContext());
        mainLayout=(LinearLayout)v.findViewById(R.id.mainLayout);
        mainLayout.addView(button);
        return v;
    }

    @Override
    public void onAttach(Context context){
        super.onAttach(context);
        if(context instanceof com.antonello.frammenti.OnFragmentInteractionListener){
            mListener=(OnFragmentInteractionListener)context;
        }
    }

    public interface OnFragmentInteractionListener{
        public void onFragmentInteraction();
    }

}
Ecco, ho aggiunto un button senza alcun listener.
Ora voglio vedere se "funziona".

Devo caricare il fragment nel Layout principale.

Provo con questo codice, se lo ricordo abbastanza bene:
public class MainActivity extends AppCompatActivity implements FragmentBarra.OnFragmentInteractionListener{

    Helper helper;
    Fragment myFrag;
    FragmentManager fragmentManager=getSupportFragmentManager();
    FragmentTransaction transaction;
    


    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myFrag=new Frammento();
        transaction=fragmentManager.beginTransaction();
        transaction.add(R.id.barra,myFrag,"myfrag");
        transaction.commit();






    }

    @Override
    public void onFragmentInteraction() {

    }




}
Il button c'è.
Ora dovrei collegare il ViewPager con un adapter.
Nella fattispecie si usa il FragmentPagerAdapter, che devo estendere.
Ci provo...

    public class Adapter extends FragmentPagerAdapter{

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

        @Override
        public Fragment getItem(int position) {
            return null;
        }

        @Override
        public int getCount() {
            return 0;
        }
    }
Già scrivendo l'estensione della classe Android Studio richiede l'implementazione dei metodi e la creazione del costruttore in automatico, per cui la cosa non presenta molti problemi.
Costruisco direttamente una nuova istanza del Fragment da inserire nell'altro LinearLayout, passandoci il numero di posizione attribuito dall'adapter:
    public class Adapter extends FragmentPagerAdapter{

        public Adapter(FragmentManager fm) {

            super(fm);
        }

        @Override
        public Fragment getItem(int position) {

            frag3=new Frammento3();
            Bundle args=new Bundle();
            args.putInt("num",position);
            frag3.setArguments(args);
            return frag3;
        }

        @Override
        public int getCount() {

            return 2;
        }
    }
Nel codice del fragment ho una variabile int che accoglie nel metodo onCreate il numero attribuito come parametro, ossia position.
public class Frammento3 extends Fragment {

    OnFragmentInteractionListener mListener;

    int numero;

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        numero=getArguments().getInt("num");
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View v=inflater.inflate(R.layout.frammento3,container,false);
        TextView textView=(TextView)v.findViewById(R.id.textView2);
        textView.setText(numero+"");
        return v;
    }

    @Override
    public void onAttach(Context context){
        super.onAttach(context);
        if(context instanceof OnFragmentInteractionListener){
            mListener=(OnFragmentInteractionListener)context;
        }
    }
}
Senza fare quella costruzione con newInstance, della quale non ho, sinceramente, capito lo scopo.

mercoledì 21 dicembre 2016

Codice per il viewPager.

Mi salvo un codice e torno ad esercitarmi su di esso...
public class MainActivity extends AppCompatActivity implements FragmentBarra.OnFragmentInteractionListener{

    Helper helper;
    Frammento myFrag;
    FragmentBarra fragmentBarra;
    PagerAdapter adapter;
    ViewPager viewPager;
    ArrayList lista;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        lista=new ArrayList();
        lista.add("Gongolo");
        lista.add("Mammolo");
        lista.add("Eolo");
        lista.add("Pisolo");
        lista.add("Brontolo");
        lista.add("Dotto");
        lista.add("Cucciolo");
        helper=new Helper(this);

        viewPager=(ViewPager)findViewById(R.id.vpdisplay);
        adapter=new ScreenSlidePagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(adapter);

        fragmentBarra = new FragmentBarra();
        FragmentManager fragmentManager=getSupportFragmentManager();
        FragmentTransaction transaction=fragmentManager.beginTransaction();
        transaction.add(R.id.barra,fragmentBarra);

        /*helper.save("Pinco");
        helper.save("Lappo");
        helper.save("Bobbo");*/





    }

    @Override
    public void onFragmentInteraction() {
        myFrag.getView().setBackgroundColor(Color.GREEN);
    }

    public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter{

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

        @Override
        public Fragment getItem(int position) {

            return MioFrammento.newInstance(position,lista);
        }

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

    public static class MioFrammento extends Fragment{
        int numero;
        Serializable lista;
        public static MioFrammento newInstance(int num, ArrayList lista){
            MioFrammento f=new MioFrammento();
           0
            Bundle args=new Bundle();
            args.putInt("num",num);
            args.putSerializable("lista",lista);
            f.setArguments(args);
            return f;
        }

        @Override
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            numero= getArguments().getInt("num");
            lista=getArguments().getSerializable("lista");
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState){
            View v=inflater.inflate(R.layout.mio_frammento,container,false);
            TextView textView=(TextView)v.findViewById(R.id.textView);
            textView.setText(((ArrayList)lista).get(numero));
            return v;
        }
    }


}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="#AAFFFF"
    android:orientation="horizontal"
    android:id="@+id/container"
    android:layout_height="match_parent"
    android:layout_width="match_parent">

    <LinearLayout
        android:id="@+id/barra"
        android:orientation="horizontal"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/vpdisplay"
        android:layout_height="match_parent"
        android:layout_width="0dp"
        android:layout_weight="4">

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

</LinearLayout> 

lunedì 19 dicembre 2016

ViewPager e relativo codice

Con il ViewPager bisogna sempre creare l'adapter.
Sembra che PagerAdapter sia un antenato di ScreenSlidePagerAdapter.

Il codice è infatti qualcosa del tipo
PagerAdapter pagerAdapter=new ScreenSlidePagerAdapter(getSupportFragmentManager())
Ossia il costruttore di ScreenSlidePagerAdapter ha bisogno di un parametro di tipo FragmentManager o derivato.
Una volta istanziato il PagerAdapter, e istanziato il ViewPager, si azzecca l'adapter al ViewPager, ma come si aggiungono pagine al PagerAdapter?

In realtà ho commesso un errore: ScreenSlidePagerAdapter è una classe creata ex novo, che estende FragmentStatePagerAdapter.
Vediamo il codice per la creazione di ScreenSlidePagerAdapter che estende FragmentStatePagerAdapter...
Ecco, ha due proprietà: una accetta come parametro un int posizione e restituisce un Fragment, l'altra imposta il numero di elementi.
    private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
        public ScreenSlidePagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            switch(position){
                case 0:
                    return new Frammento();

                case 1:
                    return new Frammento2();

                case 2:
                    return new Frammento3();

                default:break;

            }
            return null;
        }

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

Lettura di un database tramite i fragments

Per il momento creo un database o verifico se un database sia già stato creato.
Un database c'è, ed è presente su storage anziché sulla cartella inaccessibile. Credo che questa sia una soluzione più conveniente, anche se espone il database a un maggior rischio, per la possibilità di trasferirlo facilmente mediante un semplice meccanismo di copia-incolla anche su dispositivi non rootati.

Ripristino il codice per aggiungere voci al database.
public class MainActivity extends AppCompatActivity implements Frammento.OnFragmentInteractionListener{

    Helper helper;

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

        helper=new Helper(this);
        
        helper.save("Mario");
        helper.save("Pippo");
        helper.save("Mimmo");

,,,,,
Ora mi occupo di caricare un fragment.
Per prima cosa ho creato il codice del fragment, con tanto di creazione dell'interfaccia per inviare messaggi all'activity:
public class Frammento3 extends Fragment {

    OnFragmentInteractionListener mListener;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View v=inflater.inflate(R.layout.frammento3,container,false);
        return v;
    }

    @Override
    public void onAttach(Context context){
        super.onAttach(context);
        if(context instanceof OnFragmentInteractionListener){
            mListener=(OnFragmentInteractionListener)context;
        }
    }
}
Quindi ho creato il codice dell'activity principale:
public class MainActivity extends AppCompatActivity implements Frammento.OnFragmentInteractionListener{

    Helper helper;
    Frammento myFrag;
    FragmentManager fragmentManager=getSupportFragmentManager();
    FragmentTransaction transaction=fragmentManager.beginTransaction();

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

        helper=new Helper(this);

        /*helper.save("Mario");
        helper.save("Pippo");
        helper.save("Mimmo");*/

        myFrag=new Frammento();
        transaction.add(R.id.display,myFrag,"frammento");
        transaction.commit();



    }

    @Override
    public void onFragmentInteraction() {

    }
}
(ho oscurato i comandi che avevo usato in precedenza per la scrittura del database).

Ottengo il caricamento del frammento.

Ora devo fare in modo che il fragment legga il database disponendo i dati che vi trova in qualche view...

Fatto.
Viene creata una TextView per ogni record appartenente al recordset.
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View v=(View)inflater.inflate(R.layout.frammento,container,false);
        LinearLayout layout=(LinearLayout)v.findViewById(R.id.frammento);
        helper=new Helper(v.getContext());
        Cursor c=helper.query();
        do{
            testo=new TextView(v.getContext());
            testo.setText(c.getString(c.getColumnIndex("nome")));
            layout.addView(testo);
        }while(c.moveToNext());
        return v;
    }
E funziona.

sabato 17 dicembre 2016

Tornando a Giobe...

Ricominciamo dalla firma di Zbikovsky...
C:\Arch-Lab\LAVORO~1>debug es1.xxx
-d
17BC:0100  4D 5A 16 01 02 00 00 00-20 00 00 00 FF FF 00 00   MZ...... .......
17BC:0110  00 00 00 00 00 01 00 00-1E 00 00 00 01 00 00 00   ................
17BC:0120  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
17BC:0130  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
17BC:0140  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
17BC:0150  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
17BC:0160  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
17BC:0170  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
Andando indietro vado al PSP:
-d 17bc:0000
17BC:0000  CD 20 FF 9F 00 9A EE FE-1D F0 4F 03 20 12 8A 03   . ........O. ...
17BC:0010  20 12 17 03 20 12 2C 07-01 01 01 00 02 FF FF FF    ... .,.........
17BC:0020  FF FF FF FF FF FF FF FF-FF FF FF FF A0 11 4E 01   ..............N.
17BC:0030  E0 16 14 00 18 00 BC 17-FF FF FF FF 00 00 00 00   ................
17BC:0040  05 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
17BC:0050  CD 21 CB 00 00 00 00 00-00 00 00 00 00 20 20 20   .!...........
17BC:0060  20 20 20 20 20 20 20 20-00 00 00 00 00 20 20 20           .....
17BC:0070  20 20 20 20 20 20 20 20-00 00 00 00 00 00 00 00           ........
-d
17BC:0080  00 0D 65 73 31 2E 78 78-78 0D 65 78 65 0D 20 49   ..es1.xxx.exe. I
17BC:0090  35 20 44 31 20 50 33 33-30 20 54 33 0D 74 2E 65   5 D1 P330 T3.t.e
17BC:00A0  78 65 0D 00 00 00 00 00-00 00 00 00 00 00 00 00   xe..............
17BC:00B0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
17BC:00C0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
17BC:00D0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
17BC:00E0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
17BC:00F0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
-

mercoledì 14 dicembre 2016

Gestione dei frammenti su un'activity, con codice per l'espansione di un fragment.

Non ho lasciato nessun promemoria scritto di come caricare più fragments in un'activity scambiandone uno su comando dell'altro.
Ecco:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="#AAFFFF"
    android:orientation="horizontal"
    android:id="@+id/container"
    android:layout_height="match_parent"
    android:layout_width="match_parent">

    <LinearLayout
        android:id="@+id/barra"
        android:orientation="horizontal"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2"/>

    <LinearLayout
        android:id="@+id/display"
        android:orientation="horizontal"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="4"/>


</LinearLayout> 
public class MainActivity extends AppCompatActivity implements Frammento.OnFragmentInteractionListener{

    Frammento myFrag;
    FragmentManager fragmentManager;
    FragmentTransaction transaction;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myFrag=new Frammento();
        fragmentManager=getSupportFragmentManager();
        transaction=fragmentManager.beginTransaction();
        transaction.add(R.id.barra,myFrag,"barra");
        transaction.commit();

        Frammento2 frag2=new Frammento2();
        transaction=fragmentManager.beginTransaction();
        transaction.add(R.id.display,frag2,"display");
        transaction.commit();

    }

    public void onFragmentInteraction(){
        Frammento2 frammento2=(Frammento2)fragmentManager.findFragmentByTag("display");
        Button bottone=new Button(getApplicationContext());
        LinearLayout mainLayout=(LinearLayout)frammento2.getView().findViewById(R.id.frammento2);
        mainLayout.addView(bottone);
    }

}




Fragments:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:background="#FFFFFF"
    android:id="@+id/frammento">


    <Button
        android:text="Button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/button2" />
</ScrollView> 
public class Frammento extends Fragment {

    OnFragmentInteractionListener mListener;
    Button button;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        ViewGroup rootView = (ViewGroup) inflater.inflate(
                R.layout.frammento, container, false);
        button=(Button)rootView.findViewById(R.id.button2);
        button.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                mListener.onFragmentInteraction();
            }
        });
        return rootView;
    }

    @Override
    public void onAttach(Context context){
        super.onAttach(context);
        if(context instanceof OnFragmentInteractionListener){
            mListener=(OnFragmentInteractionListener)context;
        }
    }

    public interface OnFragmentInteractionListener{
        public void onFragmentInteraction();
    }
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="4"
    android:id="@+id/frammento2"
    android:background="#FAA">

    <TextView
        android:text="SECONDO FRAMMENTO"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView" />
</LinearLayout> 
public class Frammento2 extends Fragment {

    OnFragmentInteractionListener mListener;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View v=inflater.inflate(R.layout.frammento2,container,false);
        return v;
    }

    @Override
    public void onAttach(Context context){
        super.onAttach(context);
        if(context instanceof OnFragmentInteractionListener){
            mListener=(OnFragmentInteractionListener)context;
        }
        System.out.println("FRAMMENTO 2 ONATTACH");

    }


}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:background="#AFA"
    android:layout_weight="4">



    <TextView
        android:text="TERZO FRAMMENTO"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView2" />

    <Button
        android:text="Button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/button4" />
</LinearLayout> 
public class Frammento3 extends Fragment {

    OnFragmentInteractionListener mListener;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View v=inflater.inflate(R.layout.frammento3,container,false);
        return v;
    }

    @Override
    public void onAttach(Context context){
        super.onAttach(context);
        if(context instanceof OnFragmentInteractionListener){
            mListener=(OnFragmentInteractionListener)context;
        }
    }
}

Spinner (ripasso)

Ho ripassato la creazione di uno Spinner. Ed ecco il codice:
        <Spinner
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:id="@+id/spinner"
            android:background="#FFFFFF"
            android:layout_weight="1" />
public class MainActivity extends AppCompatActivity {

    ArrayAdapter adapter;
    Spinner spinner;
    List esami;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        esami=new ArrayList();
        esami.add("RBC");
        esami.add("Hb");
        esami.add("MCV");
        adapter=new ArrayAdapter(this,android.R.layout.simple_spinner_dropdown_item,esami);
        spinner=(Spinner)findViewById(R.id.spinner);
        spinner.setAdapter(adapter);


    }

}

Sliding Up Panel

Mi salvo il codice per lo Sliding Panel.
Questo è il link
<?xml version="1.0" encoding="utf-8"?>
<com.sothree.slidinguppanel.SlidingUpPanelLayout
    xmlns:sothree="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/sliding_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="top"
    sothree:umanoPanelHeight="20dp"
    sothree:umanoShadowHeight="10dp">
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:background="#FFAAAA"
        android:layout_height="match_parent"
        android:layout_width="match_parent">

        <TextView
            android:text="Base"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/textView4"
            android:layout_weight="1" />


    </LinearLayout>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="#AAFFFF"
    android:layout_height="match_parent"
    android:layout_width="match_parent">
    <TextView
        android:text="Pannello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textView5"
        android:layout_weight="1" />




</LinearLayout>

</com.sothree.slidinguppanel.SlidingUpPanelLayout> 

lunedì 12 dicembre 2016

Codice per slide con barra laterale fissa

Mi salvo il codice:
public class MainActivity extends AppCompatActivity {

    Helper helper;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        helper=new Helper(this);

        /*helper.save("Mario");
        helper.save("Pasquale");*/

        helper.saveData(1,"Primo");

    }

    class Helper extends SQLiteOpenHelper{

        public Helper(Context context) {
            super(context, "mioDatabase.db", null, 1);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("create table tblNomi(_id integer primary key, nome text)");
            db.execSQL("create table tblDati(_id integer primary key, extKey integer, dato text)");
        }

        public void save(String nome){
            SQLiteDatabase db=this.getWritableDatabase();
            ContentValues values=new ContentValues();
            values.put("nome",nome);
            db.insert("tblNomi",null,values);

        }

        public void saveData(int id, String dato){
            SQLiteDatabase db=this.getWritableDatabase();
            ContentValues values=new ContentValues();
            values.put("extKey",id);
            values.put("dato",dato);
            db.insert("tblDati",null,values);
        }

        public Cursor query(int id){
            SQLiteDatabase db=this.getWritableDatabase();
            Cursor c=db.rawQuery("select * from tblNomi where _id="+id, null);
            c.moveToFirst();
            return c;
        }






        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        }
    }

}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_height="match_parent"
    android:layout_width="match_parent">

    <ImageView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        app:srcCompat="@mipmap/ic_launcher"
        android:id="@+id/imageView"
        android:layout_weight="1" />

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="5"/>


</LinearLayout> 

domenica 11 dicembre 2016

Slider per schermate

C'è un Adapter che dovrebbe funzionare come l'adapter per le ListView.
In questo codice, sarebbe questo:
    private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {

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

        @Override
        public Fragment getItem(int position) {
            return new Frammento();
        }

        @Override
        public int getCount() {
            return NUM_PAGES;
        }
    }
Il suo costruttore è questo:
        public ScreenSlidePagerAdapter(FragmentManager fm) {
            super(fm);
        }
e accetta come parametro FragmentManager.

Come un ArrayAdapter viene "abbinato" a una ListView, così questo Adapter andrebbe "abbinato" a un controllo che fa scorrere le schermate...

Ecco: istanzio un Adapter:
 mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
e quindi lo "azzecco" al ViewPager:
mPager.setAdapter(mPagerAdapter);
Ecco la sequenza completa: prendo il ViewPager dal file XML, istanzio un'istanza dell'Adapter e poi la azzecco al ViewPager:
        mPager = (ViewPager) findViewById(R.id.pager);
        mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
        mPager.setAdapter(mPagerAdapter);
Ecco, il codice completo è questo, e funziona:
public class MainActivity extends AppCompatActivity {

    private static final int NUM_PAGES = 3;


    private ViewPager mPager;


    private PagerAdapter mPagerAdapter;

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

 
        mPager = (ViewPager) findViewById(R.id.pager);
        mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
        mPager.setAdapter(mPagerAdapter);
    }


    private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
        public ScreenSlidePagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            switch(position){
                case 0:
                    return new Frammento();

                case 1:
                    return new Frammento2();

                case 2:
                    return new Frammento3();

                default:break;

            }
            return null;
        }

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

mercoledì 7 dicembre 2016

Messaggio dal fragment alla main activity

Esercizio: messaggio del fragment verso l'Activity:

metto un Button nel Frammento 1:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#AADDFF">

    <Button
        android:text="Button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:id="@+id/button" />
</RelativeLayout> 
Nel codice Java del Frammento devo creare un'interfaccia:
    public interface OnFragmentEventListener{
        public void evento();
    }
Creo una variabile del tipo di questa interfaccia:
public class Frammento extends Fragment {

    OnFragmentEventListener mCallback;

......
Nell'evento onAttach identifico l'Activity cui il fragment viene "attaccato" come un'istanza dell'interfaccia:
    @Override
    public void onAttach(Context context){
        super.onAttach(context);
        if(context instanceof AppCompatActivity){
            mCallback=(OnFragmentEventListener)context;
        }
    }
E nell'evento onCreateView attribuisco al button il listener e dico di far eseguire nella variabile interfaccia il metodo che questa implementa:
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View v=inflater.inflate(R.layout.frammento,container,false);
        button=(Button)v.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                mCallback.evento();
            }
        });
        return v;
    }
E funziona: quando io clicco il button presente sul Frammento 1 viene eseguito il metodo come implementato dall'Activity Main:
(codice della Main Activity:)
public class MainActivity extends AppCompatActivity implements Frammento.OnFragmentEventListener{

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

    public void evento(){
        System.out.println("EVENTO RICEVUTO");
    }


}

Creazione di due fragments mediante xml.

Esercizio di creazione di due fragments messi in un'Activity per mezzo del codice xml.

Creo i fragments: una classe Java e un file XML.

Frammento.java:
public class Frammento extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View v=inflater.inflate(R.layout.frammento,container,false);
        return v;
    }
}


frammento.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#AADDFF">

    <Button
        android:text="Button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:id="@+id/button" />
</RelativeLayout> 



Frammento2.java:
public class Frammento2 extends Fragment{

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View v=inflater.inflate(R.layout.frammento2,container, false);
        return v;
    }
}


frammento2.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFAA">

    <TextView
        android:text="Questo è il frammento 2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView" />
</LinearLayout> 



MainActivity.java:
public class MainActivity extends AppCompatActivity{

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


}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent">

    <fragment android:name="com.antonello.laboratorionuovo2.Frammento"
        android:layout_height="match_parent"
        android:layout_width="0dp"
        android:id="@+id/frammento"
        android:layout_weight="1"/>

    <fragment android:name="com.antonello.laboratorionuovo2.Frammento2"
        android:layout_height="match_parent"
        android:layout_width="0dp"
        android:id="@+id/frammento2"
        android:layout_weight="1"/>

</LinearLayout> 


E così funziona perfettamente.

lunedì 5 dicembre 2016

DatePicker

Come si usa un datePicker?
A quanto pare la chiave è lo showDialog.
public class MainActivity extends AppCompatActivity {


    Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        button.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                showDialog(0);
            }
        });
    }
}
Fin qui va bene...

Ora c'è la funzione "di quando si crea una finestra di dialogo", ossia onCreateDialog, di classe Dialog e con un parametro int.

    @Override
    public Dialog onCreateDialog(int id){
        return new DatePickerDialog(this,.........)
    }
E ora vediamo con calma i parametri del costruttore...

Il primo, this, è il context, ordinaria amministrazione;
Il secondo è un listener, OnDateSetListener, che sarebbe l'ascoltatore di quando viene settata la data.
Poi ci sono tre parametri di tipo int che dobbiamo fornire noi.

Ci provo.
Ecco la prima funzione:
    @Override
    public Dialog onCreateDialog(int id){
        return new DatePickerDialog(this, onDateSetListener,anno, mese, giorno);
    }
Ed ecco il listener (secondo parametro della funzione):
    DatePickerDialog.OnDateSetListener onDateSetListener= new DatePickerDialog.OnDateSetListener() {
        @Override
        public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
            anno=year;
            mese=month;
            giorno=dayOfMonth;
        }
    };

domenica 4 dicembre 2016

Codice esercizio gestione suonerie

Mi salvo il codice sulla gestione delle suonerie...
public class MainActivity extends AppCompatActivity {

    Uri ringtoneUri;
    Button button;
    SharedPreferences SP;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button=(Button)findViewById(R.id.button);
        SP=getApplicationContext().getSharedPreferences("settings",MODE_PRIVATE);




        button.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                String strSuoneria=SP.getString("suoneria","");
                if(TextUtils.isEmpty(strSuoneria)){
                    ringtoneUri=null;

                }
                else{
                    ringtoneUri=Uri.parse(strSuoneria);
                }

                System.out.println("Stringa pescata da SharedPreferences: "+strSuoneria);
                if(ringtoneUri!=null)System.out.println("ringtoneUri selezionata: "+ringtoneUri.toString());



                Intent intent=new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
                intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE,RingtoneManager.TYPE_NOTIFICATION);

                intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI,ringtoneUri);
                startActivityForResult(intent,0);
            }
        });


    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data){
        if(resultCode==RESULT_OK) {
            Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
            String s;
            if(uri==null){
                s="";
            }
            else{
                s=uri.toString();
            }
            System.out.println("Stringa memorizzata in SP: "+s);
            SharedPreferences.Editor editor = SP.edit();
            editor.putString("suoneria", s);
            editor.commit();
        }
    }
}

in modo da usare il programma per fare dell'altro.

Impostazione delle suonerie

Raccogliamo le idee...

Quando viene scelta una suoneria, viene scelto un URI che viene attribuito alla variabile uri, la quale viene quindi memorizzata in SP.
Se viene fatta la scelta "Nessuna suoneria", non c'è nessun URI, per cui la variabile uri è nulla, e il tentativo di salvarla in SP genera un errore.

Ho ovviato così, facendo in modo che se URI è assente e uri è quindi nulla venga salvata in SP una stringa vuota.
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data){
        if(resultCode==RESULT_OK) {
            Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
            String s;
            if(uri==null){
                s="";
            }
            else{
                s=uri.toString();
            }
            System.out.println("Stringa memorizzata in SP: "+s);
            SharedPreferences.Editor editor = SP.edit();
            editor.putString("suoneria", s);
            editor.commit();
        }
    }
Ora devo andare a vedere l'altro versante, ossia il richiamo della suoneria da SP.
Se trovo una stringa non vuota, prendo questa come nome della suoneria, creando il ringtoneUri.
Se trovo una stringa vuota, invece, non devo mettere in azione la suoneria di default, bensì impostare ringtoneUri a null.
                String strSuoneria=SP.getString("suoneria","");
                if(TextUtils.isEmpty(strSuoneria)){
                    ringtoneUri=null;

                }
                else{
                    ringtoneUri=Uri.parse(strSuoneria);
                }

                System.out.println("Stringa pescata da SharedPreferences: "+strSuoneria);
                if(ringtoneUri!=null)System.out.println("ringtoneUri selezionata: "+ringtoneUri.toString());
Così dovrebbe funzionare, con suoneria assente e selezione di "Nessuna suoneria", in caso di impostazione di "nessuna suoneria".

Il codice che recupera ringtoneUri e quello che chiama l'activity della scelta suonerie devono essere messi insieme, perché il primo si deve ripetere ogni volta, mentre se viene lasciato in onCreate si esegue solo all'apertura dell'Activity.

Salvataggio grezzo di un codice sulle date

public class MainActivity extends AppCompatActivity {

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


        Date nascita=new Date(1961,8,5);
        Date scuola=new Date(1966,8,5);


        int differenza=scuola.getYear()-nascita.getYear();
        if(nascita.getMonth()>scuola.getMonth() ||
                (nascita.getMonth()==scuola.getMonth() && nascita.getDate()>scuola.getDate())){
            differenza--;
        }
        System.out.println(differenza);






    }

    Date dateFromString(String stringa){
        Date date=null;
        stringa=stringa.replace('/',' ');
        stringa=stringa.replace('-',' ');



        int posizione=stringa.length()-stringa.lastIndexOf(" ");

        if(posizione!=5 && posizione!=3)return null;

        if(posizione==5){
            sdf=new SimpleDateFormat("dd M yyyy");
        }
        if(posizione==3){
            sdf=new SimpleDateFormat("dd M yy");
        }

        try {
            sdf.setLenient(false);
            date = sdf.parse(stringa);

        } catch (ParseException e) {
            return null;
        }
        return date;
    }
}

sabato 3 dicembre 2016

Esercizi di calcoli con le date

Stando a quello che ho capito, una data può essere scritta sotto forma di Stringa o sotto forma di Date.
Date può prendere come parametro un numero Long che rappresenta le date a partire dall'Epoch.
L'intermediario fra Date e Stringa è SimpleDateFormat, che usa il metodo parse() per andare da Stringa a Date, e il metodo format() per andare da Date a Stringa.

Facciamo un po' di esercizi in tal senso...
Converto una Stringa in un Date e poi faccio l'inverso.
        String stringa=("5/9/1961");
        Date date=null;

        DateFormat sdf=new SimpleDateFormat("dd/MM/yyyy");

        try {
            date=sdf.parse(stringa);
            System.out.println(date.toString());
        } catch (ParseException e) {
            e.printStackTrace();
        }

        String nuovaStringa=null;

        nuovaStringa=sdf.format(date);

        System.out.println(nuovaStringa);
12-03 10:17:10.433 12831-12831/? I/System.out: Tue Sep 05 00:00:00 GMT+00:00 1961
12-03 10:17:10.433 12831-12831/? I/System.out: 05/09/1961


Quello che ho capito è che la reale misura del tempo è in un tipo Long, che rappresenta il numero di millisecondi dall'Epoch.
Come si estrapolano i millisecondi dall'entità Date?
Ho aggiunto una riga:
        String stringa=("5/9/1961");
        Date date=null;

        DateFormat sdf=new SimpleDateFormat("dd/MM/yyyy");

        try {
            date=sdf.parse(stringa);
            System.out.println(date.toString());
        } catch (ParseException e) {
            e.printStackTrace();
        }

        String nuovaStringa=null;

        nuovaStringa=sdf.format(date);

        System.out.println(nuovaStringa);

        System.out.println(date.getTime());
12-03 11:25:32.368 13022-13022/? I/System.out: Tue Sep 05 00:00:00 GMT+00:00 1961
12-03 11:25:32.368 13022-13022/? I/System.out: 05/09/1961
12-03 11:25:32.368 13022-13022/? I/System.out: -262656000000
Mi sembra perfetto.
Ora, posso ottenere giorno mese e anno separatamente da Date?
Ho provato
        String stringa=("5/9/1961");
        Date date=null;

        DateFormat sdf=new SimpleDateFormat("dd/MM/yyyy");

        try {
            date=sdf.parse(stringa);
            System.out.println(date.toString());
        } catch (ParseException e) {
            e.printStackTrace();
        }


        System.out.println("weekday "+date.getDate());
        System.out.println("day "+date.getDay());
        System.out.println("month "+date.getMonth());
        System.out.println("year "+date.getYear());
ottenendo
12-03 14:26:46.771 13504-13504/? I/System.out: Tue Sep 05 00:00:00 GMT+00:00 1961
12-03 14:26:46.771 13504-13504/? I/System.out: weekday 5
12-03 14:26:46.771 13504-13504/? I/System.out: day 2
12-03 14:26:46.794 13504-13504/? I/System.out: month 8
12-03 14:26:46.794 13504-13504/? I/System.out: year 61
e sembra che proceda tutto bene. Il mese è espresso partendo da zero, però...
SimpleDateFormat serve solo per la conversione da e a stringa.
L'unico problema è che questi metodi sono deprecati, non so perché, e come oggetto Date si consiglia adesso di usare Calendar.
Saranno deprecati ma funzionano.
Dunque posso fare tutto con l'oggetto di classe Date...

Bene. Cerco di fare un'operazione con la sottrazione di due date.
Per fare le operazioni devo ridurre tutto a millisecondi.
Posso ottenere il tempo in millisecondi mediante la funzione Date.getTime().
Ci provo...

Sottraggo 1 ottobre 1966 da 5 settembre 1961.
Un momento!
Come ho estratto giorno, mese e anno da un oggetto di classe Date, devo essere in grado di settare questi valori.
Ricordo dei metodi precisi, anch'essi deprecati.
Si può fare sicuramente da costruttore:
        Date date1=new Date(1966,10,1);

        Date date2=new Date(1961,9,5);

        System.out.println(date1.getMonth());

        System.out.println(date2.getMonth());
12-03 14:43:46.207 13670-13670/? I/System.out: 10
12-03 14:43:46.207 13670-13670/? I/System.out: 9
Devo regolare i conti con il mese.
Per capire qualcosa, faccio una prova: immetto come mese nel costruttore di Date il numero 12, che, se il conto dei mesi inizia da zero, dovrebbe darmi un messaggio di errore in quanto il mese di Dicembre dovrebbe essere rappresentato con 11, e 12 eccederebbe il numero dei mesi.
        Date date1=new Date(1966,12,1);

        Date date2=new Date(1961,9,5);

        System.out.println(date1.getMonth());


        System.out.println(date2.getMonth());
Ed ecco:
12-03 14:50:40.126 13911-13911/? I/System.out: 0
12-03 14:50:40.126 13911-13911/? I/System.out: 9
Ottengo 0, che dovrebbe essere Gennaio...
Mi viene un dubbio: non mi avrà aggiunto un anno in più?
Prova:
        Date date1=new Date(1966,12,1);

        Date date2=new Date(1961,9,5);

        System.out.println(date1.getMonth());
        System.out.println(date1.getYear());

        System.out.println(date2.getMonth());
12-03 14:52:45.347 13995-13995/? I/System.out: 0
12-03 14:52:45.347 13995-13995/? I/System.out: 1967
12-03 14:52:45.347 13995-13995/? I/System.out: 9
Infatti... mi ha aggiunto un anno in più!
Oltre che da costruttore, vediamo se si può impostare i valori di giorno, mese e anno in un oggetto di classe Date.

        Date date1=new Date();

        date1.setDate(5);
        date1.setMonth(8);
        date1.setYear(1961);

        System.out.println(date1);
12-03 14:56:08.224 14083-14083/? I/System.out: Thu Sep 05 14:56:08 GMT+00:00 3861
Perfetto!

. Ora proviamo a sottrarre le due date che avevo detto prima: la data del mio primo giorno di scuola elementare dalla data di nascita.
        Date nascita=new Date(1961,8,5);
        Date scuola=new Date(1966,9,1);

        Long milliDiff=scuola.getTime()-nascita.getTime();
        System.out.println(milliDiff);
Converto in millisecondi e faccio la sottrazione.
Ecco l'output:
12-03 14:59:47.952 14170-14170/? I/System.out: 160012800000
Ma non posso sapere a quanto tempo corrisponde quest'accozzaglia informe di millisecondi. Come faccio?

Posso andare per divisioni successive...

diviso 1000, diviso 3600 diviso 24 e ottengo i giorni... poi ci addentriamo coi bisestili e va tutto a pallino...
Proviamo con i giorni.
        Date nascita=new Date(1961,8,5);
        Date scuola=new Date(1966,9,1);

        Long milliDiff=scuola.getTime()-nascita.getTime();
        Long giorni=milliDiff/1000/3600/24;
        System.out.println(giorni);
12-03 15:11:16.978 14262-14262/? I/System.out: 1852
Posso dividere per 365 e ottenere gli anni.
        Date nascita=new Date(1961,8,5);
        Date scuola=new Date(1966,9,1);

        Long milliDiff=scuola.getTime()-nascita.getTime();
        Long giorni=milliDiff/1000/3600/24/365;
        System.out.println(giorni);
12-03 15:19:57.393 14669-14669/? I/System.out: 5
Ma esiste la possibilità, invece di ridurre tutto a millisecondi, di fare il calcolo direttamente fra giorni, mesi e anni?
Proviamo...

        Date nascita=new Date(1961,8,5);
        Date scuola=new Date(1966,9,1);


        int anni=scuola.getYear()-nascita.getYear();
        System.out.println(anni);
12-03 15:26:58.240 14902-14902/? I/System.out: 5
Sì, esatto. Tutto deprecato, ma tutto funzionante!
Quindi per calcolare l'età questo è perfetto!

Resta da calcolare gli anni esatti al giorno e al mese.
Ho questo schema...
        Date nascita=new Date(1961,8,5);
        Date scuola=new Date(1966,9,1);


        int differenza=scuola.getYear()-nascita.getYear();
        if(nascita.getMonth()>scuola.getMonth() ||
                (nascita.getMonth()==scuola.getMonth() && nascita.getDate()>scuola.getDate())){
            differenza--;
        }
        System.out.println(differenza);
12-03 15:34:18.835 15111-15111/? I/System.out: 5
Bene. Se invece avessi iniziato la scuola il 1 agosto 1966:
        Date nascita=new Date(1961,8,5);
        Date scuola=new Date(1966,7,1);


        int differenza=scuola.getYear()-nascita.getYear();
        if(nascita.getMonth()>scuola.getMonth() ||
                (nascita.getMonth()==scuola.getMonth() && nascita.getDate()>scuola.getDate())){
            differenza--;
        }
        System.out.println(differenza);
12-03 15:36:36.880 15192-15192/? I/System.out: 4
...avrei iniziato la scuola ancora a 5 anni non compiuti.
Se avessi iniziato il giorno prima del mio compleanno:
        Date nascita=new Date(1961,8,5);
        Date scuola=new Date(1966,8,4);


        int differenza=scuola.getYear()-nascita.getYear();
        if(nascita.getMonth()>scuola.getMonth() ||
                (nascita.getMonth()==scuola.getMonth() && nascita.getDate()>scuola.getDate())){
            differenza--;
        }
        System.out.println(differenza);
12-03 15:38:13.616 15288-15288/? I/System.out: 4
Mentre se fossi andato il giorno del mio compleanno:
        Date nascita=new Date(1961,8,5);
        Date scuola=new Date(1966,8,5);


        int differenza=scuola.getYear()-nascita.getYear();
        if(nascita.getMonth()>scuola.getMonth() ||
                (nascita.getMonth()==scuola.getMonth() && nascita.getDate()>scuola.getDate())){
            differenza--;
        }
        System.out.println(differenza);
12-03 15:39:19.222 15372-15372/? I/System.out: 5
Sarei andato a 5 anni compiuti!
Bene. Non tenendo conto delle deprecazioni, con i metodi di Date si può fare qualunque calcolo!

venerdì 2 dicembre 2016

Codice che interpreta la data in una editText

Ecco il codice definitivo:
public class MainActivity extends AppCompatActivity {

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

        Date date=null;
        String stringa="5 09 961";



        int posizione=stringa.length()-stringa.lastIndexOf(" ");

        if(posizione!=5 && posizione!=3)return;

        if(posizione==5){
            System.out.println("Posizione 5");
            sdf=new SimpleDateFormat("dd M yyyy");
        }
        if(posizione==3){
            System.out.println("Posizione 3");
            sdf=new SimpleDateFormat("dd M yy");
        }

        try {
            sdf.setLenient(false);
            date = sdf.parse(stringa);
            System.out.println(date.toString());
        } catch (ParseException e) {
            System.out.println("ERRORE");
        }


    }
}

giovedì 1 dicembre 2016

Inserimento della data e riconoscimento di vari formati di date

Obiettivo: Permettere il riconoscimento come data di vari formati inseriti liberamente.

Vado subito a fare una ricerca...

Teniamo presente che bisogna comunque e sempre usare la classe Calendar.

E creiamo un'istanza di Calendar...
Calendar calendar= Calendar.getInstance();
E fin qui non ci sono dubbi, anche se non abbiamo risolto niente.

La classe che aveva un ruolo, se ricordo bene, nella conversione di date, era SimpleDateFormat.
Provo ad istanziarla...

.....

Bene, ho fatto un po' di ricerche e pare che l'unico modo sia preparare una serie di formati di data confrontandoli con ciò che viene scritto.
Quali possono essere i formati di data più "immediati"?
Tipo:
  1. 5 9 1961
  2. 5 9 61
  3. 05 09 1961
  4. 05 09 61
  5. 5/9/1961
  6. 5/9/61
  7. 05/09/1961
  8. 05/09/61
... mi sta venendo un'idea: e se attraverso la manipolazione delle stringhe parificassi i vari formati di data convertendo in spazio vuoto sia gli slash sia gli eventuali trattini?7 Sarebbe fattibile.
Vediamo come si può manipolare una stringa.

Ottimo!
Praticamente il metodo replace() fa perfettamente al caso mio.
Per convertire una stringa in cui le varie parti di una data siano separate da uno spazio qualora venga introdotta con degli slash, si può usare questa sintassi:
        String stringa="5/9/1961";

        stringa=stringa.replace('/',' ');

        System.out.println(stringa);
Ed ecco l'output:
12-01 13:53:38.906 4629-4629/? I/System.out: 5 9 1961
Stessa cosa con il trattino:
        String stringa="5-9-1961";

        stringa=stringa.replace('-',' ');

        System.out.println(stringa);
12-01 13:54:50.784 4717-4717/? I/System.out: 5 9 1961
Se vengono presi in considerazione caratteri che non fanno parte della stringa, vengono bellamente ignorati:
        String stringa="5 9 1961";

        stringa=stringa.replace('/',' ');

        System.out.println(stringa);
12-01 13:56:24.096 4808-4808/? I/System.out: 5 9 1961
Questo mi consente di mettere in sequenza le "normalizzazioni" della stringa.
Ora torno al codice che mi deve parsare la stringa.
L'uso di setLenient=false è importante per far lanciare eccezione qualora il formato della stringa non rispecchi quello voluto.

Bene.
Mi costruisco un array di SimpleDateFormat.
Ecco il codice che ho scritto: sembra che sia sufficiente usare come parametro di SimpleDateFormat la stringa "dd MM yyyy" per accettare tutti i vari formati che avevo elencato sopra, tranne quando la separazione tra le cifre è fatta con uno slash o un trattino.
        ArrayList<SimpleDateFormat> lista=new ArrayList<SimpleDateFormat>();
        lista.add(new SimpleDateFormat("dd/MM/yyyy"));

        for(SimpleDateFormat format : lista){
            try {
                format.setLenient(false);
                format.parse(stringa);
                System.out.println("CORRETTO");
            } catch (ParseException e) {
                System.out.println("ERRORE");
            }

        }
Credo di poter lavorare con una certa dose di correttezza sufficiente se pongo che il mese vada sempre introdotto in numero, riportando tutto a un formato "normale" mediante la sostituzione dei simboli di separazione con spazi vuoti.
No! C'è qualche problema con l'anno.
Se io scrivo yyyy e introduco l'anno in due cifre, me lo conta senza le prime due cifre, ossia il 61 dopo Cristo.
Devo poter discriminare dalla stringa se l'ultimo pezzo dopo lo spazio vuoto è di due o quattro cifre.

Come fare?
Mediante il metodo lastIndexOf della stringa posso risalire, sottraendo la posizione del carattere dalla lunghezza della stringa, alla posizione da destra del carattere.
Ecco come ho risolto per il momento il problema. L'utente viene obbligato a scrivere l'anno in due o quattro cifre, se ne usa un numero diverso incorre nell'errore.
La data è giusta comunque:
public class MainActivity extends AppCompatActivity {

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

        Date date=null;
        String stringa="5 09 961";

        int posizione=stringa.length()-stringa.lastIndexOf(" ");

        if(posizione==5){
            sdf=new SimpleDateFormat("dd M yyyy");
        }
        if(posizione==3){
            sdf=new SimpleDateFormat("dd M yy");
        }
        else{
            System.out.println("ERRORE");
        }

        try {
            date=sdf.parse(stringa);
            System.out.println(date.toString());
        } catch (ParseException e) {
            System.out.println("ERRORE");
        }

    }
}