JavascriptProva

sabato 12 marzo 2016

Codice MediaRecorder e MediaPlayer

Salvo qui il codice completo di MediaRecorder e MediaPlayer:
public class MainActivity extends Activity{

 private MediaPlayer mPlayer;
 private MediaRecorder mRecorder;
 private Button bttRecord; 
 private Button bttStopRecord;
 private Button bttPlay;
 private Button bttStopPlay;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  bttRecord=(Button)findViewById(R.id.button1);
  bttStopRecord=(Button)findViewById(R.id.button2);
  bttPlay=(Button)findViewById(R.id.button3);
  bttStopPlay=(Button)findViewById(R.id.button4);
  
  bttRecord.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    mRecorder =new MediaRecorder();
    mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    mRecorder.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/mioFile.3gp");
    try{
     mRecorder.prepare();
    }catch(Exception e){
     Log.d("errore", "Prepare failed!");
    }
    mRecorder.start();
   }
  });
  bttStopRecord.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    mRecorder.stop();
    mRecorder.release();
    mRecorder=null;
    
   }
  });
  
  bttPlay.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    mPlayer=new MediaPlayer();
    try{
     mPlayer.setDataSource(Environment.getExternalStorageDirectory().getAbsolutePath()+"/mioFile.3gp");
     mPlayer.prepare();
     mPlayer.start();
    }catch(Exception e)
    {
     Log.d("Exception", "Play failed");
    }
    
   }
  });
  
  bttStopPlay.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    mPlayer.release();
    mPlayer=null;
    
   }
  });
  
 
 }

 
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.laboratorio.MainActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="38dp"
        android:text="Record" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button1"
        android:layout_alignBottom="@+id/button1"
        android:layout_marginLeft="46dp"
        android:layout_toRightOf="@+id/button1"
        android:text="Stop record" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/button1"
        android:layout_below="@+id/button1"
        android:layout_marginTop="55dp"
        android:text="Play" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button3"
        android:layout_alignBottom="@+id/button3"
        android:layout_alignLeft="@+id/button2"
        android:text="Stop Play" />

</RelativeLayout> 
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.laboratorio"
    android:versionCode="1"
    android:versionName="1.0" >
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-sdk
        android:minSdkVersion="18"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest> 
Per eventuale ripasso futuro.

Registrazione di suoni con Android

Recorder.
Quale è l'oggetto che dobbiamo istanziare per registrare la voce?

Ecco, dichiaro una variabile di tipo MediaRecorder e una di tipo MediaPlayer, con le relative "importazioni" richieste da Eclipse.

public class MainActivity extends Activity{

 private MediaPlayer mPlayer;
 private MediaRecorder mRecorder;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  
 
 }
Quindi devo istanziare le variabili.
Come si fa?

Ecco, predispongo un Button che istanzia l'oggetto:
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  button=(Button)findViewById(R.id.button1);
  
  button.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    mRecorder =new MediaRecorder();
    
   }
  });
Ma adesso bisogna settare alcune cose di questo neonato MediaRecorder...

Lo faccio pedissequamente, senza pensarci troppo: capirò in seguito.
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  button=(Button)findViewById(R.id.button1);
  
  button.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    mRecorder =new MediaRecorder();
    mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    mRecorder.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"mioFile.3gp");
    try{
     mRecorder.prepare();
     catch(Exception e){
      Log.d("prepare","failed");
     }
    }
   }
  });
E quindi inizia:
public class MainActivity extends Activity{

 private MediaPlayer mPlayer;
 private MediaRecorder mRecorder;
 private Button button;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  button=(Button)findViewById(R.id.button1);
  
  button.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    mRecorder =new MediaRecorder();
    mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    mRecorder.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"mioFile.3gp");
    try{
     mRecorder.prepare();
    }catch(Exception e){
     Log.d("errore", "Prepare failed!");
    }
    mRecorder.start();
   }
  });
 
 }

 
}
Ho avuto un po' di problemi.
Per prima cosa, leggo che nel Manifest vanno impostati dei permessi, di cui non mi ero accorto prima (anche se ci avevo pensato per poi scordarmene...):
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.laboratorio"
    android:versionCode="1"
    android:versionName="1.0" >
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-sdk
        android:minSdkVersion="18"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest> 
...quindi sembra che abbia messo in sequenza sbagliata alcuni settaggi (la cui natura mi è ancora ignota): inizialmente, con questa sequenza...
    mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    mRecorder.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"mioFile.3gp");
...ho avuto un messaggio di errore:
03-12 14:56:52.930: E/MediaRecorder(16135): try to set the audio encoder without setting the audio source first
Allora ho cambiato:
    mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    mRecorder.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"mioFile.3gp");
e ho ottenuto:
03-12 15:13:32.585: E/MediaRecorder(18394): setAudioEncoder called in an invalid state(2)
Cambio ancora:
    mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    mRecorder.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"mioFile.3gp");
Ed è sempre lui:
03-12 15:17:28.156: E/MediaRecorder(18958): start called in an invalid state: 4

Ma ecco che sull'impagabile StackOverflow leggo "check if you have output file path set and if it really exists.", e penso che forse il path del file di destinazione non è scritto bene in quanto ci manga uno slash!
Ci metto lo slash:
    mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    mRecorder.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/mioFile.3gp");
...E finalmente funziona!!!

martedì 8 marzo 2016

Codice per risolvere il conflitto di nome per un nuovo foglio di Excel da rinominare.

Il problema è dover inserire un nuovo foglio di Excel e rinominarlo, con un nome che potrebbe entrare in conflitto con un eventuale foglio preesistente con lo stesso nome.
Ho seguito una logica un po' contorta, forse...

Il foglio, una volta creato, deve subire l'azione di due subroutines, chiamate EmptyRowDelete e DividiInterviste.
Se invece il foglio viene mantenuto, deve subire solo l'azione di DividiInterviste.
Ho seguito la logica di andare a ErrHandler: se c'è conflitto, di andare a fine: se non c'è conflitto.
In ErrHandler, se viene creato un file ex novo, si va ugualmente a fine: perché il destino è comune a quello che ci sarebbe in mancanza di errore, mentre se viene mantenuto il file originario si va a continua: per subire solo l'ultima delle azioni subite dal file negli altri due casi.
Sub CopiaFoglio()
    Dim newsheet As Worksheet
    Set newsheet = Sheets.Add
    
    On Error GoTo ErrHandler
    newsheet.Name = "Foglio elaborazione"
   
    GoTo fine



ErrHandler:
    risposta = MsgBox("Creare un nuovo Foglio Elaborazione?", vbYesNo)

        If risposta = vbNo Then
        Application.DisplayAlerts = False
        newsheet.Delete
        Application.DisplayAlerts = True
    GoTo continua

    Else
        Application.DisplayAlerts = False
        Sheets("Foglio elaborazione").Delete
        Application.DisplayAlerts = True
        newsheet.Name = "Foglio elaborazione"
    End If
fine:
    Sheets("Foglio Elaborazione").Move after:=Sheets("PANNELLO DI CONTROLLO")
    Sheets("riserva").Cells.Copy Destination:=Sheets("Foglio elaborazione").Cells
    EmptyRowDelete
continua:
     Sheets("Foglio elaborazione").Activate
     DividiInterviste
     
End Sub
Ho cercato di rendere con i colori le due vie e la via comune finale.

lunedì 7 marzo 2016

Creazione di un nuovo foglio con un dato nome in Excel.

Da un elenco di fogli "intoccabile" si copia il tutto su un nuovo foglio rinominato ad hoc.
Bisogna anche gestire l'ipotesi in cui il nuovo foglio già esista.


Sub Macro3()


    Set NewSheet = Sheets.Add
    On Error GoTo ErrHandler
    NewSheet.Name = "Foglio elaborazione"
    Sheets("riserva").Cells.Copy Destination:=NewSheet.Cells

    Exit Sub
ErrHandler:
    NewSheet.Delete
    
End Sub
Con questo codice ci siamo quasi.
Viene aggiunto un nuovo foglio, e viene rinominato, ma c'è una gestione dell'errore nel caso in cui un foglio con questo nome già esista: il foglio viene eliminato.
L'unico neo è che all'atto dell'eliminazione del foglio appare un avviso, come di default ogni qualvolta si elimini un foglio.
La cosa è disattivabile: devo solo ricordare come.

Ecco:
Sub Macro3()


    Set NewSheet = Sheets.Add
    On Error GoTo ErrHandler
    NewSheet.Name = "Foglio elaborazione"
    Sheets("riserva").Cells.Copy Destination:=NewSheet.Cells

    Exit Sub
ErrHandler:
    Application.DisplayAlerts = False
    NewSheet.Delete
    Application.DisplayAlerts = True
End Sub
In questo modo, il tentativo di rinominare un nuovo foglio aggiunto abortisce alla base, in quanto il nuovo foglio aggiunto viene prontamente eliminato, come se non fosse mai stato aggiunto.
Peraltro, provando manualmente a eliminare un foglio della cartella, gli avvisi appaiono come di norma perché l'impostazione Application.DisplayAlerts è settata a false solo per il momento necessario ad eliminare senza "traumi" il foglio appena aggiunto.
Però la cosa sarebbe più completa ed elegante se l'utente potesse avere la possibilità di scegliere se mantenere il vecchio foglio "Foglio Elaborazione", oppure crearne uno nuovo che sia la copia dell'originale, nel caso in cui il foglio sia stato per qualche motivo modificato.
Ci provo...

Ed ecco il risultato finale: si può scegliere se si vuole ricreare il foglio o mantenere quello preesistente.
Sub Macro3()

    
    Set NewSheet = Sheets.Add
    On Error GoTo ErrHandler
    NewSheet.Name = "Foglio elaborazione"
   
    GoTo fine

ErrHandler:
    risposta = MsgBox("Creare un nuovo Foglio Elaborazione?", vbYesNo)
    If risposta = vbYes Then
        Application.DisplayAlerts = False
        Sheets("Foglio elaborazione").Delete
        Application.DisplayAlerts = True
        NewSheet.Name = "Foglio elaborazione"
    Else
        Application.DisplayAlerts = False
        NewSheet.Delete
        Application.DisplayAlerts = True
    End If
    
fine:
     Sheets("riserva").Cells.Copy Destination:=Sheets("Foglio elaborazione").Cells
End Sub

domenica 6 marzo 2016

Android: ripasso su layout mobili nell'ambito di una ScrollView

Devo rimettere a posto i concetti relativi agli elementi spostabili nell'ambito di una ScrollView.

Ho un RelativeLayout posto all'interno di una ScrollView:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" 
    android:fillViewport="true"
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <RelativeLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:id="@+id/mainLayout"
    android:background="#aef"
    tools:context="com.example.comunicatore.MainActivity" >


</RelativeLayout>
</ScrollView> 
Adesso voglio esercitarmi a riscrivere il codice secondo il quale vengono creati dei layout ognuno contenente un'immagine presa nelle risorse, spostabili nell'ambito della ScrollView.
Ossia la schermata può scorrere e nell'ambito della schermata si può eseguire il drag-drop di questi layout.

Cancello il codice che ho scritto e riscrivo.

Parto da questo:
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;

public class MainActivity extends Activity {

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


	}

	
}
Ho già un id attribuito al RelativeLayout e alla ScrollView che lo contiene, nel file xml.

Vado:
inizio con la dichiarazione della ScrollView e del RelativeLayout
//DICHIARAZIONI---DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
	ScrollView scrollView;
	RelativeLayout mainLayout;
//TERMINE DICHIARAZIONI---DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
(mi creo delle sezioni distinte nell'ambito del codice per poterlo rileggere più agevolmente quando diventerà complicato).

Ora inizializzo scrollView e mainLayout:
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
//INIZIALIZZAZIONI----IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
		scrollView=(ScrollView)findViewById(R.id.scrollView);
		mainLayout=(RelativeLayout)findViewById(R.id.mainLayout);
//TERMINE INIZIALIZZAZIONI----IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
E adesso procedo alla creazione a runtime di un layout:
per prima cosa lo dichiaro nella sezione DICHIARAZIONI (preferisco che il suo scope sia diffuso a tutte le parti del codice):
//DICHIARAZIONI---DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
	ScrollView scrollView;
	RelativeLayout mainLayout;
	LinearLayout layout;
//TERMINE DICHIARAZIONI---DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
Dichiaro la ImageView che figurerà all'interno del layout:
//DICHIARAZIONI---DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
	ScrollView scrollView;
	RelativeLayout mainLayout;
	LinearLayout layout;
	ImageView imageView;
//TERMINE DICHIARAZIONI---DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
Dopo aver creato il layout, creo una ImageView che vi andrà messa dentro:
//CODICE DI ONCREATE----CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
		layout=new LinearLayout(this);
		imageView=new ImageView(this);
//TERMINE CODICE DI ONCREATE----CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
E ora devo prendere l'immagine dalle risorse e metterla nella ImageView.
Ricorro al codice che riduce le dimensioni delle immagini:
		layout=new LinearLayout(this);
		imageView=new ImageView(this);
		BitmapFactory.Options opzioni=new BitmapFactory.Options();
		opzioni.inJustDecodeBounds=true;
		BitmapFactory.decodeResource(getResources(), R.drawable.faciadecul,opzioni);
		int fattore=1;
		while(opzioni.outWidth/fattore>100 && opzioni.outHeight/fattore>100){
			fattore*=2;
		}
		opzioni.inJustDecodeBounds=false;
		opzioni.inSampleSize=fattore;
		Bitmap bmp=BitmapFactory.decodeResource(getResources(), R.drawable.faciadecul,opzioni);
		imageView.setImageBitmap(bmp);
E quindi pongo la ImageView entro il Layout.
		layout=new LinearLayout(this);
		imageView=new ImageView(this);
		BitmapFactory.Options opzioni=new BitmapFactory.Options();
		opzioni.inJustDecodeBounds=true;
		BitmapFactory.decodeResource(getResources(), R.drawable.faciadecul,opzioni);
		int fattore=1;
		while(opzioni.outWidth/fattore>100 && opzioni.outHeight/fattore>100){
			fattore*=2;
		}
		opzioni.inJustDecodeBounds=false;
		opzioni.inSampleSize=fattore;
		Bitmap bmp=BitmapFactory.decodeResource(getResources(), R.drawable.faciadecul,opzioni);
		imageView.setImageBitmap(bmp);
		layout.addView(imageView)


Ora imposto le proprietà del layout e lo aggiungo a mainLayout.
		layout=new LinearLayout(this);
		imageView=new ImageView(this);
		BitmapFactory.Options opzioni=new BitmapFactory.Options();
		opzioni.inJustDecodeBounds=true;
		BitmapFactory.decodeResource(getResources(), R.drawable.faciadecul,opzioni);
		int fattore=1;
		while(opzioni.outWidth/fattore>100 && opzioni.outHeight/fattore>100){
			fattore*=2;
		}
		opzioni.inJustDecodeBounds=false;
		opzioni.inSampleSize=fattore;
		Bitmap bmp=BitmapFactory.decodeResource(getResources(), R.drawable.faciadecul,opzioni);
		imageView.setImageBitmap(bmp);
		layout.addView(imageView);
		RelativeLayout.LayoutParams params=new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
		mainLayout.addView(layout);


Ora lancio il tutto, scritto di getto, per verificare la mia abilità...



Perfetto! Funziona alla perfezione!

Giocherellando sulle dimensioni dell'immagine verifico che la scrollView funzioni anch'essa, e risulta funzionante.

Ora metto il codice per rendere spostabile il layout con l'immagine.
Creo una sezione //LISTENERS. Dichiaro un OnTouchListener nella sezione DICHIARAZIONI...
//DICHIARAZIONI---DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
	ScrollView scrollView;
	RelativeLayout mainLayout;
	LinearLayout layout;
	ImageView imageView;

	View.OnTouchListener layoutTouchListener;
	
//TERMINE DICHIARAZIONI---DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
e vado a inizializzarlo nella sezione LISTENERS:
//LISTENERS----LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
layoutTouchListener=new View.OnTouchListener() {
	
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		
		return false;
	}
};
		
//TERMINE LISTENERS----LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
Quindi mi assicuro che all'evento Touch, sempre, venga rilevata la posizione del mouse (o meglio del dito)
Dichiaro le coordinate del mouse/dito nella sezione DICHIARAZIONI:
	ScrollView scrollView;
	RelativeLayout mainLayout;
	LinearLayout layout;
	ImageView imageView;

	View.OnTouchListener layoutTouchListener;
	
	int X,Y;
E rilevo nell'evento OnTouch le coordinate:
layoutTouchListener=new View.OnTouchListener() {
	
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		X=(int)event.getRawX();
		Y=(int)event.getRawY();
		return false;
	}
};

Ora bisogna calcolare la differenza fra la posizione del mouse/dito e quella del layout nel momento in cui va a toccare (evento ACTION_DOWN).
Dichiaro due altre variabili: DeltaX e DeltaY, in cui metterò le differenze delle coordinate dito-layout.
	ScrollView scrollView;
	RelativeLayout mainLayout;
	LinearLayout layout;
	ImageView imageView;

	View.OnTouchListener layoutTouchListener;
	
	int X,Y;
	int deltaX, deltaY;
e vado a dar loro il valore.
Per fare questo, nel codice del listener, devo desumere le coordinate del layout stesso, mediante i LayoutParameters:
layoutTouchListener=new View.OnTouchListener() {
	
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		X=(int)event.getRawX();
		Y=(int)event.getRawY();
		switch(event.getAction()){
		case MotionEvent.ACTION_DOWN:
			RelativeLayout.LayoutParams params=(RelativeLayout.LayoutParams)v.getLayoutParams();
			deltaX=X-params.leftMargin;
			deltaY=Y-params.topMargin;
                        break;
		}
		return false;
	}
};
Ottenuta la differenza, a ogni movimento del mouse/dito devo porre le coordinate del layout a valori pari alle coordinate del dito meno le coordinate del layout.
layoutTouchListener=new View.OnTouchListener() {
	
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		X=(int)event.getRawX();
		Y=(int)event.getRawY();
		switch(event.getAction()){
		case MotionEvent.ACTION_DOWN:
			RelativeLayout.LayoutParams params=(RelativeLayout.LayoutParams)v.getLayoutParams();
			deltaX=X-params.leftMargin;
			deltaY=Y-params.topMargin;
			break;
		case MotionEvent.ACTION_MOVE:
			params=(RelativeLayout.LayoutParams)v.getLayoutParams();
			params.leftMargin=X-deltaX;
			params.topMargin=Y-deltaY;
			v.setLayoutParams(params);
			break;
		}
		return false;
	}
};
(l'evento OnTouch si ripete sempre anche durante il movimento, per cui X e Y vengono continuamente rilevate).

Ora devo attribuire il Listener al layout, però! Ho lanciato l'applicazione dimenticando di farlo, e ovviamente non funzionava...

layout=new LinearLayout(this); imageView=new ImageView(this); BitmapFactory.Options opzioni=new BitmapFactory.Options(); opzioni.inJustDecodeBounds=true; BitmapFactory.decodeResource(getResources(), R.drawable.faciadecul,opzioni); int fattore=1; while(opzioni.outWidth/fattore>100 || opzioni.outHeight/fattore>100){ fattore*=2; } opzioni.inJustDecodeBounds=false; opzioni.inSampleSize=fattore; Bitmap bmp=BitmapFactory.decodeResource(getResources(), R.drawable.faciadecul,opzioni); imageView.setImageBitmap(bmp); layout.addView(imageView); RelativeLayout.LayoutParams params=new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT); layout.setOnTouchListener(layoutTouchListener); mainLayout.addView(layout); Non funziona ancora!
Provo a cambiare il false dell'evento OnTouch a true:
layoutTouchListener=new View.OnTouchListener() {
	
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		X=(int)event.getRawX();
		Y=(int)event.getRawY();
		switch(event.getAction()){
		case MotionEvent.ACTION_DOWN:
			RelativeLayout.LayoutParams params=(RelativeLayout.LayoutParams)v.getLayoutParams();
			deltaX=X-params.leftMargin;
			deltaY=Y-params.topMargin;
			break;
		case MotionEvent.ACTION_MOVE:
			params=(RelativeLayout.LayoutParams)v.getLayoutParams();
			params.leftMargin=X-deltaX;
			params.topMargin=Y-deltaY;
			v.setLayoutParams(params);
			break;
		}
		return true;
	}
};
E parte!!!
Probabilmente con il false l'evento "bubblava" al mainLayout.
Però insorge un nuovo problema! Finché non viene "sfottuta" la scrollView, il layout con l'immagine si sposta agevolmente, ma quando lo porto in giù oltrepassando il limite della "schermata", allora entra in azione la scrollView, che funziona, ma una volta azionata non riesco più a muovere il layout, che nel trascinamento col mouse/dito ha strani comportamenti.
Probabilmente ciò è dovuto al fatto che la scrollView viene manipolata quando tocco il layout. Così devo mettere in azione un blocco della scrollView nel momento in cui sto "draggando" il layout.
Ci provo con un magico metodo di nome "request..." e non ricordo più come, da porre nel codice dell'evento OnTouch.
Lo ritrovo con l'Intellisense...
layoutTouchListener=new View.OnTouchListener() {
	
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		scrollView.requestDisallowInterceptTouchEvent(false);
		X=(int)event.getRawX();
		Y=(int)event.getRawY();
		switch(event.getAction()){
		case MotionEvent.ACTION_DOWN:
			RelativeLayout.LayoutParams params=(RelativeLayout.LayoutParams)v.getLayoutParams();
			deltaX=X-params.leftMargin;
			deltaY=Y-params.topMargin;
			break;
		case MotionEvent.ACTION_MOVE:
			params=(RelativeLayout.LayoutParams)v.getLayoutParams();
			params.leftMargin=X-deltaX;
			params.topMargin=Y-deltaY;
			v.setLayoutParams(params);
			break;
		}
		return true;
	}
};
Eccolo!
Rilancio l'applicazione e vediamo ora come va...

Va male, esattamente come prima, perché quel metodo dovevo impostarlo a true!
layoutTouchListener=new View.OnTouchListener() {
	
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		scrollView.requestDisallowInterceptTouchEvent(true);
		X=(int)event.getRawX();
		Y=(int)event.getRawY();
		switch(event.getAction()){
		case MotionEvent.ACTION_DOWN:
			RelativeLayout.LayoutParams params=(RelativeLayout.LayoutParams)v.getLayoutParams();
			deltaX=X-params.leftMargin;
			deltaY=Y-params.topMargin;
			break;
		case MotionEvent.ACTION_MOVE:
			params=(RelativeLayout.LayoutParams)v.getLayoutParams();
			params.leftMargin=X-deltaX;
			params.topMargin=Y-deltaY;
			v.setLayoutParams(params);
			break;
		}
		return true;
	}
};
Ora è praticamente perfetto!!!

Una griglia di numeri in JavaScript

Vorrei creare una tastiera mediante la quale sia possibile prelevare cifre per poi deporle in uno spazio a creare numeri.

(nota: provato solo per Firefox)

Proverei con il JavaScript...

Comincio con il creare due DIV ognuno dei quali porta un numero da 1 a 3.
Cliccando sul DIV dovrebbe apparire al puntatore del mouse un "cartellino" contenente il numero rappresentato dal DIV.

Come si può creare un DIV a runtime? Rinfreschiamoci le idee...

<style>
.numero{
 font-size:60px;
 background-color:#AACCFF;
 width:100px;
 height:100px;
}

</style>


<script>
function creaDiv(){
 var mioDiv=document.createElement('div');
 mioDiv.className="numero";
 mioDiv.innerHTML=1;
 document.getElementsByTagName("body")[0].appendChild(mioDiv); 
}
</script>

<body onLoad="creaDiv()">


</body> 
Adesso vediamo di creare dei DIV affiancati, in file di tre.
Ricordo un classico schema per creare delle griglie di elementi...


Ecco, l'ho messo in pratica, ho rinunciato ad andare per passettini creando solo 1, 2 e 3, e ho fatto di getto tutto, ed ecco la funzione grid(left, top) che mi crea una griglia di elementi che ha la posizione specificata dai parametri:
<style>
.numero{
 font-size:100px;
 background-color:#AAEEDD;
 width:100px;
 height:100px;
 border: 2px solid green;
 line-height:100%;
 text-align:center;
 vertical-align:text-middle;
}

</style>


<script>
function main(){
 grid(300,50);
}
function grid(left,top){
 var x,y;
 for(n=0;n<9;n++){
  x=n%3;
  y=Math.floor(n/3);
  creaDiv(x,y,left,top,n);
 }
  
}
function creaDiv(x,y,left,top,n){
 var mioDiv=document.createElement('div');
 mioDiv.className="numero";
 mioDiv.innerHTML=n+1;
 mioDiv.style.position="absolute";
 mioDiv.style.left=left+x*parseInt(getComputedStyle(mioDiv).getPropertyValue("width"));
 mioDiv.style.top=top+y*parseInt(getComputedStyle(mioDiv).getPropertyValue("height"));
 document.getElementsByTagName("body")[0].appendChild(mioDiv); 
}
</script>

<body onLoad="main()">


</body>
Ecco la griglia:



Mi piace, ogni tanto, ripassare e approfondire il JavaScript!