JavascriptProva

lunedì 26 marzo 2018

Colonna di labels spostabile con due parametri aggiuntivi.

Obiettivo: spostare la griglia di caselle a piacimento Per fare questo aggiungo due parametri.
Presto fatto!
Posso spostare tutta la colonna a mio piacimento mediante i parametri sinistra e alto.
    Private Sub creaColonna(mese As Integer, anno As Integer,
                            labelWidth As Integer, labelHeight As Integer,
                            horSpace As Integer, vertSpace As Integer,
                            sinistra As Integer, alto As Integer,
                            isCalendar As Boolean)

        Dim giorniDelMese As Integer = DaysInMonth(anno, mese)
        Dim perColumn = giorniDelMese
        Dim giorno As New Date(anno, mese, 1)
        For n = 0 To giorniDelMese - 1
            mLabel = New Label
            If isCalendar Then mLabel.Text = giorno.ToString("dddd" + " " + "dd/MMMM/yyyy").ToUpper
            giorno = giorno.AddDays(1)
            mLabel.Width = labelWidth
            mLabel.Height = labelHeight
            mLabel.BorderStyle = BorderStyle.FixedSingle
            mLabel.AutoSize = False
            mLabel.Left = sinistra + (mLabel.Width + horSpace) * (n \ perColumn)
            mLabel.Top = alto + (mLabel.Height + vertSpace) * (n Mod perColumn)
            Controls.Add(mLabel)
        Next
    End Sub
Ed ecco:



Perfetto! Ho raggiunto la massima flessibilità!

Funzione flessibile per la creazione di labels in colonne.

Obiettivo: per disporre varie colonne ognuna con un tipo diverso di label creare una funzione flessibile con parametri.

Ecco la funzione flessibile:
    Private Sub creaColonna(mese As Integer, anno As Integer,
                            labelWidth As Integer, labelHeight As Integer,
                            horSpace As Integer, vertSpace As Integer,
                            isCalendar As Boolean)

        Dim giorniDelMese As Integer = DaysInMonth(anno, mese)
        Dim perColumn = giorniDelMese
        Dim giorno As New Date(anno, mese, 1)
        For n = 0 To giorniDelMese - 1
            mLabel = New Label
            If isCalendar Then mLabel.Text = giorno.ToString("dddd" + " " + "dd/MMMM/yyyy").ToUpper
            giorno = giorno.AddDays(1)
            mLabel.Width = labelWidth
            mLabel.Height = labelHeight
            mLabel.BorderStyle = BorderStyle.FixedSingle
            mLabel.AutoSize = False
            mLabel.Left = (mLabel.Width + horSpace) * (n \ perColumn)
            mLabel.Top = (mLabel.Height + vertSpace) * (n Mod perColumn)
            Controls.Add(mLabel)
        Next
    End Sub
Parametri:
  1. mese
  2. anno
  3. larghezza della label
  4. altezza della label
  5. spaziatura orizzontale
  6. spaziatura verticale
  7. variabile booleana che stabilisce se la colonna sia un calendario, con scritte le date, o no.
Se impostata quest'ultima a True, ottengo:



mentre se è impostata a False ottengo:



Funziona, anche se è ancora perfettibile...

Sviluppo di un calendario su form in VB.NET

Ecco. Ricominciamo a creare un semplice calendario...

Usare delle Labels.
Non ricordo come si creano le date in VB.

Obiettivo: creare date con somme e sottrazioni di giorni fra un mese e l'altro.
Per prima cosa ho trovato il modo di sommare le date.
Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim d As New Date(2018, 3, 2)
        Debug.Print(d)
        d = d.AddDays(10)
        Debug.Print(d)
    End Sub
End Class
02/03/2018
12/03/2018
Vado su calcoli più complessi: attraverso la fine dell'anno...
Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim d As New Date(2018, 12, 20)
        Debug.Print(d)
        d = d.AddDays(12)
        Debug.Print(d)
    End Sub
End Class
20/12/2018
01/01/2019
Perfetto.

Anni bisestili:
2016 (anno bisestile): sommo 9 giorni alla data del 20 febbraio:
Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim d As New Date(2016, 2, 20)
        Debug.Print(d)
        d = d.AddDays(9)
        Debug.Print(d)
    End Sub
End Class
20/02/2016
29/02/2016


2017 (anno non bisestile): sommo 9 giorni alla data del 20 febbraio:
Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim d As New Date(2017, 2, 20)
        Debug.Print(d)
        d = d.AddDays(9)
        Debug.Print(d)
    End Sub
End Class
20/02/2017
01/03/2017
Perfetto!


Obiettivo n.2: creare una disposizione delle labels in un form secondo l'algoritmo che io chiamo "divisione intera - modulo"
Public Class Form1
    Dim mLabel As Label
    Const vertSpace = 10
    Const horSpace = 30
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For n = 0 To 29
            mLabel = New Label
            mLabel.Width = 100
            mLabel.Height = 50
            mLabel.BorderStyle = BorderStyle.FixedSingle
            mLabel.AutoSize = False
            mLabel.Left = (mLabel.Width + horSpace) * (n \ 5)
            mLabel.Top = (mLabel.Height + vertSpace) * (n Mod 5)
            Controls.Add(mLabel)
        Next


    End Sub
End Class




Bene.



Obiettivo n.3: inserire nelle labels i giorni di un mese.

Vediamo come si fa a ottenere il numero di giorni di un mese.

Ecco, ho ottenuto tutto il necessario:
Imports System.DateTime
Public Class Form1
    Dim mLabel As Label
    Const vertSpace = 10
    Const horSpace = 30
    Const perColumn = 10
    Const anno = 2016
    Const mese = 2

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim giorno As New Date(anno, mese, 1)
        For n = 0 To DaysInMonth(anno, mese) - 1
            mLabel = New Label
            mLabel.Text = giorno
            giorno = giorno.AddDays(1)
            mLabel.Width = 100
            mLabel.Height = 50
            mLabel.BorderStyle = BorderStyle.FixedSingle
            mLabel.AutoSize = False
            mLabel.Left = (mLabel.Width + horSpace) * (n \ perColumn)
            mLabel.Top = (mLabel.Height + vertSpace) * (n Mod perColumn)
            Controls.Add(mLabel)
        Next
    End Sub
End Class





Obiettivo n.4: formattare le date

Per prima cosa ho trovato il modo di scrivere per esteso il giorno della settimana.
Ma poi ho avuto l'esigenza di mettere a capo la data per isolare il nome del giorno della settimana nella riga superiore, e ho trovato Environment.newLine. Inoltre il toUpper per fare tutte maiuscole.
Ultima modifica: il mese scritto in lettere anziché in numero:
        For n = 0 To DaysInMonth(anno, mese) - 1
            mLabel = New Label
            mLabel.Text = giorno.ToString("dddd" + Environment.NewLine + "dd/MMMM/yyyy").ToUpper
            giorno = giorno.AddDays(1)
            mLabel.Width = 120
            mLabel.Height = 50
            mLabel.BorderStyle = BorderStyle.FixedSingle
            mLabel.AutoSize = False
            mLabel.Left = (mLabel.Width + horSpace) * (n \ perColumn)
            mLabel.Top = (mLabel.Height + vertSpace) * (n Mod perColumn)
            Controls.Add(mLabel)
        Next
Ed è tutto:



Per il momento mi sembra soddisfacente!

giovedì 22 marzo 2018

Salvataggio di AutoCompleteTextView con database

Ho risolto un problema che mi è risultato piuttosto difficile, ossia usare una casella autocompletante con una tabella di database.
Ne salvo il codice:

activity_main.xml:
<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="4"
    tools:context="c.antonello.tavolodatabase.MainActivity">


    <AutoCompleteTextView
        android:id="@+id/autoCompleteTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="text"/>


</LinearLayout> 


MainActivity:
public class MainActivity extends AppCompatActivity {

    Helper helper;

    AutoCompleteTextView completeTextView;
    SimpleCursorAdapter mAdapter;

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

        helper=new Helper(this);
        completeTextView=(AutoCompleteTextView)findViewById(R.id.autoCompleteTextView);

        mAdapter= new SimpleCursorAdapter(this,
                android.R.layout.simple_list_item_1,
                null,
                new String[]{"nome"},
                new int[]{android.R.id.text1},
                0
        );

        mAdapter.setCursorToStringConverter(new SimpleCursorAdapter.CursorToStringConverter() {
            @Override
            public CharSequence convertToString(Cursor cursor) {
                int index=cursor.getColumnIndex("nome");
                return cursor.getString(index);
            }
        });

        mAdapter.setFilterQueryProvider(new FilterQueryProvider() {
            @Override
            public Cursor runQuery(CharSequence charSequence) {
                System.out.println(charSequence);
                return helper.querySelect(charSequence.toString());
            }
        });

        completeTextView.setAdapter(mAdapter);

        completeTextView.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View view, int i, KeyEvent keyEvent) {
                if(keyEvent.getAction()==KeyEvent.ACTION_DOWN){
                    switch(i){
                        case KeyEvent.KEYCODE_ENTER:
                            System.out.println(completeTextView.getText());
                            return true;
                        default:
                            break;
                    }
                }
                return false;
            }
        });
    }
}


helper:
public class Helper extends SQLiteOpenHelper {


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

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("create table tabella(_id integer primary key,nome text)");

    }

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

    }

    public Cursor query(){
        SQLiteDatabase db=this.getReadableDatabase();
        return db.rawQuery("select * from tabella",null);
    }

    public Cursor querySelect(String stringa){
        SQLiteDatabase db=this.getReadableDatabase();
        Cursor c=db.rawQuery("select * from tabella where nome like '%"+stringa+"%'",null);
        return c;

    }

    public void modifica(int id,String stringa){
        SQLiteDatabase db=this.getWritableDatabase();
        ContentValues values=new ContentValues();
        values.put("nome",stringa);
        db.update("tabella",values,"_id="+id,null);
    }

    public void cancella(int id){
        SQLiteDatabase db=this.getWritableDatabase();
        db.delete("tabella","_id="+id,null);
    }



    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

sabato 17 marzo 2018

CursorAdapter con aggiunta di una riga extra alla fine.

Ora dobbiamo riscrivere il codice per un CursorAdapter, aggiungendo elementi alla fine.
Eccolo:
public class MainActivity extends AppCompatActivity {

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

        listView=(ListView)findViewById(R.id.listView);
        /*helper=new Helper(this);
        helper.save("Brontolo");
        helper.save("Cucciolo");
        helper.save("Pisolo");
        helper.save("Gongolo");
        helper.save("Mammolo");
        helper.save("Dotto");
        helper.save("Eolo");*/


        MyCursorAdapter adapter=new MyCursorAdapter(this,helper.query());

        listView.setAdapter(adapter);
        LayoutInflater inflater=(LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
        View v=inflater.inflate(R.layout.row,null);
        EditText editText=(EditText) v.findViewById(R.id.editText);
        editText.setText("EXTRA");
        listView.addFooterView(v);


    }

    class MyCursorAdapter extends CursorAdapter{

        public MyCursorAdapter(Context context, Cursor c) {
            super(context, c);
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
            LayoutInflater inflater=(LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
            return inflater.inflate(R.layout.row,null);
        }

        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            EditText editText=(EditText) view.findViewById(R.id.editText);
            editText.setText(cursor.getString(cursor.getColumnIndex("nome")));
        }
    }
}


Riscrittura di CursorAdapter personalizzato.

La riscrittura di un CursorAdapter mi risulta facile: questo codice (contiene anche frammenti per la sperimentazione di ArrayAdapter vari già fatta prima) funziona benissimo.
public class MainActivity extends AppCompatActivity {


    ArrayAdapter arrayAdapter;
    ArrayList arrayList;
    Helper helper;
    ListView listView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView=(ListView)findViewById(R.id.listView);
        helper=new Helper(this);
        /*helper.save("Brontolo");
        helper.save("Cucciolo");
        helper.save("Pisolo");
        helper.save("Gongolo");
        helper.save("Mammolo");
        helper.save("Dotto");
        helper.save("Eolo");*/

        arrayList=new ArrayList();
        arrayList.add("Alfa");
        arrayList.add("Beta");
        arrayList.add("Gamma");
        arrayList.add("Delta");
        arrayList.add("Epsilon");
        arrayList.add("Zeta");
        arrayList.add("Eta");

        String[] matrice=new String[]{"uno","due","tre","quattro","cinque","sei","sette"};

        MyCursorAdapter adapter=new MyCursorAdapter(this,helper.query());
        listView.setAdapter(adapter);

    }

    class MyCursorAdapter extends CursorAdapter{

        public MyCursorAdapter(Context context, Cursor c) {
            super(context, c);
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
            LayoutInflater inflater=(LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
            return inflater.inflate(R.layout.row,null);
        }

        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            TextView textView=view.findViewById(R.id.textView);
            textView.setText(cursor.getString(cursor.getColumnIndex("nome")));
        }
    }


}

Esercizi di riscrittura di ArrayAdapter nativo e personalizzato

Il problema è aggiungere una voce "vuota" a una ListView, da compilare.
Come faccio?
Inizio col creare una ListView.
La cosa mi servirà anche per esercitarmi con la ListView e con gli adapters.

Per prima cosa vediamo un adapter personalizzato. Iniziamo con un ArrayAdapter non personalizzato.
public class MainActivity extends AppCompatActivity {


    ArrayList arrayList;
    Helper helper;
    ListView listView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView=(ListView)findViewById(R.id.listView);
        helper=new Helper(this);
        /*helper.save("Brontolo");
        helper.save("Cucciolo");
        helper.save("Pisolo");
        helper.save("Gongolo");
        helper.save("Mammolo");
        helper.save("Dotto");
        helper.save("Eolo");*/

        arrayList=new ArrayList();
        arrayList.add("Alfa");
        arrayList.add("Beta");
        arrayList.add("Gamma");
        arrayList.add("Delta");
        arrayList.add("Epsilon");
        arrayList.add("Zeta");
        arrayList.add("Eta");

        ArrayAdapter arrayAdapter=new ArrayAdapter(this,R.layout.row,
                R.id.textView,arrayList);
        
        listView.setAdapter(arrayAdapter);
    }
}
Bene.

Ho fatto un excursus sugli adapters, ho trovato la soluzione alla mia esigenza specifica, e adesso devo esercitarmi un po'.
Scrittura di un arrayadapter.
public class MainActivity extends AppCompatActivity {


    ArrayAdapter arrayAdapter;
    ArrayList arrayList;
    Helper helper;
    ListView listView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView=(ListView)findViewById(R.id.listView);
        helper=new Helper(this);
        /*helper.save("Brontolo");
        helper.save("Cucciolo");
        helper.save("Pisolo");
        helper.save("Gongolo");
        helper.save("Mammolo");
        helper.save("Dotto");
        helper.save("Eolo");*/

        arrayList=new ArrayList();
        arrayList.add("Alfa");
        arrayList.add("Beta");
        arrayList.add("Gamma");
        arrayList.add("Delta");
        arrayList.add("Epsilon");
        arrayList.add("Zeta");
        arrayList.add("Eta");

        String[] matrice=new String[]{"uno","due","tre","quattro","cinque","sei","sette"};

        arrayAdapter=new ArrayAdapter(this,R.layout.row,R.id.textView,arrayList);

        listView.setAdapter(arrayAdapter);
    }
}
Ecco l'uso dell'ArrayAdapter preconfezionato.
Funziona.

Adesso cerchiamo di scrivere il codice dell'ArrayAdapter personalizzato che dovrebbe evitare di creare una nuova view quando questa esiste già.

Ecco con l'adapter personalizzato che estende ArrayAdapter: praticamente svolge la stessa funzione, credo...

        CustomAdapter adapter=new CustomAdapter(this,R.layout.row,arrayList);
        listView.setAdapter(adapter);
    }

    class CustomAdapter extends ArrayAdapter{

        public CustomAdapter(@NonNull Context context, int resource,ArrayList arrayList) {
            super(context, resource,arrayList);
        }

        @NonNull
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            LayoutInflater inflater=(LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
            convertView=inflater.inflate(R.layout.row,null);
            TextView textView=convertView.findViewById(R.id.textView);
            textView.setText(getItem(position));
            return convertView;
        }
    }

Ora uso quell'artifizio per fare in modo che, se la view non è di nuova creazione, non venga nuovamente inflatata ma si usi già per quella che è.
        CustomAdapter adapter=new CustomAdapter(this,R.layout.row,arrayList);
        listView.setAdapter(adapter);

    }

    class CustomAdapter extends ArrayAdapter {
        public CustomAdapter(Context context, int resource,ArrayList lista) {
            super(context, resource,lista);
        }

        @NonNull
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder=null;
            if(convertView==null){
                LayoutInflater inflater=(LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
                convertView=inflater.inflate(R.layout.row,null);
                viewHolder=new ViewHolder();
                viewHolder.txtNome=(TextView)convertView.findViewById(R.id.textView);
                convertView.setTag(viewHolder);
            }else{
                viewHolder=(ViewHolder)convertView.getTag();
            }
            viewHolder.txtNome.setText(getItem(position));
            return convertView;
        }
    }

    class ViewHolder {
        public TextView txtNome;
    }
}
E funziona.

mercoledì 14 marzo 2018

Mandala sui fragments

Ecco il Mandala distrutto e ricostruito sulla creazione di fragments:

Fragments

Una domanda a bruciapelo: ricordo ancora come si creano i Fragments?
Certamente no.
E' ora di mandalizzarne un po'...

Ho ricostruito nella memoria il modo di tracciare due fragments.
Distruggo il mandala e ricostruisco tutto da capo.
Si parte dal layout della MainActivity:
<?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"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="c.antonello.tavolofragment.MainActivity"


    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:orientation="horizontal"
    android:weightSum="4" >

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

    <fragment
        android:name="c.antonello.tavolofragment.Frammento2"
        android:id="@+id/frammento2"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3" />


</LinearLayout> 
mentre sul file Java della MainActivity non si fa niente in assoluto.

Quindi si creano i Fragments come due nuove classi che estendono Fragment:
public class Frammento extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.frammento,container,false);
    }
}
public class Frammento2 extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.frammento2,container,false);
    }
}
e si creano i relativi layout in xml:

frammento.xml
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffff88">

</LinearLayout> 


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

</LinearLayout> 
che vengono inflatati dal metodo onCreateView contenuto nel codice Java del fragment.
Ad ognuno di essi ho attribuito un colore in modo da distinguerli nell'activity risultante.
Funziona.

Adesso sono pronto per la distruzione del Mandala con ricostruzione in diretta...

martedì 13 marzo 2018

Mandala delle funzioni limitanti il trascinamento di un overlay

Ecco, ho distrutto le routines che limitano gli spostamenti dell'immagine e le ho ricostruite.

OnConfigurationChanged (Overlay)

Ed ora questa è la routine che si occupa della gestione delle rotazioni del cellulare:
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
            resetPosition();
            if(wParams.y>(szDisplay.y-statusBarHeight()-wParams.height)){
                wParams.y=szDisplay.y-statusBarHeight()-wParams.height;
                windowManager.updateViewLayout(wImage,wParams);
            }
        }
    }


Io raggrupperei queste in una serie di "routines di servizio", compresa quella che misura lo schermo e quella che misura la statusBar.
Questa ha la funzione di riportare alle "giuste misure", senza "false presenze" sul display di immagini aventi coordinate che ne superano ampiamente le dimensioni, in relazione alle rotazioni del dispositivo, e non ai movimenti di trascinamento come invece fa resetPosition().

La parte con il LANDSCAPE l'ho aggiustata, adesso devo vedere come gestire la parte che da LANDSCAPE porta a PORTRAIT.
Nel passaggio dal LANDSCAPE a PORTRAIT, la y può rimanere oltre i limiti del display, mentre la x va aggiustata.
La sintassi di resetPosition può andare per la x, perché ne riduce il valore a 0 quando l'immagine cada a meno di metà display mentre ne porta il valore alla larghezza del display quando l'immagine cada oltre metà.
Non vedo perché non vada bene così:
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
            resetPosition();
            if(wParams.y>(szDisplay.y-statusBarHeight()-wParams.height)){
                wParams.y=szDisplay.y-statusBarHeight()-wParams.height;
                windowManager.updateViewLayout(wImage,wParams);
            }
        }
        if(newConfig.orientation== Configuration.ORIENTATION_PORTRAIT){
            resetPosition();
        }
    }
Resta il "neo" della posizione y dell'immagine che non va a fondo... per il momento lo lascio così.

resetPosition dell'immagine nel display (Overlay)

Ricominciamo col mandala dello spostamento di un'immagine in overlay.
Questo è quanto ho ricostruito agevolmente finora:

Servizio:
public class OverlayService extends Service {

    int startX, startY;
    float eventX,eventY;
    Immagine wImage,tImage;

    public OverlayService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();

        wImage=new Immagine(this);
        tImage=new Immagine(this);
        wImage.setImageResource(R.drawable.post_it);
        tImage.setImageResource(R.drawable.monnezza);

        final WindowManager windowManager=(WindowManager) getSystemService(WINDOW_SERVICE);
        final WindowManager.LayoutParams wParams=new WindowManager.LayoutParams(
                200,
                200,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT
        );

        wParams.gravity= Gravity.TOP | Gravity.START;
        wParams.x=0;
        wParams.y=100;

        WindowManager.LayoutParams tParams=new WindowManager.LayoutParams(
                200,
                200,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT
        );

        tParams.gravity=Gravity.TOP | Gravity.START;
        tParams.x=0;
        tParams.y=100;

        windowManager.addView(tImage,tParams);
        windowManager.addView(wImage,wParams);

        wImage.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                view.performClick();

                switch(motionEvent.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        startX=wParams.x;
                        startY=wParams.y;
                        eventX=motionEvent.getRawX();
                        eventY=motionEvent.getRawY();
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        wParams.x=startX+(int)(motionEvent.getRawX()-eventX);
                        wParams.y=startY+(int)(motionEvent.getRawY()-eventY);
                        windowManager.updateViewLayout(wImage,wParams);
                        return true;

                }



                return true;
            }
        });




    }

    class Immagine extends android.support.v7.widget.AppCompatImageView{

        public Immagine(Context context) {
            super(context);
        }

        @Override
        public boolean performClick() {
            super.performClick();
            return true;
        }
    }
}


Ora nel corso dell'evento MOVE deve esserci qualcosa che risistemi i confini dell'immagine.
Io farei qualcosa di semplice in questo modo: creare una funzione che mi sospinga sempre in una determinata posizione l'immagine.
Per far questo devo derivare le dimensioni del display:
    private void misuraSchermo(){
        windowManager.getDefaultDisplay().getSize(szDisplay);

    }

    private void resetPosition(){
        misuraSchermo();
        if(wParams.x<=szDisplay.x/2){
            wParams.x=0;
        }else{
            wParams.x=szDisplay.x-wParams.width;
        }
        windowManager.updateViewLayout(wImage,wParams);

    }
Con queste due "routines di servizio" misuro lo schermo e poi all'evento UP riporto l'immagine a sinistra o a destra a seconda che si trovi più verso sinistra o destra.
Questa è la prima difficoltà che ho avuto nel ricordare il codice, ma predisporrò degli altri Mandala.
Ma ho commesso un errore nella ricostruzione di resetPosition.
Non ho considerato che potrei spingere l'immagine anche nella dimensione verticale, oltre che in quella orizzontale, in modo che essa si trovi illusoriamente al limite inferiore della finestra ma in realtà si trovi molto più in basso, resistendo poi al "prelievo" successivo con il tocco.
Ecco la funzione completa, dopo aver creato anche una funzione che contempla la misurazione della statusBar:
    private void resetPosition(){
        misuraSchermo();
        if(wParams.x<=(szDisplay.x/2-wParams.width/2)){
            wParams.x=0;
        }else{
            wParams.x=szDisplay.x-wParams.width;
        }
        if(wParams.y>szDisplay.y-statusBarHeight()-wParams.height){
            wParams.y=szDisplay.y-statusBarHeight()-wParams.height;
        }
        windowManager.updateViewLayout(wImage,wParams);

    }
Questa, così come quella successiva che si occupa della gestione delle rotazioni del cellulare, conviene che me le faccia subito, in modo da togliermi il pensiero.