JavascriptProva

Visualizzazione post con etichetta Layout. Mostra tutti i post
Visualizzazione post con etichetta Layout. Mostra tutti i post

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!!!

mercoledì 27 gennaio 2016

Creazione di un form per il caricamento di immagini in database e creazione di un bordo in un LinearLayout programmaticamente.

Prendere un'immagine dalla memoria e metterla in un database, insieme a etichetta e categoria.
Mi predispongo una tabella di database in cui vi siano i tre campi.
 class Helper extends SQLiteOpenHelper{

  public Helper(Context context) {
   super(context, "database", null, 1);
  }

  @Override
  public void onCreate(SQLiteDatabase db) {
   db.execSQL("CREATE TABLE TABELLA(_ID INTEGER PRIMARY KEY,ETICHETTA TEXT,CATEGORIA TEXT,IMMAGINE BLOB)");
   
   
  }
  
  

  @Override
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
   // TODO Auto-generated method stub
   
  }
  
 }
Ora creo il metodo save e il metodo query.
Ma prima forse mi conviene definire una classe che abbia tutte le proprietà
E qui la cosa si fa interessante per la gestione dell'immagine.
Credo che mi convenga memorizzare un array di bytes.

 class JImage{
  public String Etichetta;
  public String Categoria;
  public byte[] ImageByteArray;
 }
Questo presuppone che nell'immissione di dati venga creata prima la ByteArrayOutputStream e quindi dalla bitmap venga fatta la compressione con successiva conversione della ByteArrayOutputStream in byte di array.

Adesso provo a creare il metodo save().
  public void save(JImage jImage){
   SQLiteDatabase db=this.getWritableDatabase();
   ContentValues values=new ContentValues();
   values.put("ETICHETTA", jImage.Etichetta);
   values.put("CATEGORIA", jImage.Categoria);
   values.put("IMMAGINE", jImage.ImageByteArray);
   db.insert("TABELLA", null, values);
  }
Ecco.

Adesso devo costruire il meccanismo per l'immissione dell'immagine e delle sue caratteristiche.

Fatto.
Il codice che ho inserito è questo (completo):
public class Scelta extends Activity {

 //DICHIARAZIONI
 Bitmap bmp;
 JImage jImage;
 Helper helper;
 Button button;
 Adapter adapter;

 ImageView imageView;
 EditText editText;
 AutoCompleteTextView autoComplete;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_scelta);
  
  //DEFINIZIONI
  helper=new Helper(this);
  imageView=(ImageView) findViewById(R.id.imageView1);
  editText=(EditText) findViewById(R.id.editText1);
  autoComplete=(AutoCompleteTextView) findViewById(R.id.autoCompleteTextView1);
  button=(Button) findViewById(R.id.button1);
  button.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    Intent intent=new Intent();
    intent.setData(Uri.parse("content://media/external/images/media"));
    intent.setAction(Intent.ACTION_PICK);
    startActivityForResult(intent,0);
    
   }
  });
  
  adapter=new Adapter(this,helper.catQuery(" "));
  autoComplete.setAdapter(adapter);
  autoComplete.setOnEditorActionListener(new TextView.OnEditorActionListener() {
   
   @Override
   public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
    ByteArrayOutputStream stream=new ByteArrayOutputStream();
    bmp.compress(CompressFormat.JPEG, 50, stream);
    byte[] blob=stream.toByteArray();
    jImage=new JImage();
    jImage.Etichetta=editText.getText().toString();
    jImage.Categoria=autoComplete.getText().toString();
    jImage.ImageByteArray=blob;
    helper.save(jImage);
    jImage=null;
    bmp=null;
    return false;
   }
  });
  

  
 }
 public void onActivityResult(int requestCode, int resultCode, Intent data){
  if(resultCode==RESULT_OK){
   BitmapFactory.Options opzioni=new BitmapFactory.Options();
   opzioni.inJustDecodeBounds=true;
   BitmapFactory.decodeFile(getPathFromUri(data.getData()),opzioni);
   int fattore=1;
   while(opzioni.outWidth/fattore>200 && opzioni.outHeight/fattore>200){
    fattore*=2;
   }
   opzioni.inSampleSize=fattore;
   opzioni.inJustDecodeBounds=false;
   bmp=BitmapFactory.decodeFile(getPathFromUri(data.getData()),opzioni);
   imageView.setImageBitmap(bmp);
   
   
   
   
  }
 }
 
 private String getPathFromUri(Uri uri){
  Cursor crs=getContentResolver().query(uri, null, null, null, null);
  crs.moveToFirst();
  int index=crs.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
  String s=crs.getString(index);
  return s;
 }
 class Helper extends SQLiteOpenHelper{

  public Helper(Context context) {
   super(context, "database", null, 1);
  }

  @Override
  public void onCreate(SQLiteDatabase db) {
   db.execSQL("CREATE TABLE TABELLA(_id INTEGER PRIMARY KEY,ETICHETTA TEXT,CATEGORIA TEXT,IMMAGINE BLOB)");
   db.execSQL("CREATE TABLE TBLCATEGORIE(_id INTEGER PRIMARY KEY,CATEGORIA TEXT)");
  }
  
  public void save(JImage jImage){
   SQLiteDatabase db=this.getWritableDatabase();
   ContentValues values=new ContentValues();
   values.put("ETICHETTA", jImage.Etichetta);
   values.put("CATEGORIA", jImage.Categoria);
   values.put("IMMAGINE", jImage.ImageByteArray);
   db.insert("TABELLA", null, values);
   values.clear();
   values.put("CATEGORIA", jImage.Categoria);
   db.insert("TBLCATEGORIE", null, values);
   imageView.setImageBitmap(null);
   editText.setText(null);
   autoComplete.setText(null);
  }
  
  public Cursor query(){
   SQLiteDatabase db=this.getWritableDatabase();
   Cursor c = db.rawQuery("SELECT * FROM TABELLA", null);
   c.moveToFirst();
   return c;
  }
  
  public Cursor catQuery(String str){
   SQLiteDatabase db=this.getWritableDatabase();
   Cursor c=db.rawQuery("SELECT * FROM TBLCATEGORIE WHERE CATEGORIA LIKE '"+str+"%'", null);
   c.moveToFirst();
   return c;
  }
  

  @Override
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
   
   
  }
  
 }
 
 class JImage{
  public String Etichetta;
  public String Categoria;
  public byte[] ImageByteArray;
 }
 
 class Adapter extends CursorAdapter{

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

  @Override
  public View newView(Context context, Cursor cursor, ViewGroup parent) {
   LayoutInflater inflater=(LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
   TextView v=(TextView) inflater.inflate(android.R.layout.simple_dropdown_item_1line, null);
   return v;
  }

  @Override
  public void bindView(View view, Context context, Cursor cursor) {
   ((TextView)view).setText(cursor.getString(1));
   
  }
  
  @Override
  public Cursor runQueryOnBackgroundThread(CharSequence constraint){
   if(constraint!=null) return helper.catQuery(constraint+"");
   return null;
  }
  
  @Override
  public String convertToString(Cursor cursor){
   return cursor.getString(1);
   
  }
  
 }
Questo codice è stato trasferito su un'altra activity, chiamata "Scelta".
Ora vorrei visualizzare le immagini su dei LinearLayout.
Per prima cosa, trasferisco il codice su un'altra activity.

E l'ho fatto, ripassando l'Intent esplicito (per passare da un'activity all'altra.
  button=(Button) findViewById(R.id.button1);
  button.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    
    Intent intent=new Intent(MainActivity.this,Scelta.class);
    startActivity(intent);
    
   }
  });
Bene.
Ora, all'avvio di questa Activity, voglio che le immagini salvate nel database vengano riportate su dei LinearLayout.
Devo ripassare le procedure per creare programmaticamente un linearlayout.
LinearLayout ll = new LinearLayout(this);
E poi?
Ecco il codice per aggiungere un Layout all'Activity:
  LinearLayout ll = new LinearLayout(this);
  ll.setBackgroundColor(Color.BLUE);
  ll.setOrientation(LinearLayout.VERTICAL);
  AbsoluteLayout.LayoutParams params=new AbsoluteLayout.LayoutParams(200,200,100,0);
  ll.setLayoutParams(params);
  AbsoluteLayout abs=(AbsoluteLayout)findViewById(R.id.lay);
  abs.addView(ll);
Ora potrebbe essere utile disegnare un bordo al layout.
Questa è una novità.
E ho trovato subito la soluzione
  LinearLayout ll = new LinearLayout(this);
  
  ll.setOrientation(LinearLayout.VERTICAL);
  AbsoluteLayout.LayoutParams params=new AbsoluteLayout.LayoutParams(200,200,100,0);
  ll.setLayoutParams(params);
  GradientDrawable gd=new GradientDrawable();
  gd.setColor(Color.WHITE);
  gd.setStroke(5, Color.BLACK);
  ll.setBackground(gd);
  AbsoluteLayout abs=(AbsoluteLayout)findViewById(R.id.lay);
  abs.addView(ll);
...che mi dà un Layout bianco con un bordo nero di spessore 5 (il numero che appare come parametro nel metodo setStroke).

venerdì 8 gennaio 2016

Inserimento eseguito programmaticamente di LinearLayout esterno in un LinearLayout creato programmaticamente.


Ora provo a inserire programmaticamente un LinearLayout figlio in un LinearLayout creato programmaticamente.
Devo fare uso dell'inflater.

hills.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="@drawable/hills"
    android:orientation="vertical" >
</LinearLayout> 
Parto dal presupposto che i LayoutParams siano già definiti nel layout esterno...
public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  LinearLayout ll=new LinearLayout(this);
  ll.setOrientation(LinearLayout.HORIZONTAL);
  ll.setBackground(getResources().getDrawable(R.drawable.sky));
  LayoutParams llParams=new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
  setContentView(ll,llParams); 
  
  LayoutInflater inflater=(LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  LinearLayout child=(LinearLayout)inflater.inflate(R.layout.hills, null);
  
  ll.addView(child);
  
 }
E ottengo questo:



Evidentemente devo creare i LayoutParams programmaticamente...
public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  LinearLayout ll=new LinearLayout(this);
  ll.setOrientation(LinearLayout.HORIZONTAL);
  ll.setBackground(getResources().getDrawable(R.drawable.sky));
  LayoutParams llParams=new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
  setContentView(ll,llParams); 
  
  LayoutInflater inflater=(LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  LinearLayout child=(LinearLayout)inflater.inflate(R.layout.hills, null);
  LayoutParams childParams = new LayoutParams(0,LayoutParams.MATCH_PARENT,1);
  ll.addView(child,childParams);
  
 }
E ottengo...



Creo un altro layout figlio programmaticamente e lo affianco:
public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  LinearLayout ll=new LinearLayout(this);
  ll.setOrientation(LinearLayout.HORIZONTAL);
  ll.setBackground(getResources().getDrawable(R.drawable.sky));
  LayoutParams llParams=new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
  setContentView(ll,llParams); 
  
  LayoutInflater inflater=(LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  LinearLayout child=(LinearLayout)inflater.inflate(R.layout.hills, null);
  LayoutParams childParams = new LayoutParams(0,LayoutParams.MATCH_PARENT,1);
  ll.addView(child,childParams);
  
  LinearLayout child1=new LinearLayout(this);
  child1.setBackground(getResources().getDrawable(R.drawable.w));
  ll.addView(child1,childParams);
  
 }
...e okay:

Creazione "programmatica" di LinearLayout e di due LinearLayout figli, con immagini di sfondo.


Adesso provo a creare un LinearLayout programmaticamente.
cancello tutti i LinearLayout "figli"...
<LinearLayout 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:orientation="horizontal"
    tools:context="com.example.lab10.MainActivity" >
</LinearLayout> 


Ora cerchiamo di procedere alla creazione di un nuovo layout.
public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  LinearLayout ll=new LinearLayout(this);
  
  setContentView(ll); 
 }
Questo funziona.
Adesso devo trovare come dare gli attributi al layout programmaticamente.

Sarebbero questi:
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
E proviamo...
public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  LinearLayout ll=new LinearLayout(this);
  ll.setOrientation(LinearLayout.HORIZONTAL);
  ll.setBackground(getResources().getDrawable(R.drawable.sky));
  LayoutParams llParams=new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
  setContentView(ll,llParams); 
 }
E ottengo il risultato voluto:



Ho impostato quindi:
  • l'orientamento;
  • l'immagine di fondo;
  • i LayoutParams, ossia width e height, ambedue impostati a MATCH_PARENT, come nel file xml.
Per confronto:
<LinearLayout 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:orientation="horizontal"
    android:background="@drawable/sky"
    tools:context="com.example.lab10.MainActivity" >
</LinearLayout>

Adesso inserisco i due "layout figli", come ho fatto da xml in precedenza, questa volta programmaticamente:

public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  LinearLayout ll=new LinearLayout(this);
  ll.setOrientation(LinearLayout.HORIZONTAL);
  ll.setBackground(getResources().getDrawable(R.drawable.sky));
  LayoutParams llParams=new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
  setContentView(ll,llParams); 
  
  LinearLayout child=new LinearLayout(this);
  child.setOrientation(LinearLayout.HORIZONTAL);
  child.setBackground(getResources().getDrawable(R.drawable.w));
  LayoutParams childParams=new LayoutParams(0,LayoutParams.MATCH_PARENT,1);
  ll.addView(child,childParams);
  
  LinearLayout child1=new LinearLayout(this);
  child1.setOrientation(LinearLayout.HORIZONTAL);
  child1.setBackground(getResources().getDrawable(R.drawable.w3));
  LayoutParams childParams1=new LayoutParams(0,LayoutParams.MATCH_PARENT,1);
  ll.addView(child1,childParams1);
 }
...ci sono impazzito un po' perché avevo commesso qualche errore banale, ma corretto il tutto funziona:

Inclusione di un LinearLayout su xml esterno nel LinearLayout dell'activity principale, mediante xml.

Ecco come ho creato un LinearLayout contenente tre LinearLayout, di cui uno esterno incluso, il tutto tramite manipolazione dell'xml.

activity_main.xml
<LinearLayout 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:orientation="horizontal"
    tools:context="com.example.lab10.MainActivity" >

 <LinearLayout 
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:layout_weight="1"
      android:background="@drawable/w" >
 </LinearLayout>
 
 <include layout="@layout/hills" 
     android:layout_width="0dp"
     android:layout_height="match_parent"
     android:layout_weight="1" /> 
    
 <LinearLayout 
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:layout_weight="1"
      android:background="@drawable/w3" >  
 </LinearLayout>
</LinearLayout> 
la parte marcata in giallo è l'inclusione dell'xml esterno.

hills.xml (xml esterno)
<?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="@drawable/hills"
    android:orientation="vertical" >
</LinearLayout> 
...e il risultato è perfetto!

mercoledì 6 gennaio 2016

Elucubrazioni sulla grafica su Layout e Views in Android

Dunque il setContentView può caricare una view o un layout.
Il layout non ha un metodo onDraw, mentre la view ce l'ha.
Il layout può avere un background, però?
Proviamo... questa materia è difficilissima, ma prima o poi, con l'esercizio, ci dobbiamo pur arrivare, a padroneggiarla!

  public void Disegna(){
   Paint pennello=new Paint();
   Bitmap tela=Bitmap.createBitmap(larghezza,altezza,Bitmap.Config.ARGB_8888);
   Canvas dipinto=new Canvas(tela);
   
   pennello.setColor(Color.RED);
   dipinto.drawRect(100, 100,400,400,pennello);
   muro=(RelativeLayout)findViewById(R.id.muro);
   muro.setBackgroundDrawable(new BitmapDrawable(tela));
   
  }
  
  @Override
  public void onWindowFocusChanged(boolean hasfocus){
   muro=(RelativeLayout)findViewById(R.id.muro);
   altezza=muro.getHeight();
   larghezza=muro.getWidth();
   Disegna();
   
  }
Dunque il RelativeLayout ha un drawable.
Ma anche la View può essere trattata alla stessa maniera:
public class MainActivity extends Activity {


 int larghezza;
 int altezza;
 RelativeLayout muro;
 MyView myView;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
 
  myView =new MyView(this);
  setContentView(myView);
  
  
   
 }
 
 private void Disegna(){
  Bitmap tela=Bitmap.createBitmap(larghezza, altezza, Bitmap.Config.ARGB_8888);
  Canvas dipinto=new Canvas(tela);
  Paint pennello=new Paint();
  pennello.setColor(Color.BLUE);
  dipinto.drawRect(100,100,200,200,pennello);
  myView.setBackgroundDrawable(new BitmapDrawable(tela));
 }
 
 @Override
 public void onWindowFocusChanged(boolean hasfocus){
  altezza=myView.getHeight();
  larghezza=myView.getWidth();
  Disegna();
  
 }
 
  
 class MyView extends View{

  public MyView(Context context) {
   super(context);
   // TODO Auto-generated constructor stub
  }

 
  
 }
Però il Layout non ha un metodo onDraw. Con queste procedure, sia per il Layout sia per la View dipingiamo una tela e poi ce la mettiamo.
La View può essere disegnata da sé, mentre il Layout no. Forse perché è l'elemento radice... Non è facile penetrare nella filosofia di questo sistema operativo!