Creación de un juego 3-en-raya (tic-tac-toe, el gato) para dos jugadores locales, que permite la introducción de los nombres de los jugares y cuente con un historial de partidas jugadas.
Este video fue grabado en vivo del curso básico de desarrollo de aplicaciones Android el 2016. Algunas cosas pueden haber cambiado y/o desarrolladas de la forma más sencilla posible, aún así, es buena referencia para quienes que inician en Android y/o programación.
Aprenderás
- Crear tu primera aplicación Android en Android Studio
 - Usar recursos Material Design, colores recomendados, etc.
 - Crear un adaptador para un 
RecyclerView 
Colores
Colores para el texto
Colores usados en el vídeo:
<color name="colorPrimaryText">#DE000000</color>
<color name="colorSecondaryText">#8A000000</color>
<color name="colorDisabledText">#61000000</color>
    
<color name="colorPrimaryDarkText">#FFFFFF</color>
<color name="colorSecondaryDarkText">#B3FFFFFF</color>
<color name="colorDisabledDarkText">#80FFFFFF</color>
Colores del tema
Colores usados en el video:
<color name="colorPrimary">#00BCD4</color>
<color name="colorPrimaryDark">#0097A7</color>
<color name="colorAccent">#FFD740</color>
Dependencias
Minuto 0:52
Para usar componentes Material Design.
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
compile 'com.android.support:cardview-v7:23.4.0'
compile 'com.android.support:recyclerview-v7:23.4.0'
Diseño
Minuto 1:05
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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="vertical"
    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="tech.alvarez.tresenraya.MainActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <EditText
            android:id="@+id/jugador1EditText"
            android:layout_width="0dp"
            android:layout_height="48dp"
            android:layout_weight="1"
            android:hint="@string/jugador1" />
        <EditText
            android:id="@+id/jugador2EditText"
            android:layout_width="0dp"
            android:layout_height="48dp"
            android:layout_weight="1"
            android:hint="@string/jugador2" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal">
        <Button
            android:id="@+id/unoButton"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:onClick="presionar1"
            android:textSize="50sp" />
        <Button
            android:id="@+id/dosButton"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:onClick="presionar2"
            android:textSize="50sp" />
        <Button
            android:id="@+id/tresButton"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:onClick="presionar3"
            android:textSize="50sp" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal">
        <Button
            android:id="@+id/cuatroButton"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:onClick="presionar4"
            android:textSize="50sp" />
        <Button
            android:id="@+id/cincoButton"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:onClick="presionar5"
            android:textSize="50sp" />
        <Button
            android:id="@+id/seisButton"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:onClick="presionar6"
            android:textSize="50sp" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal">
        <Button
            android:id="@+id/sieteButton"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:onClick="presionar7"
            android:textSize="50sp" />
        <Button
            android:id="@+id/ochoButton"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:onClick="presionar8"
            android:textSize="50sp" />
        <Button
            android:id="@+id/nueveButton"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:onClick="presionar9"
            android:textSize="50sp" />
    </LinearLayout>
    <android.support.v7.widget.RecyclerView
        android:id="@+id/historialRecyclerView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>
Si bien se podría usar otros componentes como
GridViewen lugar de variosLinearLayouts.
Activity
Minuto 5:09
Referencias
private EditText jugador1EdiText;
private EditText jugador2EdiText;
private Button unoButton;
private Button dosButton;
private Button tresButton;
private Button cuatroButton;
private Button cincoButton;
private Button seisButton;
private Button sieteButton;
private Button ochoButton;
private Button nueveButton;
private RecyclerView historialRecyclerView;
onCreate()
jugador1EdiText = (EditText) findViewById(R.id.jugador1EditText);
jugador2EdiText = (EditText) findViewById(R.id.jugador2EditText);
unoButton = (Button) findViewById(R.id.unoButton);
dosButton = (Button) findViewById(R.id.dosButton);
tresButton = (Button) findViewById(R.id.tresButton);
cuatroButton = (Button) findViewById(R.id.cuatroButton);
cincoButton = (Button) findViewById(R.id.cincoButton);
seisButton = (Button) findViewById(R.id.seisButton);
sieteButton = (Button) findViewById(R.id.sieteButton);
ochoButton = (Button) findViewById(R.id.ochoButton);
nueveButton = (Button) findViewById(R.id.nueveButton);
historialRecyclerView = (RecyclerView) findViewById(R.id.historialRecyclerView);
onClick para los botones
La acción para los botones se generan automáticamente presionando Alt+Enter y escoger la generación del método.
Acciones
Minuto 8:21
Variable global para detectar si toca X
private boolean tocaX = true;
Método de un botón
if (unoButton.getText().toString().equals("")) {
    if (tocaX) {
        unoButton.setText("X");
    } else {
        unoButton.setText("O");
    }
    tocaX = !tocaX;
}
Método gano
Minuto 10:53
public boolean gano(String simbolo) {
    boolean siHayGanador = false;
    if (unoButton.getText().equals(simbolo) && dosButton.getText().equals(simbolo) && tresButton.getText().equals(simbolo)) {
        siHayGanador = true;
    }
    if (unoButton.getText().equals(simbolo) && cuatroButton.getText().equals(simbolo) && sieteButton.getText().equals(simbolo)) {
        siHayGanador = true;
    }
    if (unoButton.getText().equals(simbolo) && cincoButton.getText().equals(simbolo) && nueveButton.getText().equals(simbolo)) {
        siHayGanador = true;
    }
    if (cuatroButton.getText().equals(simbolo) && cincoButton.getText().equals(simbolo) && seisButton.getText().equals(simbolo)) {
        siHayGanador = true;
    }
    if (tresButton.getText().equals(simbolo) && seisButton.getText().equals(simbolo) && nueveButton.getText().equals(simbolo)) {
        siHayGanador = true;
    }
    if (sieteButton.getText().equals(simbolo) && ochoButton.getText().equals(simbolo) && nueveButton.getText().equals(simbolo)) {
        siHayGanador = true;
    }
    if (tresButton.getText().equals(simbolo) && cincoButton.getText().equals(simbolo) && sieteButton.getText().equals(simbolo)) {
        siHayGanador = true;
    }
    if (dosButton.getText().equals(simbolo) && cincoButton.getText().equals(simbolo) && ochoButton.getText().equals(simbolo)) {
        siHayGanador = true;
    }
    return siHayGanador;
}
Verificar si ganó
Minuto 13:30
Método verificarSiGano
public void verificarSiGano(String simbolo) {
    if (gano(simbolo)) {
        Toast.makeText(getApplicationContext(), "Gano " + simbolo + "!!!", Toast.LENGTH_SHORT).show();
        String nombreJugador1 = jugador1EdiText.getText().toString();
        String nombreJugador2 = jugador2EdiText.getText().toString();
        int quienGano = 0;
        if (simbolo == "X") {
            quienGano = 1;
        }
        if (simbolo == "O") {
            quienGano = 2;
        }
        Date fechaActual = Calendar.getInstance().getTime();
        Partida partida = new Partida(nombreJugador1, nombreJugador2, quienGano, fechaActual);
        partidasAdapter.add(partida);
        limpiar();
    }
}
Adapter
Minuto 14:52
Clase Partida
public class Partida {
    private String nombreJugador1;
    private String nombreJugador2;
    private int quienGano;
    private Date fecha;
    // lo demás se genera con Android Studio
}
Adapter
public class PartidasAdapter extends RecyclerView.Adapter<PartidasAdapter.ViewHolder> {
    private ArrayList<Partida> dataset;
    public PartidasAdapter() {
        dataset = new ArrayList<>();
    }
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_partida, parent, false);
        return new ViewHolder(view);
    }
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Partida partida = dataset.get(position);
        if (partida.getQuienGano() == 1) {
            holder.tituloTextView.setText(partida.getNombreJugador1());
        } else {
            holder.tituloTextView.setText(partida.getNombreJugador2());
        }
        holder.subtituloTextView.setText(darFormato(partida.getFecha()));
    }
    @Override
    public int getItemCount() {
        return dataset.size();
    }
    public static String darFormato(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("ddMMMyyyy hh:mm");
        return simpleDateFormat.format(date).toUpperCase();
    }
    public static class ViewHolder extends RecyclerView.ViewHolder {
        TextView tituloTextView;
        TextView subtituloTextView;
        public ViewHolder(View itemView) {
            super(itemView);
            tituloTextView = (TextView) itemView.findViewById(R.id.tituloTextView);
            subtituloTextView = (TextView) itemView.findViewById(R.id.subtituloTextView);
        }
    }
    public void add(Partida partida) {
        dataset.add(partida);
        notifyDataSetChanged();
    }
    public void clear() {
        dataset.clear();
        notifyDataSetChanged();
    }
}
Diseño Item Partida
Minuto 16:10
item_partida.xml
Aún se deben adicionar los IDs.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="72dp"
    android:orientation="horizontal"
    android:paddingBottom="8dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="8dp">
    <ImageView
        android:layout_width="24dp"
        android:layout_height="24dp"
        android:layout_gravity="center_vertical"
        android:src="@mipmap/ic_launcher" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="vertical"
        android:paddingLeft="32dp"
        android:paddingRight="16dp">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/app_name"
            android:textColor="@color/colorPrimaryText"
            android:textSize="16sp" />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/app_name"
            android:textColor="@color/colorSecondaryText"
            android:textSize="14sp" />
    </LinearLayout>
</LinearLayout>
Formato para fechas
Minuto 17:39
Obtener fecha actual
Date fechaActual = Calendar.getInstance().getTime();
Dar formato a una fecha
public static String darFormato(Date date) {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("ddMMMyyyy hh:mm");
    return simpleDateFormat.format(date).toUpperCase();
}
Limpiar
Minuto 19:52
Método limpiar
private void limpiar() {
    unoButton.setText("");
    dosButton.setText("");
    tresButton.setText("");
    cuatroButton.setText("");
    cincoButton.setText("");
    seisButton.setText("");
    sieteButton.setText("");
    ochoButton.setText("");
    nueveButton.setText("");
}
También puede usarse
setText(null)
Código
Código completo de la aplicación: