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

mercoledì 13 luglio 2011

Menu con le ViewStub

Prima di tutto creiamo un nuovo progetto con Eclipse.
Il Manifest non subirà cambiamenti particolari quindi tralasciamo la sua visualizzazione e analizziamo invece il layout dell’Activity principale.

Sorgenti:
stubs.xml
Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">

<LinearLayout android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="vertical"
android:gravity="center">
<EditText android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="Click...but do nothing" />
</LinearLayout>

<ViewStub android:id="@+id/stub_menu" android:inflatedId="@+id/panel_menu"
android:layout="@layout/menu" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_gravity="top" />

</merge>

La prima cosa che salta all’occhio direi è l’utilizzo del tag <merge>
Cos’è ? A cosa serve ? Il tag <merge> è stato creato per ridurre il numero di livelli nella gerarchia delle Views, sembra un po’ ostica da capire come cosa, ma vedendolo in azione si intuisce meglio il suo scopo. In altre parole, basta pensare che ogni View, e quindi ogni Layout, è figlio di un’altra View (o Layout) e difatti quando si crea un XML layout bisogna specifare un root Layout, che verrà istanziato poi al momento di generare il codice Java corrispondente dalla classe LayoutInflater. In questo caso però, quando il LayoutInflater incontrerà il tag <merge> non creerà una nuova istanza di un Layout ma non farà altro che unire la nostra View alla top-level View, cioè alla View di alto livello già istanziata. Comunque per altri chiarimenti vi rimando alla bibliografia in fondo al tutorial. Un altro motivo per cui ho utilizzato il tag <merge> è per poter sovrapporre le due View del layout, che sono il LinearLayout e, per l’appunto, la nostra ViewStub !
Il LinearLayout comprende una EditText e un Button, che ho messo a puro scopo indicativo, mentre vorrei soffermarmi un po’ sulla ViewStub, anche perché è il motivo di questo tutorial !

Analizzando la ViewStub

La ViewStub è una View che non ha dimensioni, non viene disegnata e che quindi non viene considerata in nessun modo all’interno del nostro layout. In pratica l’unica cosa che facciamo è dichiarare la sua esistenza per poterla poi usare in seguito quando ne avremo bisogno ! Il beneficio di usare una ViewStub è quello di non appesantire il sistema nella creazione di nuovi elementi a runtime, un po’ come la tecnica del lazy loading delle immagini,che spopola nel progettazione Web 2.0

Gli attributi della ViewStub

Quello che ci serve per dichiarare una ViewStub è un android:id, cioè l’identificativo della ViewStub stessa, e un android:layout, che non è altro che il riferimento al file XML contenente il layout che andrà a “popolare” la ViewStub. Un terzo attributo è l’android:inflateId, cioè l’identificativo del file XML contenente il layout (quello specificato prima). Per il resto, larghezza e altezza ecc.. sono i classici attributi che ritroviamo nella creazione dei layout. Nel caso specifico, ho settato come android:layout_gravity il valore top, in modo da posizionare la ViewStub in alto nello schermo.
Ok direi che per ora può bastare, vedremo successivamente come gestire la ViewStub all’interno dell’Activity. Per ulteriori informazioni vi rimando alla bibliografia in fondo a questo tutorial.

Il layout del menu

Quello di seguito altro non è che il layout XML del menu vero e proprio, quello che sarà dichiarato nell’attributo android:layout della ViewStub

Sorgenti:
menu.xml
Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:background="#99000000">
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content" android:padding="20dp"
android:orientation="horizontal" android:gravity="center"
android:background="#888">
<Button android:id="@+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="Button 1" />
<Button android:id="@+id/button_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="Button 2" />
<Button android:id="@+id/button_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="Button 3" />
</LinearLayout>
</LinearLayout>

Molto semplice, due LinearLayout, uno dentro l’altro. Il secondo è quello che contiene i 3 pulsanti di esempio, mentre il primo è il nostro root Layout !
Ed ecco il trick . Nel primo LinearLayout ho settato come attributo android:background il valore “#99000000” , il quale darà il nostro tocco di stile al menu, rendendo lo sfondo trasparente (o traslucente). Ma cosa sono quei numeri ? Non è altro che il riferimento ad un colore del tipo rgb con una componente alpha-transparency, in pratica i primi due numeri -99- definiscono la alpha-transparency (a), i seguenti 2 numeri -00- la componente red (r), i successivi -00- il green (g) e infine gli ultimi due -00- il blue (b). Tradotto, ho settato lo sfondo del LinearLayout con il colore nero e un grado di trasparenza pari a 99. Provate a variare i primi due numeri (da 00 a 99) per vedere le varie differenze di trasparenza.

L’Activity principale

Ed eccoci finalmente al codice dell’Activity principale (nonché l’unica del tutorial).

Sorgenti:
StubActivity.java
Codice (Java): [Seleziona]
public class StubActivity extends Activity {
/** Called when the activity is first created. */
private View menu;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stubs);
menuInit();
}

private void menuInit() {
menu = ((ViewStub) findViewById(R.id.stub_menu)).inflate();
menu.setVisibility(View.GONE);
Button b1 = (Button) menu.findViewById(R.id.button_1);
b1.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
Toast.makeText(getApplicationContext(),
"Click on Button 1",
Toast.LENGTH_SHORT).show();
}

});
Button b2 = (Button) menu.findViewById(R.id.button_2);
b2.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
Toast.makeText(getApplicationContext(),
"Click on Button 2",
Toast.LENGTH_SHORT).show();
}

});
Button b3 = (Button) menu.findViewById(R.id.button_3);
b3.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
Toast.makeText(getApplicationContext(),
"Click on Button 3",
Toast.LENGTH_SHORT).show();
}

});
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_MENU:
int visibility = menu.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE;
menu.setVisibility(visibility);
break;
case KeyEvent.KEYCODE_BACK:
if (menu.getVisibility() == View.VISIBLE) {
menu.setVisibility(View.GONE);
} else
this.finish();
break;
default:
break;
}
return false;
}

}

Come sempre, creiamo una classe che estende Activity e settiamo la View principale con il file stubs.xml, dopodiché inizializziamo il menu.
Ho creato il metodo menuInit() proprio per fare questo, vediamo cosa fa.

Codice (Java): [Seleziona]
menu = ((ViewStub) findViewById(R.id.stub_menu)).inflate();
Ecco il tassello mancante per l’utilizzo delle ViewStub. Il metodo inflate() inserisce di fatto la ViewStub all’interno del nostro layout, restituendo il riferimento alla View che contiene il layout del menu. Da questo momento la View diventa visibile a tutti gli effetti, ecco perché con la successiva riga di codice

Codice (Java): [Seleziona]
menu.setVisibility(View.GONE);
Rimuovo la View da flusso delle View visibili a schermo, perché per il momento il menu non deve essere visibile.
Ora che abbiamo il riferimento alla View del menu, possiamo interagire con i componenti che la popolano. Nello specifico, è stato assegnato un OnClickListener ai 3 pulsanti del menu, i quali al loro click faranno apparire a video un messaggio.

Gestire il menu sull’onKeyDown

Ora che il menu è inizializzato possiamo mostrarlo e renderlo fruibile. In questo tutorial ho deciso di farlo apparire alla pressione del tasto menu del device (ma guarda il caso… ) ma nulla vieta di gestirlo diversamente. Il codice non è ottimizzato al massimo, ma d’altronde è solo un esempio.
Con queste righe di codice

Codice (Java): [Seleziona]
int visibility = menu.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE;
menu.setVisibility(visibility);

Rendo visibile o meno il menu alla pressione del tasto menu.
Dato che stiamo facendo l’override del metodo onKeyDown dell’Activity, il tasto “indietro” del device sarà ora inutilizzabile, quindi andiamo a gestire anche questo, per poter permettere l’uscita dall’applicazione nel modo tradizionale, e già che ci siamo aggiungiamo un altro tocco di stile al nostro menu, nascondendolo anche alla pressione del suddetto tasto

Codice (Java): [Seleziona]
if (menu.getVisibility() == View.VISIBLE) {
menu.setVisibility(View.GONE);
} else this.finish();

E con questo è tutto, abbiamo realizzato un menu con sfondo trasparente con il solo ausilio delle ViewStub. In questo modo l’app risulta notevolmente meno appesantita, il nostro codice è modulare e la nostra ViewStub è riusabile per altri progetti.

Bibliografia:

giovedì 7 aprile 2011

Length-prefix message framing for streams

/// <summary>
/// Maintains the necessary buffers for applying a length-prefix message framing protocol over a stream.
/// </summary>
/// <remarks>
/// <para>Create one instance of this class for each incoming stream, and assign a handler to <see cref="MessageArrived"/>. As bytes arrive at the stream, pass them to <see cref="DataReceived"/>, which will invoke <see cref="MessageArrived"/> as necessary.</para>
/// <para>If <see cref="DataReceived"/> raises <see cref="System.Net.ProtocolViolationException"/>, then the stream data should be considered invalid. After that point, no methods should be called on that <see cref="PacketProtocol"/> instance.</para>
/// <para>This class uses a 4-byte signed integer length prefix, which allows for message sizes up to 2 GB. Keepalive messages are supported as messages with a length prefix of 0 and no message data.</para>
/// <para>This is EXAMPLE CODE! It is not particularly efficient; in particular, if this class is rewritten so that a particular interface is used (e.g., Socket's IAsyncResult methods), some buffer copies become unnecessary and may be removed.</para>
/// </remarks>
public class PacketProtocol
{
/// <summary>
/// Wraps a message. The wrapped message is ready to send to a stream.
/// </summary>
/// <remarks>
/// <para>Generates a length prefix for the message and returns the combined length prefix and message.</para>
/// </remarks>
/// <param name="message">The message to send.</param>
public static byte[] WrapMessage(byte[] message)
{
// Get the length prefix for the message
byte[] lengthPrefix = BitConverter.GetBytes(message.Length);
// Concatenate the length prefix and the message
byte[] ret = new byte[lengthPrefix.Length + message.Length];
lengthPrefix.CopyTo(ret, 0);
message.CopyTo(ret, lengthPrefix.Length);
return ret;
}
/// <summary>
/// Wraps a keepalive (0-length) message. The wrapped message is ready to send to a stream.
/// </summary>
public static byte[] WrapKeepaliveMessage()
{
return BitConverter.GetBytes((int)0);
}
/// <summary>
/// Initializes a new <see cref="PacketProtocol"/>, limiting message sizes to the given maximum size.
/// </summary>
/// <param name="maxMessageSize">The maximum message size supported by this protocol. This may be less than or equal to zero to indicate no maximum message size.</param>
public PacketProtocol(int maxMessageSize)
{
// We allocate the buffer for receiving message lengths immediately
this.lengthBuffer = new byte[sizeof(int)];
this.maxMessageSize = maxMessageSize;
}
/// <summary>
/// The buffer for the length prefix; this is always 4 bytes long.
/// </summary>
private byte[] lengthBuffer;
/// <summary>
/// The buffer for the data; this is null if we are receiving the length prefix buffer.
/// </summary>
private byte[] dataBuffer;
/// <summary>
/// The number of bytes already read into the buffer (the length buffer if <see cref="dataBuffer"/> is null, otherwise the data buffer).
/// </summary>
private int bytesReceived;
/// <summary>
/// The maximum size of messages allowed.
/// </summary>
private int maxMessageSize;
/// <summary>
/// Indicates the completion of a message read from the stream.
/// </summary>
/// <remarks>
/// <para>This may be called with an empty message, indicating that the other end had sent a keepalive message. This will never be called with a null message.</para>
/// <para>This event is invoked from within a call to <see cref="DataReceived"/>. Handlers for this event should not call <see cref="DataReceived"/>.</para>
/// </remarks>
public Action<byte[]> MessageArrived { get; set; }
/// <summary>
/// Notifies the <see cref="PacketProtocol"/> instance that incoming data has been received from the stream. This method will invoke <see cref="MessageArrived"/> as necessary.
/// </summary>
/// <remarks>
/// <para>This method may invoke <see cref="MessageArrived"/> zero or more times.</para>
/// <para>Zero-length receives are ignored. Many streams use a 0-length read to indicate the end of a stream, but <see cref="PacketProtocol"/> takes no action in this case.</para>
/// </remarks>
/// <param name="data">The data received from the stream. Cannot be null.</param>
/// <exception cref="System.Net.ProtocolViolationException">If the data received is not a properly-formed message.</exception>
public void DataReceived(byte[] data)
{
// Process the incoming data in chunks, as the ReadCompleted requests it
// Logically, we are satisfying read requests with the received data, instead of processing the
// incoming buffer looking for messages.
int i = 0;
while (i != data.Length)
{
// Determine how many bytes we want to transfer to the buffer and transfer them
int bytesAvailable = data.Length - i;
if (this.dataBuffer != null)
{
// We're reading into the data buffer
int bytesRequested = this.dataBuffer.Length - this.bytesReceived;
// Copy the incoming bytes into the buffer
int bytesTransferred = Math.Min(bytesRequested, bytesAvailable);
Array.Copy(data, i, this.dataBuffer, this.bytesReceived, bytesTransferred);
i += bytesTransferred;
// Notify "read completion"
this.ReadCompleted(bytesTransferred);
}
else
{
// We're reading into the length prefix buffer
int bytesRequested = this.lengthBuffer.Length - this.bytesReceived;
// Copy the incoming bytes into the buffer
int bytesTransferred = Math.Min(bytesRequested, bytesAvailable);
Array.Copy(data, i, this.lengthBuffer, this.bytesReceived, bytesTransferred);
i += bytesTransferred;
// Notify "read completion"
this.ReadCompleted(bytesTransferred);
}
}
}
/// <summary>
/// Called when a read completes. Parses the received data and calls <see cref="MessageArrived"/> if necessary.
/// </summary>
/// <param name="count">The number of bytes read.</param>
/// <exception cref="System.Net.ProtocolViolationException">If the data received is not a properly-formed message.</exception>
private void ReadCompleted(int count)
{
// Get the number of bytes read into the buffer
this.bytesReceived += count;
if (this.dataBuffer == null)
{
// We're currently receiving the length buffer
if (this.bytesReceived != sizeof(int))
{
// We haven't gotten all the length buffer yet: just wait for more data to arrive
}
else
{
// We've gotten the length buffer
int length = BitConverter.ToInt32(this.lengthBuffer, 0);
// Sanity check for length < 0
if (length < 0)
throw new System.Net.ProtocolViolationException("Message length is less than zero");
// Another sanity check is needed here for very large packets, to prevent denial-of-service attacks
if (this.maxMessageSize > 0 && length > this.maxMessageSize)
throw new System.Net.ProtocolViolationException("Message length " + length.ToString(System.Globalization.CultureInfo.InvariantCulture) + " is larger than maximum message size " + this.maxMessageSize.ToString(System.Globalization.CultureInfo.InvariantCulture));
// Zero-length packets are allowed as keepalives
if (length == 0)
{
this.bytesReceived = 0;
if (this.MessageArrived != null)
this.MessageArrived(new byte[0]);
}
else
{
// Create the data buffer and start reading into it
this.dataBuffer = new byte[length];
this.bytesReceived = 0;
}
}
}
else
{
if (this.bytesReceived != this.dataBuffer.Length)
{
// We haven't gotten all the data buffer yet: just wait for more data to arrive
}
else
{
// We've gotten an entire packet
if (this.MessageArrived != null)
this.MessageArrived(this.dataBuffer);
// Start reading the length buffer again
this.dataBuffer = null;
this.bytesReceived = 0;
}
}
}
}

martedì 22 marzo 2011

Color Picker



color_picker_seekbar_r.xml
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ff000000"
android:centerY="0.5"
android:endColor="#ffff0000"
android:angle="0"
/>
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ff000000"
android:centerY="0.5"
android:endColor="#ffff0000"
android:angle="0"
/>
</shape>
</clip>
</item>
</layer-list>


color_picker_seekbar_g.xml
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ff000000"
android:centerY="0.5"
android:endColor="#ff00ff00"
android:angle="0"
/>
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ff000000"
android:centerY="0.5"
android:endColor="#ff00ff00"
android:angle="0"
/>
</shape>
</clip>
</item>
</layer-list>
color_picker_seekbar_b.xml
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ff000000"
android:centerY="0.5"
android:endColor="#ff0000ff"
android:angle="0"
/>
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ff000000"
android:centerY="0.5"
android:endColor="#ff0000ff"
android:angle="0"
/>
</shape>
</clip>
</item>
</layer-list>
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button android:id="@+id/changeTextColorButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Change Text Color"
/>
<Button android:id="@+id/changeBackgroundColorButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Change Background Color"
/>
<TextView android:id="@+id/sampleTextView1"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:gravity="center_vertical|center_horizontal"
android:textSize="20dp"
android:text="Sample1"/>
</LinearLayout>
dialog_picker.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="4dp"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="@string/color_picker_viewer"/>
<TextView android:id="@+id/colorPickerViewer"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"/>
<TextView android:id="@+id/colorPickerTextR"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingTop="5dp"/>
<SeekBar android:id="@+id/colorPickerSeekBarR"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:max="255"
android:padding="8dp"
android:progressDrawable="@drawable/color_picker_seekbar_r"/>
<TextView android:id="@+id/colorPickerTextG"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"/>
<SeekBar android:id="@+id/colorPickerSeekBarG"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:max="255"
android:padding="8dp"
android:progressDrawable="@drawable/color_picker_seekbar_g"/>
<TextView android:id="@+id/colorPickerTextB"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"/>
<SeekBar android:id="@+id/colorPickerSeekBarB"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:max="255"
android:padding="8dp"
android:progressDrawable="@drawable/color_picker_seekbar_b" />
</LinearLayout>
dialog_selecter.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<GridView android:id="@+id/colorSelectGridView"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:verticalSpacing="6dp"
android:horizontalSpacing="6dp"
android:numColumns="4"/>
</LinearLayout>
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, ColorSelectDialog!</string>
<string name="app_name">Color Select Dialog</string>
<string name="color_picker_viewer">Color Viewer(Click to select 16Color)</string>
<string name="color_picker_red">RED</string>
<string name="color_picker_green">GREEN</string>
<string name="color_picker_blue">BLUE</string>
</resources>
ColorSelectDialog.java
package jp.hiro711.ColorSelectDialog;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class ColorSelectDialog extends Activity {
final int CHANGE_TEXT = 0;
final int CHANGE_BACKGROUND = 1;

final int COLOR_TABLE[] = {
0xffffffff, 0xffc0c0c0, 0xff808080, 0xff000000,
0xffffc0c0, 0xffff6060, 0xffff0000, 0xff800000,
0xffffe0c0, 0xffffb060, 0xffff8000, 0xff804000,
0xffffffc0, 0xffffff60, 0xffffff00, 0xff808000,
0xffe0ffc0, 0xffb0ff60, 0xff80ff00, 0xff408000,
0xffc0ffc0, 0xff60ff60, 0xff00ff00, 0xff008000,
0xffc0ffe0, 0xff60ffb0, 0xff00ff80, 0xff008040,
0xffc0ffff, 0xff60ffff, 0xff00ffff, 0xff008080,
0xffc0e0ff, 0xff60b0ff, 0xff0080ff, 0xff004480,
0xffc0c0ff, 0xff6060ff, 0xff0000ff, 0xff000080,
0xffe0c0ff, 0xffb060ff, 0xff8000ff, 0xff400080,
0xffffc0ff, 0xffff60ff, 0xffff00ff, 0xff800080,
0xffffc0e0, 0xffff60b0, 0xffff0080, 0xff800040
};

int mColor = 0xffffffff;
int mTextColor = 0xffc0c0c0;
int mBackgroundColor = 0xff000000;

LayoutInflater inflater;
View dialogView;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

final Button button1 = (Button)findViewById(R.id.changeTextColorButton);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mColor = mTextColor;
colorDialog(CHANGE_TEXT);
}
});
final Button button2 = (Button)findViewById(R.id.changeBackgroundColorButton);
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mColor = mBackgroundColor;
colorDialog(CHANGE_BACKGROUND);
}
});
}

private void colorDialog(final int where) {
final String rString = getResources().getString(R.string.color_picker_red);
final String gString = getResources().getString(R.string.color_picker_green);
final String bString = getResources().getString(R.string.color_picker_blue);

inflater = LayoutInflater.from(this);
dialogView = inflater.inflate(R.layout.dialog_picker, null);

final TextView textR = (TextView)dialogView.findViewById(R.id.colorPickerTextR);
textR.setText(String.format("%s(%02X)", rString, (mColor & 0x00ff0000) >> 16));
final TextView textG = (TextView)dialogView.findViewById(R.id.colorPickerTextG);
textG.setText(String.format("%s(%02X)", gString, (mColor & 0x0000ff00) >> 8));
final TextView textB = (TextView)dialogView.findViewById(R.id.colorPickerTextB);
textB.setText(String.format("%s(%02X)", bString, (mColor & 0x000000ff)));
final TextView viewer = (TextView)dialogView.findViewById(R.id.colorPickerViewer);
viewer.setBackgroundColor(mColor);
viewer.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
showDialog(0);
}
});

final SeekBar seekBarR = (SeekBar)dialogView.findViewById(R.id.colorPickerSeekBarR);
seekBarR.setProgress((mColor & 0x00ff0000) >>16);
seekBarR.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int value = seekBar.getProgress();
textR.setText(String.format("%s(%02X)", rString, value));
mColor = (mColor & 0xff00ffff) | value << 16;
viewer.setBackgroundColor(mColor);
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
int value = seekBar.getProgress();
textR.setText(String.format("%s(%02X)", rString, value));
mColor = (mColor & 0xff00ffff) | value << 16;
viewer.setBackgroundColor(mColor);
}

@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
int value = seekBar.getProgress();
textR.setText(String.format("%s(%02X)", rString, value));
mColor = (mColor & 0xff00ffff) | value << 16;
viewer.setBackgroundColor(mColor);
}
});
final SeekBar seekBarG = (SeekBar)dialogView.findViewById(R.id.colorPickerSeekBarG);
seekBarG.setProgress((mColor & 0x0000ff00) >> 8);
seekBarG.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int value = seekBar.getProgress();
textG.setText(String.format("%s(%02X)", gString, value));
mColor = (mColor & 0xffff00ff) | value << 8;
viewer.setBackgroundColor(mColor);
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
int value = seekBar.getProgress();
textG.setText(String.format("%s(%02X)", gString, value));
mColor = (mColor & 0xffff00ff) | value << 8;
viewer.setBackgroundColor(mColor);
}

@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
int value = seekBar.getProgress();
textG.setText(String.format("%s(%02X)", gString, value));
mColor = (mColor & 0xffff00ff) | value << 8;
viewer.setBackgroundColor(mColor);
}
});
final SeekBar seekBarB = (SeekBar)dialogView.findViewById(R.id.colorPickerSeekBarB);
seekBarB.setProgress((mColor & 0x000000ff));
seekBarB.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int value = seekBar.getProgress();
textB.setText(String.format("%s(%02X)", bString, value));
mColor = (mColor & 0xffffff00) | value;
viewer.setBackgroundColor(mColor);
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
int value = seekBar.getProgress();
textB.setText(String.format("%s(%02X)", bString, value));
mColor = (mColor & 0xffffff00) | value;
viewer.setBackgroundColor(mColor);
}

@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
int value = seekBar.getProgress();
textB.setText(String.format("%s(%02X)", bString, value));
mColor = (mColor & 0xffffff00) | value;
viewer.setBackgroundColor(mColor);
}
});
final AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setView(dialogView);
alert.setPositiveButton("OK", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int idx) {
switch(where) {
case CHANGE_TEXT:
mTextColor = mColor;
final TextView textView0 = (TextView)findViewById(R.id.sampleTextView1);
textView0.setTextColor(mTextColor);
break;
case CHANGE_BACKGROUND:
mBackgroundColor = mColor;
final TextView textView1 = (TextView)findViewById(R.id.sampleTextView1);
textView1.setBackgroundColor(mBackgroundColor);
break;
}
}
});
alert.show();
}

@Override
protected Dialog onCreateDialog(int id) {
if(id == 0) {
final String rString = getResources().getString(R.string.color_picker_red);
final String gString = getResources().getString(R.string.color_picker_green);
final String bString = getResources().getString(R.string.color_picker_blue);

LayoutInflater inflater1 = LayoutInflater.from(this);
final View dialogView1 = inflater1.inflate(R.layout.dialog_selecter, null);

final GridView gridView = (GridView)dialogView1.findViewById(R.id.colorSelectGridView);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
view.setBackgroundColor(COLOR_TABLE[position]);
return view;
}
};
for(int i = 0; i<COLOR_TABLE.length; i++) {
adapter.add("");
}
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
mColor = COLOR_TABLE[arg2];
final TextView textR = (TextView)dialogView.findViewById(R.id.colorPickerTextR);
textR.setText(String.format("%s(%02X)", rString, (mColor & 0x00ff0000) >> 16));
final TextView textG = (TextView)dialogView.findViewById(R.id.colorPickerTextG);
textG.setText(String.format("%s(%02X)", gString, (mColor & 0x0000ff00) >> 8));
final TextView textB = (TextView)dialogView.findViewById(R.id.colorPickerTextB);
textB.setText(String.format("%s(%02X)", bString, (mColor & 0x000000ff)));
final TextView viewer = (TextView)dialogView.findViewById(R.id.colorPickerViewer);
viewer.setBackgroundColor(mColor);
final SeekBar seekBarR = (SeekBar)dialogView.findViewById(R.id.colorPickerSeekBarR);
seekBarR.setProgress((mColor & 0x00ff0000) >>16);
final SeekBar seekBarG = (SeekBar)dialogView.findViewById(R.id.colorPickerSeekBarG);
seekBarG.setProgress((mColor & 0x0000ff00) >> 8);
final SeekBar seekBarB = (SeekBar)dialogView.findViewById(R.id.colorPickerSeekBarB);
seekBarB.setProgress((mColor & 0x000000ff));
dismissDialog(0);
}
});

return new AlertDialog.Builder(this)
.setView(dialogView1)
.setNegativeButton("Cancel", null)
.create();
}
return super.onCreateDialog(id);
}
}