dimarts, 16 de febrer del 2016

OpenGL

Android incluye soporte para alto rendimiento en 2D y gráficos 3D con la biblioteca de gráficos abierta (OpenGL), en concreto, la API OPENGL es una api de gráficos de plataforma cruzada que esepcifica una interfície de programario estándar para el maquinario de proceso de gráficos 3D. OPENGL es una adaptación de la especificación OpenGL destinada a dispositivos encastados.
Android es compatible con varias versiones de la API OpenGL.
Es una api que especifica como se hacen los modelos 3D... hay un jugador que mira al mundo, todo esta compuesto por triángulos, las matrices de trabajo están perfectamente definidas, forma parte de kronos, lo hicieron para los sistemas 3D.
Kronos es una fundación con ánimo de lucro, todo es libre pero se ganan dinero por el hardware. Se creó en lenguaje C, es de estado secuencial y trabaja matricialmente, era un c sin complicaciones porque estaba pensado para código máquina. La gracia es que el algoritmo de cálculo de una superficie la puede hacer o bien el hardware y si este no lo tiene implementado lo hace el software.
Entonces si tienes un programa que tiene que hacer iluminación, hay que tener en cuenta que el hardware es mucho más rápido que usar el software.
Hay varias versiones, estas hacen referencia al OpenGL a dispositivos móviles, el webGL es con javascript con navegador y unicamente OpenGL para los PCs de mesa, como Windows, Linux, Apple...
Las diferentes y más relevantes versiones de OpenGL serian:
  • OpenGL ES 1.0 y 1.1 - especificación API con soporte de android 1.0 y superior.
  • OpenGL ES 2.0 - especificación API soportado por Android 2.2 (nivel de API 8) 4.3 y superior.
  • OpenGL ES 3.0 - especificación API con soporte para android (nivel de API 18) 4.3 y superior.
L'API especifica proporcionada por Android es similar a la API J2ME JSR239 OpenGL ES, pero no es idéntica.

Hay dos clases fundamentales en Android que te permite crear y manipular gráficos con la API OpenGL ES:
  • GL.SurfaceView.
  • GL.SurfaceView.Renderer.

GL.SurfaceView

Esta clase es una View donde se puede dibujar y manipular objetos mediante llamadas a la API de OpenGL y es similar en función a un  . Se puede utilizar esta clase mediante la creación de una instancia de GLSurfaceView y añadiendo su Renderer en ella. No obstante, si queremos capturar desarrollos de pantalla táctil, se ha de ampliar la clase. GLSurfaceView para implementar los oyentes táctiles.
El GLSurfaceView es una vista especial que gestiona superficies OpenGL para nosotros y dibuja en el sistema de visión de Android. También añade una gran cantidad de características que hacen que sea más fácil de usar OpenGL, incluyendo pero no limitado a:
  • Proporciona un subproceso de representación dedicada para OpenGL porque no afecte al fin principal.
  • Nos permite dibujar siempre que queramos.
  • Se ocupa de la configuración de pantalla para nosotros, utilizando EGL, la interfície entre OpenGL y el sistema de ventanas subyacente.
Esencialmente tendremos una vista, igual que tenemos botones, imagenes y textView, tendremos un GLSurfaceView, todo lo que se dibuje ahí irá por hardware. Para utilizar OpenGL se recomiendan las APIS de java, OpenGL esta especificado en C, pero son cáculos matriciales por lo tanto no hay centenares de líneas de código, sino que son productos transformados que pueden llevar a cualquier lenguaje de programación. Con cualquier lenguaje de programación puedes hacerlo.

GLSurfaceView.Renderer

Aquesta interfície define los métodos necesarios para dibujar gráficos en un GLSurfaceView. Se tiene que proporcionar una implementación de esta interfície con una clase separada y adjuntarla a la instancia GLSurfaceView utilizando GLSurfaceView.setRenderer().
Requiere que implemente los métodos siguientes:
  • onSurfaceCreated(): El sistema llama a este método una vez, en crear el GLSurfaceView. Utilizad este método para llevar acciones que tienen que ocurrir solamente una vez, como configurar los parámetros del entorno OpenGL o el inicio de objetos gráficos OpenGL.
  • onDrawFrame(): El sistema llama a este método en cada redibujo del GLSurfaceView. Utilizad estos métodos como principal punto de ejecución para elaborar (y redibujar) objetos gráficos.
  • onSurfaceChanged(): El sistema llama a este método cuando los GLSurfaceView cambian de geometría, incluyendo cambios en el tamaño del GLSurfaceView o la orientación de la pantalla del dispositivo. Por ejemplo el sistema que llama a este método cuando el dispositivo cambia de vertical a horizontal. Utilizad este método para responder los cambios en el GLSurfaceView contenedor.
 Si la aplicación utiliza funciones de OpenGL que no estan disponibles en todos los dispositivos tiene que incluir estos requisitos dentro del archivo AndroidManifest.xml:
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<uses-feature android:glEsVersion="0x00030000" android:required="true" />

API OpenGL ES 3.0 es compatible con la 2.0, lo que significa que puede ser mas flexible con su implementación de OpenGL ES en la aplicación. Declarar OpenGL 2.0 es un requisito, y al comprobar la disponibilidad de la API 3.0 en tiempo de ejecución, si es compatible, utilizará esta.
Ejemplo de  código:
@Override
public void onCreate(Bundle savedInstanceState)
   {
   super.onCreate(savedInstanceState);
   mGLSurfaceView = new GLSurfaceView(this);
   // soporta OpenGL ES 2.0?
   final ActivityManager activityManager = (ActivityManager)
   getSystemService(Context.ACTIVITY_SERVICE);
   final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
   final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
   if (supportsEs2){
      // contexto compatible
      mGLSurfaceView.setEGLContextClientVersion(2);
      mGLSurfaceView.setRenderer(new NuestroRenderer());
   } else{
      // Usar OpenGL ES 1, por ejemplo
   }
   //utilizamos toda el area de la activity
   setContentView(mGLSurfaceView);
}

Antes de que nuestro procesador muestre algo, necesitamos algo que mostrar. En OpenGL ES 2, especificamos matrices de nombres. Estos números pueden representar posiciones, colores, o cualquier otra cosa. En esta demo mostraremos tres triángulos.

// Los datos estan guardados en buffer de tipo float.
private final FloatBuffer mTriangle1Vertices;
private final FloatBuffer mTriangle2Vertices;
private final FloatBuffer mTriangle3Vertices;
//nombre de bytes per float
private final int mBytesPerFloat = 4;
//Inicialitzatció.
public NuestroRenderer(){
   final float[] triangle1VerticesData= {
      // X, Y, Z,
      // R, G, B, A
      -0.5f, -0.25f, 0.0f,
      1.0f, 0.0f, 0.0f, 1.0f,

      0.5f, -0.25f, 0.0f,
      0.0f, 0.0f, 1.0f, 1.0f,

      0.0f, 0.559016994f, 0.0f,
      0.0f, 1.0f, 0.0f, 1.0f
   }
   // Inicialización de los buffers.
   mTriangle1Vertices = ByteBuffer.allocateDirect(triangle1VerticesData.length *    mBytesPerFloat).order(ByteOrder.nativeOrder()).asFloatBuffer();
   ...
   mTriangle1Vertices.put(triangle1VerticesData).position(0);
   ...
}

Es normal que la codificación este en Java en Android, pero la implementación interna de OpenGL ES 2 esta escrita en C. Antes de pasar nuestros datos por OpenGL, tenemos que convertirlo a un formato que se puedan entender. Java y el sistema operativo nativo podría no guardar sus bytes en el mismo orden, así que hace falta utilizar un conjunto especial de clases de amortiguación y crear un ByteBuffer suficientemente grande como para mantener, entre nuestros datos, y decirle que para guardar los datos utilizando la orden de bytes nativo. Entonces los convertimos en un FloatBuffer, para que podamos hacerlo servir para guardar los datos de punto flotante. Finalmente, copiamos nuestra matriz en la memoria intermedia.

Apuntes.
Ejemplo.















Reproducción de medios

Una buena experiencia de usuario es imprescindible.
Las aplicaciones multimedia tienen que ofrecer a los usuarios poder controlar el volumen de su aplicación utilizando el hardware o el software de control del volumen del dispositivo, auriculares bluetooth, o los auriculares.
De la misma manera, tiene que ser posible parar, pausar, saltar... Los medios que se están reproduciendo.
Android mantiene un flujo (mediaplayer) de audio para cada medio, notificación, llamada... que hay en el dispositivo. Se puede controlar el volumen de cada uno por separado.
La mayoría de estos flujos responden a STREAM_MUSIC, otros corresponderían como flujos del sistema, como la alarma.
Por defecto, poner las teclas del dispositivo cambia el volumen del flujo activo. Si el dispositivo no esta reproduciendo nada cambia el volumen de la llamada.
Mediante setVolumeControlStream() se puede cambiar el volumen del audio que se esta reproduciendo.
setVolumeControlStream(AudioManager.STREAM_MUSIC);
Hace que al pulsar las teclas de volumen funcionen como se espere.
Para esto, necesitaremos los permisos:
<uses-permission android:name="android.permission.WAKE_LOCK" />
Disponemos de la posibilidad de que responda a las teclas de pausa, reproducción... para que sea nuestra app la que lo controle, necesitará el broadcast, dentro del manifest, sería el broadcast que escuchamos. Normalmente lo lanza el sistema, nosotros normalmente usamos RemoteControlReceiver.
<receiver android:name=".RemoteControlReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
tendremos la clase broadcastReceiver que es y le hacemos hacer la acción.
y el receptor extrae la tecla que se tiene que pulsar de la siguiente manera:
public class Receptor extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
   if (
      Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())){
         KeyEvent event =(KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
      if (KeyEvent.KEYCODE_MEDIA_PLAY == event.getKeyCode()){
          // tecla pulsada
         }
      }
   }
}
Android utiliza el foco de audio para moderar cuando diversas apps están reproduciendo medios. Antes que una app inicie la reproducción tiene que pedir y recibir el foco. Con requestAudioFocus() podremos pedir el foco y devolverá AUDIOFOCUS_REQUEST_GRANTED si lo ha conseguido.
Hace falta especificar que flujo se esta utilizando y si será puntual o permanente la petición, por ejemplo un aviso o reproducción de música.
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
// petición del foco para reproducir música
int result = am.requestAudioFocus(afChangeListener,
   // utiliza un flujo de música
   AudioManager.STREAM_MUSIC,
   // petición permanente
   AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
   am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
   // comienza la reproducción.
}
Cada vez que cambia el foco, cambia el changelistener y le podemos decir lo que tiene que hacer.
Cada vez que la aplicación que roba el foco se dispara:
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
este va a buscar si hay alguna cosa programada.
Una vez finaliza la reproducción hace falta liberar el foco de audio con abandonAudioFocus().am.abandonAudioFocus(afChangeListener);
Esta la posibilidad de que el volumen quede bajo hasta que se vuelva a poner el foco en la app inicial, por ejemplo un navegador de rutas para un vehículo, esto se hace con:
int result = am.requestAudioFocus(afChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
);

También podemos gestionar cuando un foco cambia de app:

// gestión cuando se pierde el foco, el cual depende de la manera como se pierde.
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
// Pausa
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Sigue reproduciendo.
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
am.abandonAudioFocus(afChangeListener);
// Para.
}
}
};


Reducir el volumen (ducking) nos permite puntualmente reducir el volumen cuando una app tiene el foco de audio sin parar la reproducción.

OnAudioFocusChangeListener afChangeListener = new
OnAudioFocusChangeListener() {
   public void onAudioFocusChange(int focusChange) {
      if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
         // Baja el volumen
      } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
         // Sube el volumen
      }
   }
};

Los usuarios pueden disponer de altavoces, auriculares, etc, y hace falta saber como conectar y gestionar cada uno de estos dispositivos.
Para saber que dispositivos se están utilizando, utilizaremos la clase AudioManager.
if (isBluetoothA2dpOn()) {
   //ajustamos para Bluetooth.
} else if (isSpeakerphoneOn()) {
   // ajustamos para altavoz
} else if (isWiredHeadsetOn()) {
   // ajustamos para auriculares
} else { 

   // no hay ninguna salida para escuchar el audio.
}
En el caso de cambiar alguno de estos dispositivos podemos tener problemas con el volumen. Dispondremos de una señal que se envía a las aplicaciones ACTION_AUDIO_BECOMING_NOISY para controlar estos casos.

private class Receptor extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {

   if(AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())){
      // Hacemos una pausa
      }
   }
}
private IntentFilter intentFilter = new
IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
private void startPlayback() {
   registerReceiver(myNoisyAudioStreamReceiver(), intentFilter);
}
private void stopPlayback() {
   unregisterReceiver(myNoisyAudioStreamReceiver);
}



1. Desarrolla una aplicación para Android que reproduzca una pista de música almacenada en los recursos del dispositivo. La aplicación debe disponer de botones para parar, pausar e iniciar la pista de música. Debe mostrar el tiempo de reproducción.
Solución.
Proyecto en Android Studio.
2. A partir del ejercicio anterior, crea un servicio en primer plano que realice la reproducción de música mostrando con una notificación de información al usuario en la barra de estado.
Solución.
3. Crea una aplicación móvil para Android que permita acceder a los contenidos de música de tu dispositivo, los muestre en una lista, y en seleccionar una pista la reproduzca. Crea una animación de un botón que al pulsarlo desaparezca.
Solución.


Apuntes.

Cámara en android

Hace referencia a las librerias de multimedia integradas.
En realidad no solo leemos la biblioteca, también hacemos la foto.
Uno de los recursos mas importantes son las fotos, un recurso que tiene android es poner en marcha la aplicación de cámara, la ponemos en marcha y recibimos la foto o también podemos integrarla en nuestra propia aplicación. Según como, puede marcar que esta deprecated, hay una clase que han cambiado de la 4.4 a la 5, por el tema de las cámaras que trabajan a 360º.
Hay unas cuantas consideraciones sobre el tema de utilizar cámara en cuestión:
El uso de la cámara se ha de poner en el manifest.
DIAPO3-4
Tenemos camera, surfaceView, MediaRecorder y intención.
En el manifest tenemos que poner que queremos usar la cámaraç<ues-permision...
Diapo 5
---
El acceso a la aplicación de fotos es uno de los recursos habituales, explica comousar el emulador....
Para poner en marcha la aplicación, tenemos que crear un intent, con la URI andorid.media.action.IMAGE_CAPTURE" pone en marcha la aplicación de camara y cuando hacemos el start y será el intent que se le envia.
RESULTOKEY RESULTCANCEL...

OnActivityResult será lo que se ejecutará cuando recibamos la foto hecha.



Ejemplo1:




Ejemplo2:

Ejemplo 3:




Apuntes.


Swift


Swift es un nuevo lenguaje de programación para iOS, OS X, watchOS y aplicaciones tvOS que se basa en lo mejor de C y Objective-C, sin las limitaciones de compatibilidad C. Swift adopta patrones de programación seguras y añade características modernas para que la programación sea más fácil, más flexible y más divertida. Borrón y cuenta nueva de Swift, respaldado por Cacao y Touch framework, es una oportunidad para re-imaginar cómo funciona el desarrollo de software.

Swift ha surgido en base a años de elaboración. La manzana sentó las bases de Swift por el avance de nuestro compilador, depurador, y la infraestructura marco existente. Sea simplificado la gestión de memoria con el Automatic Reference  Counting (ARC). Se ha modernizado y estandarizado en todas partes. Objective-C en sí ha evolucionado para soportar bloques, literales colección, y los módulos, lo que permite la adopción de las tecnologías framework lingüísticas modernas sin interrupción. Gracias a este trabajo preliminar, pueden introducir un nuevo lenguaje para el futuro del desarrollo de software de Apple.

Swift le resulta familiar a los desarrolladores de Objective-C. Adopta la legibilidad de los parámetros con nombre de Objetivo-C y el poder del modelo de objetos dinámicos de Objective-C. Proporciona un acceso transparente a los marcos de cacao existentes y la interoperabilidad mezclar y combinar con el código de Objective-C. La construcción de esta base común, Swift introduce muchas nuevas características y unifica las partes procesales y orientados a objetos del lenguaje.

Swift es amigable para los nuevos programadores. Es el primer lenguaje de programación de sistemas de calidad industrial que es tan expresiva y agradable como un lenguaje de script. Es compatible con juegos infantiles, una característica innovadora que permite a los programadores para experimentar con el código Swift y ver los resultados inmediatamente, sin la sobrecarga de la construcción y funcionamiento de una aplicación.

Swift combina lo mejor del pensamiento lengua moderna, con la sabiduría de la cultura más amplia de ingeniería de Apple. El compilador está optimizado para el rendimiento y el lenguaje está optimizado para el desarrollo, sin comprometer a ambos. Está diseñado para escalar desde "hola, mundo" a un sistema operativo completo. Todo esto hace que Swift una inversión de futuro para los desarrolladores y sonido para Apple.

Swift es una fantástica manera de escribir iOS, OS X, watchOS y aplicaciones tvOS, y seguirá evolucionando con nuevas características y capacidades. 

Tour de Swift

La tradición sugiere que el primer programa en un nuevo lenguaje debe imprimir las palabras "Hola, mundo!" En la pantalla. En Swift, esto se puede hacer en una sola línea:
   print("Hello, world!")

Valores simples.


Si usted ha escrito el código en C o Objective-C, esta sintaxis es familiar en Swift, esta línea de código es un programa completo. No es necesario importar una biblioteca independiente para la funcionalidad como de entrada/salida o el manejo de cadenas. El código escrito en el ámbito global se utiliza como punto de entrada para el programa, por lo que no necesita una función main(). También no es necesario escribir un punto y coma al final de cada declaración.
Este tour le da suficiente información para empezar a escribir código en Swift, mostrando cómo llevar a cabo una variedad de tareas de programación.
Usamos 'let' para hacer una constante y 'var' para hacer una variable. El valor de una constante no tiene por qué ser conocido en tiempo de compilación, pero hay que asignarle un valor exactamente una vez. Esto significa que puede usar constantes para nombrar un valor que se determina una vez, pero se utiliza en muchos lugares.
Por ejemplo:
var myVariable = 42
myVariable = 50
let myConstant = 42

Una constante o variable deben tener el mismo tipo que el valor que se desea asignar a la misma. Sin embargo, no siempre se tiene que escribir el tipo de forma explícita. Proporcionar un valor al crear una constante o variable permite al compilador inferir su tipo. En el ejemplo anterior, el compilador infiere que Variable es un número entero, ya que su valor inicial es un número entero.
Si el valor inicial no proporciona suficiente información (o si no hay valor inicial), especifique el tipo escribiéndolo después de la variable, separados por dos puntos.
let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70

Los valores no se convierten implícitamente a otro tipo. Si necesitamos convertir un valor a un tipo diferente, crearemos una instancia del tipo deseado.
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
Hay una manera aún más sencilla para incluir valores en cadenas: Escribir el valor entre paréntesis, y escribir una barra invertida (\) antes del paréntesis. Por ejemplo:
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."


Crear matrices y diccionarios utilizando corchetes ([]), y acceder a sus elementos escribiendo el índice o una clave entre paréntesis. Una coma se permite después del último elemento.







var shoppingList = ["catfish", "water", "tulips", "blue paint"]

shoppingList[1] = "bottle of water"

var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
]

occupations["Jayne"] = "Public Relations"
Para crear una matriz vacía o diccionario, utilice la sintaxis de inicialización:
let emptyArray = [String]()
let emptyDictionary = [String: Float]()

Si la información de tipo se puede deducir, se puede escribir como una matriz vacía [] y un diccionario vacío como [:] - por ejemplo, cuando se establece un nuevo valor para una variable o al pasar un argumento a una función.
shoppingList = []
occupations = [:]


Flujo de control

Utilice if y switch para hacer condicionales y el uso for-in, for, while y repeat-while para hacer bucles. Los paréntesis alrededor de la variable de condición o de bucle son opcionales. Se requieren apoyos de todo el cuerpo.






let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
    if score > 50 {
       teamScore += 3
    } else {
       teamScore += 1
     }
}
print(teamScore)


En una sentencia if, el condicional debe ser una expresión booleana, esto significa que el código if puntuación{...} es un error, no una comparación implícita a cero.
Se puede utilizar if y let para trabajar con valores que pudieran faltar. Estos valores se representan como opcionales. Un valor opcional o bien contiene un valor nulo o contiene para indicar que se pierde un valor. Escribe un signo de interrogación (?) Después de que el tipo de un valor para marcar el valor como opcional.
var optionalString: String? = "Hello"
print(optionalString == nil)
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}


Si el optionalName es nulo, el condicional es falso y el código entre llaves se omite. De lo contrario, el valor opcional se desenvuelve y se asigna a la constante después de let, que hace que el desempaquetado valor disponible en el interior del bloque de código.
Otra forma de manejar los valores opcionales es proporcionar un valor por defecto utilizando el ?? operador. Si el valor opcional no está presente, el valor predeterminado se utiliza en su lugar.
let nickName: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickName ?? fullName)"
Los switches soportan cualquier tipo de datos y una amplia variedad de operadores de comparación, que no se limitan a los números enteros y las pruebas para la igualdad.
let vegetable = "red pepper"
switch vegetable {
   case "celery":
      print("Add some raisins and make ants on a log.")
   case "cucumber", "watercress":
      print("That would make a good tea sandwich.")
   case let x where x.hasSuffix("pepper"):
      print("Is it a spicy \(x)?")
   default:
      print("Everything tastes good in soup.")
}
Let puede ser usado en un patrón para asignar el valor que este emparejado, que parte de un patrón a una constante.
Después de ejecutar el código dentro de la caja del interruptor que hacía juego, el programa sale de la sentencia switch. La ejecución no continúa al siguiente caso, lo que no hay necesidad de romper explícitamente al final del código de cada caso.
Se utiliza for-in para iterar sobre los elementos de un diccionario, proporcionando un par de nombres a utilizar para cada par clave-valor. Los diccionarios son una colección desordenada, por lo que sus claves y valores se repiten a lo largo de un orden arbitrario.






let interestingNumbers = [
    "Prime": [2, 3, 5, 7, 11, 13],
    "Fibonacci": [1, 1, 2, 3, 5, 8],
    "Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
    for number in numbers {
       if number > largest {
          largest = number
       }
    }
}
print(largest)

Usaremos while para repetir un bloque de código hasta que una condición cambie. El estado de un bucle puede estar en el extremo en su lugar, asegurando que el bucle se ejecuta al menos una vez.





var n = 2
while n < 100 {
    n = n * 2
}
print(n)

var m = 2
repeat {
    m = m * 2
} while m < 100

print(m)

Podemos mantener un índice en un bucle, ya sea mediante el uso .. <para hacer una serie de índices o escribiendo una inicialización explícita, condición, y el incremento. Estos dos bucles hacen lo mismo:





var firstForLoop = 0
for i in 0..<4 {
    firstForLoop += i
}
print(firstForLoop)

var secondForLoop = 0
for var i = 0; i < 4; ++i {
    secondForLoop += i
}
print(secondForLoop)

Utilizamos ..< para hacer una gama que omite su valor superior, y utilizamos ... para hacer una gama que incluye ambos valores.

Funciones y cierres

Utilizaremos func para declarar una función. Para llamar a una función necesitaremos poner su nombre con una lista de argumentos entre paréntesis. Utilizaremos -> para separar los nombres de los parámetros y tipos de tipo de retorno de la función.
func greet(name: String, day: String) -> String {
    return "Hello \(name), today is \(day)."
}
greet("Bob", day: "Tuesday")


Utilizaremos una tupla para hacer un compuesto de valor, por ejemplo, para devolver varios valores de una función. Los elementos de una tupla pueden ser referidos por nombre o por número.






func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
    var min = scores[0]
    var max = scores[0]
    var sum = 0
    for score in scores {
       if score > max {
          max = score
       } else if score < min {
          min = score
       }
          sum += score
       }
   return (min, max, sum)
}
let statistics = calculateStatistics([5, 3, 100, 3, 9])
print(statistics.sum)
print(statistics.2)

Las funciones también pueden tomar un número variable de argumentos, su recogida en una matriz.






func sumOf(numbers: Int...) -> Int {
    var sum = 0
    for number in numbers {
       sum += number
    }
    return sum
}
sumOf()
sumOf(42, 597, 12)

Las funciones se pueden anidar. Funciones anidadas tienen acceso a las variables que fueron declaradas en la función externa. Puedes utilizar las funciones anidadas para organizar el código en una función que es largo o complejo.







func returnFifteen() -> Int {
    var y = 10
    func add() {
       y += 5
    }
    add()
    return y
}
returnFifteen()

Las funciones son un tipo de primera clase. Esto significa que una función puede devolver otra función como su valor.






func makeIncrementer() -> ((Int) -> Int) {
    func addOne(number: Int) -> Int {
       return 1 + number
    }
    return addOne
}
var increment = makeIncrementer()
increment(7)

Una función puede tener otra función como uno de sus argumentos.






func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
    for item in list {
       if condition(item) {
          return true
       }
    }
return false
}

func lessThanTen(number: Int) -> Bool {
    return number < 10
}

var numbers = [20, 19, 7, 12]
hasAnyMatches(numbers, condition: lessThanTen)

Las funciones son en realidad un caso especial de los cierres: bloques de código que se pueden llamar más tarde. El código en un cierre tiene acceso a cosas como las variables y funciones que estaban disponibles en el ámbito donde se creó el cierre, incluso si el cierre está en un ámbito diferente cuando se ejecuta, como vimos en un ejemplo de esto ya con funciones anidadas. Podemos escribir un cierre sin un nombre por el que rodea código con llaves ({}). El uso en separar los argumentos y el tipo de retorno del cuerpo.






numbers.map({
    (number: Int) -> Int in
    let result = 3 * number
    return result
})

Tiene varias opciones para la escritura de los cierres más concisa. Cuando un tipo de cierre es ya conocida, como la devolución de llamada para un delegado, se puede omitir el tipo de sus parámetros, el tipo de retorno, o ambas cosas. cierres sola declaración implícita devuelven el valor de su única declaración.





let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)

Se puede hacer referencia a los parámetros por número en lugar de por su nombre, este enfoque es especialmente útil en los cierres muy cortos. Un cierre de la última pasada como argumento a una función puede aparecer inmediatamente después del paréntesis. Cuando el cierre es el único argumento a una función, se puede omitir el paréntesis en su totalidad.






let sortedNumbers = numbers.sort { $0 > $1 }
print(sortedNumbers)

Objetos y clases

Utilizaremos class seguido del nombre de la clase para crear una clase. Una declaración de propiedad en una clase se escribe de la misma manera que una declaración constante o variable, excepto que es en el contexto de una clase. Del mismo modo, el método y las declaraciones de función se escriben de la misma manera.





class Shape {
    var numberOfSides = 0
    func simpleDescription() -> String {
       return "A shape with \(numberOfSides) sides."
    }
}

Crear una instancia de una clase, poniendo entre paréntesis después del nombre de la clase. Utilice la sintaxis con punto para acceder a las propiedades y métodos de la instancia.





var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()

Esta versión de la clase Shape le falta algo importante: un inicializador para establecer la clase cuando se crea una instancia. Utilizamos init para crear uno.

class NamedShape {
    var numberOfSides: Int = 0
    var name: String
    init(name: String) {
       self.name = name
    }
    func simpleDescription() -> String {
       return "A shape with \(numberOfSides) sides."
    }
}


Observe cómo self se utiliza para distinguir la propiedad del nombre, del nombre de argumento al inicializador. Los argumentos del inicializador se pasan como una llamada a la función cuando se crea una instancia de la clase. Cada propiedad necesita un valor asignado, ya sea en su declaración (al igual que con numberOfSides) o en el inicializador (al igual que con el nombre).

Utilice deinit para crear un deinitializer si es necesario realizar alguna tarea de limpieza antes de que se cancela la asignación del objeto.

Subclases incluyen su nombre de superclase del nombre de la clase, separados por dos puntos. No hay ningún requisito para las clases a la subclase cualquier clase raíz estándar, por lo que pueden incluir u omitir una superclase, según sea necesario.

Métodos en una subclase que tienen preferencia sobre la implementación de la superclase están marcados con override-overriding para evitar la sobreescritura de un método por accidente, es detectado por el compilador como un error si no lo ponemos. El compilador también detecta métodos con anulación que en realidad no anulan cualquier método en la superclase.







class Square: NamedShape {
    var sideLength: Double

    init(sideLength: Double, name: String) {
       self.sideLength = sideLength
       super.init(name: name)
       numberOfSides = 4
    }

    func area() -> Double {
       return sideLength * sideLength
    }
    override func simpleDescription() -> String {
       return "A square with sides of length \(sideLength)."
    }
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()

Además de las propiedades simples que se almacenan, las propiedades pueden tener un getter y setter.






class EquilateralTriangle: NamedShape {
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) {
       self.sideLength = sideLength
       super.init(name: name)
       numberOfSides = 3
    }


    var perimeter: Double {
       get {
          return 3.0 * sideLength
       }
       set {
          sideLength = newValue / 3.0
       }
    }
 
   override func simpleDescription() -> String {
      return "An equilateral triangle with sides of length \(sideLength)."
   }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)

En el setter para el perimeter, el nuevo valor tiene el nombre implicito newValue. 
Podemos proporcionar un nombre explícito entre paréntesis después del set.
Observamos que el inicializador para la clase de triángulo equilátero tiene tres etapas diferentes
  • Mediante la configuración de las propiedades que declara la subclase.  
  • Llamando a la inicializador superclase
  • Cambiar el valor de las propiedades definidas por la superclase. Cualquier otra configuración funciona pero utiliza métodos getters o setters, también se puede hacer en este momento.
Si no es necesario para calcular la propiedad, pero todavía tiene que proporcionar el código que se ejecuta antes y después de establecer un nuevo valor, utilice willSet y didSet. El código que proporciona es ejecutar en cualquier momento los cambios de valor fuera de un inicializador. Por ejemplo, la clase a continuación se asegura de que la longitud del lado de su triángulo es siempre la misma que la longitud del lado de su cuadrado.






class TriangleAndSquare {
    var triangle: EquilateralTriangle {
       willSet {
          square.sideLength = newValue.sideLength
       }
    }
    var square: Square {
       willSet {
          triangle.sideLength = newValue.sideLength
       }
    }
    init(size: Double, name: String) {
       square = Square(sideLength: size, name: name)
       triangle = EquilateralTriangle(sideLength: size, name: name)
    }
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
print(triangleAndSquare.square.sideLength)
print(triangleAndSquare.triangle.sideLength)
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)


Cuando se trabaja con valores opcionales, podemos escribir ? antes de las operaciones como los métodos, propiedades y subíndices. Si el valor antes de ? es nil, todo después de que el ? es ignorado y el valor de toda la expresión es nula. De lo contrario, el valor opcional se desenvuelve, y todo después de la ? actúa sobre el valor sin envolver. En ambos casos, el valor de toda la expresión es un valor opcional.

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength

Enumeraciones y estructuras

Utilice enum para crear una enumeración. Al igual que las clases y todos los otros tipos de nombres, las enumeraciones pueden tener métodos asociados con ellos.






enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King
    func simpleDescription() -> String {
       switch self {
//this en Java
          case .Ace:
             return "ace"
          case .Jack:
             return "jack"
          case .Queen:
             return "queen"
          case .King:
             return "king"
          default:
             return String(self.rawValue)
       }
    }
}
let ace = Rank.Ace
let aceRawValue = ace.rawValue


En el ejemplo anterior, el tipo de valor de la enumeración es de tipo int, por lo que sólo tiene que especificar el primer valor. El resto de los valores se asignan en orden. También puede utilizar cadenas o números de punto flotante como el tipo de prima de una enumeración. Utilice la propiedad rawValue para acceder al valor de un caso de enumeración. Utilice el init? (RawValue :) inicializador para hacer una instancia de una enumeración de un valor en bruto.






if let convertedRank = Rank(rawValue: 3) {
    let threeDescription = convertedRank.simpleDescription()
}

Los valores del caso de una enumeración, son valores reales, no sólo otra manera de escribir sus valores. De hecho, en los casos donde no hay un valor significativo, no tenemos que proporcionar uno.






enum Suit {
case Spades, Hearts, Diamonds, Clubs
func simpleDescription() -> String {
    switch self {
       case .Spades:
          return "spades"
       case .Hearts:
          return "hearts"
       case .Diamonds:
          return "diamonds"
       case .Clubs:
          return "clubs"
       }
    }
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()
let heart = Suit.Spades
let heartsDescription = heart.simpleDescription()

Observemos las dos formas en que el caso de los corazones de la enumeración se hace referencia más arriba: Cuando se asigna un valor a las constantes hearts, los casos Suit.Hearts enumeración se refiere por su nombre completo debido a que la constante no tiene un tipo explícito especificado. En el interior del switch, el caso de enumeración es referido por los .Hearts forma abreviada debido a que el valor del self ya es conocido por ser un traje. Puede utilizar la forma abreviada en cualquier momento el tipo del valor que ya se conoce.
Utilice struct para crear una estructura. Las estructuras soportan muchas de las mismas conductas como las clases, incluyendo métodos y inicializadores. Una de las diferencias más importantes entre las estructuras y las clases de estructuras es que siempre se copian cuando se pasan alrededor de su código, pero las clases se pasan por referencia.






struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
      return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
 
Un ejemplo de un caso de enumeración puede tener valores asociados a la instancia. Las instancias de la misma enumeración pueden tener diferentes valores asociados con ellos. Usted proporciona los valores asociados al crear la instancia. valores asociados y los valores brutos son diferentes: El valor bruto de un caso de enumeración es el mismo para todas sus instancias, y le proporcionará el valor bruto cuando se define la enumeración.

Por ejemplo, consideremos el caso de solicitar la hora de salida y puesta de sol desde un servidor. El servidor responde ya sea con la información o responde con información de error.







enum ServerResponse {
    case Result(String, String)
    case Error(String)
}

let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")

switch success {
   case let .Result(sunrise, sunset):
      print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
   case let .Error(error):
      print("Failure... \(error)")
}


Observe cómo se extraen las horas de salida y puesta del sol a partir del valor de respuesta del servidor como parte de la búsqueda de valor frente a los casos switch.

Protocolos y Extensiones

Utilizar el protocolo para declarar un protocolo.
protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}

Las clases, enumeraciones, estructuras y todos pueden adoptar protocolos.






class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "A very simple class."
    var anotherProperty: Int = 69105
    func adjust() {
       simpleDescription += " Now 100% adjusted."
    }
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
 
struct SimpleStructure: ExampleProtocol {
    var simpleDescription: String = "A simple structure"
    mutating func adjust() {
       simpleDescription += " (adjusted)"
    }
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
 

Observe el uso de la palabra clave mutating en la declaración de estructura simple para marcar un método que modifica la estructura. La declaración de clase simple no necesita ninguno de sus métodos marcados como mutando porque los métodos de una clase siempre pueden modificar a la clase.
Utilizar la extensión para agregar funcionalidad a un tipo existente, como los nuevos métodos y las propiedades calculadas. Se puede utilizar una extensión para añadir conformidad protocolo para un tipo que se declara en otro lugar, o incluso a un tipo que ha importado de una biblioteca o un framework.






extension Int: ExampleProtocol {
    var simpleDescription: String {
       return "The number \(self)"
    }
    mutating func adjust() {
       self += 42
    }
}
print(7.simpleDescription)

Se puede utilizar un nombre de protocolo al igual que cualquier otro tipo, por ejemplo el nombre, para crear una colección de objetos que tienen diferentes tipos, sino que todos ajustarse a un protocolo único. Cuando se trabaja con valores cuyo tipo es un tipo de protocolo, métodos fuera de la definición de protocolo no están disponibles.





let protocolValue: ExampleProtocol = a
print(protocolValue.simpleDescription)
// print(protocolValue.anotherProperty) // Uncomment to see the error

A pesar de que el valor de protocolo variable tiene un tipo de tiempo de ejecución de SimpleClass, el compilador lo trata como el tipo dado de ExampleProtocol. Esto significa que no se puede acceder accidentalmente a los métodos o propiedades que la clase implementa además de su cumplimiento del protocolo.

Genéricos

Escribe un nombre dentro de paréntesis angulares para realizar una función genérica o tipo.






func repeatItem<Item>(item: Item, numberOfTimes: Int) -> [Item] {
    var result = [Item]()
    for _ in 0..<numberOfTimes {
       result.append(item)
    }
    return result
}
repeatItem("knock", numberOfTimes:4)

Puedes hacer que las formas genéricas de funciones y métodos, así como las clases, enumeraciones y estructuras.






// Reimplement the Swift standard library's optional type
enum OptionalValue<Wrapped> {
    case None
    case Some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)

Donde después de usar el nombre de tipo para especificar una lista de requisitos, por ejemplo, para implementar un protocolo, para requerir dos tipos que pueden ser el mismo, o para requerir una clase para tener una superclase particular.





func anyCommonElements <T: SequenceType, U: SequenceType where T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element>    (lhs: T, _ rhs: U) -> Bool {
    for lhsItem in lhs {
       for rhsItem in rhs {
           if lhsItem == rhsItem {
           return true
          }
       }
    }
    return false
}
anyCommonElements([1, 2, 3], [3])
anyCommonElements([1,2,3,4,5,6],[3])
anyCommonElements([1,2,3,4,5,6],[7])
 
Escribir <T: Equatable> es lo mismo que decir <T where T: Equatable>.
Es posible que necesitemos hacer:
import Foundation
para que funcione correctamente.

Más información:
Developer swift.

Ejercicios.
Soluciones propuestas apple.


Estilos y temas (Android)

Un estilo es un conjunto de propiedades que especifican el aspecto y el formato de un View o ventana, un estilo puede especificar propiedades como la altura, color de una fuente... se puede definir con un XML.
Los estilos de android comparten una filosofía similar en las hojas de estilo, permitiendo separar diseño del contenido.
Por ejemplo, podemos transformar:
<TextView
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:textColor="#00FF00"
   android:typeface="monospace"
   android:text="@string/hello" />

En:

<TextView
   style="@style/CodeFont"
   android:text="@string/hello" />

Todos los atributos relacionados con los estilos se han retirado del XML del diseño y puestos en una definición de estilo llamada CodeFont, que se aplica a continuación con el atributo style. Un tema es un estilo aplicado a toda una actividad o a una aplicación, en vez de a una única View (como el ejemplo anterior). Cuando se aplica un estilo como un tema, cada vista en la actividad o aplicación tendrán las propiedades del estilo.
Por ejemplo, se peude aplicar el mismo CodeFont estilo como un tema para una actividad y después todo el texto dentro de esta actividad tendrá una fuente senzilla de color verde.
Por lo tanto, se parecen mucho a los css, los hijos heredan los estilos, como tipografia color...
El tema se aplica automaticamente a todos los componentes, en cambio los estilos no. El tema se puede aplicar por actividades o por aplicación, por lo tanto esta definido mediante el android manifest. Si a parte de todo el tema aplicas un estilo, este prevalece.
Para definirlo se hace con un archivo xml que esta en recursos.
el nombre del fichero el que quieras, la raiz es recursos.
Para crear un conjunto de estilos, hace falta dejar un fichero XML en el directorio res/values/ del projecto, con un nombre cualquiera.
Para cada estilo que queramos crear, hará falta añadir un elemento <style> al archivo con un nombre que identifica de forma única el estilo. A continuación, hay que añadir un elemento <item> para cada propiedad de este estilo, con un nombre que declara la propiedad de estilos y un valor para asociar con ella. El valor para el <item> puede ser una cadena de palabras clave, un color hexadecimal, una referencia a otro tipo de recurso o a otro valor en función de la propiedad del estilo.
Por ejemplo:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <style name="CodeFont" parent="@android:style/TextAppearance.Medium">
   <item name="android:layout_width">fill_parent</item>
   <item name="android:layout_height">wrap_content</item>
   <item name="android:textColor">#00FF00</item>
   <item name="android:typeface">monospace</item>
 </style>
</resources>Los estilos por programación se pueden modificar. necesitaremos poner un identificador.
Nosotros podemos coger un estilo y como padre coge el textappareance, este ejemplo tenemos item android:textcolor que modificamos el color.

Todos los hijos de <resources> hacen un objeto de recurso de aplicación en tiempo de compilación, se puede hacer referencia por el nombre <style>
El atributo parent al elemento <style> es opcional y especifica la ID del recurso de otro estilo del cual este estilo tiene que heredar propiedades. A continuación puedes anular las propiedades de estilo heredadas si quieres.
Un estilo que se quiere utilizar como una actividad o un tema de aplicación se define en XML exactamente lo mismo para un estilo que para una vista. Un estilo como el que se ha definido antes se puede aplicar como un estilo para una vista única o tema de una actividad o aplicación entera.
Un ejemplo de la herencia de estilos:
<style name="textVerd" parent="@android:style/TextAppearance">
    <item name="android:textColor">#00FF00</item>
</style>
En el caso de heredar de un estilo propio, la sintaxis es algo diferente:
<style name="CodeFont.Rojo">
    <item name="android:textColor">#FF0000</item>
</style>
<style name="CodeFont.Rojo.Gran">
    <item name="android:textSize">30sp</item>
</style>
Permite crear un estilo propio, nombre codefont de tipo rojo, después tenemos un subtipo.
Para aplicar el estilo ponemos style y le aplicamos el código fuente. Si lo queremos hacer para toda la aplicación tiene que ser en nivel de theme, muchos estilos empaquetados definen un tema.
Por lo tanto, hay dos maneras de configurar un estilo:
  • Para vista individual, añadiendo el atributo style a un elemento View al XML por su diseño.
  • Para toda una actividad o aplicación, añadiendo el atributo android:theme al activity o element <application> en el manifest de Android.
<TextView style="@style/CodeFont" android:text="@string/hello" />
<application android:theme="@style/CustomTheme">
<activity android:theme="@android:style/Theme.Dialog">

Android también ofrece otros recursos incorporados, hay muchos temas predefinidos que se pueden utilizar para evitar escribir tu mismo.

<color name="custom_theme_color">#b0b0ff</color>
<style name="CustomTheme" parent="android:Theme.Light">
   <item name="android:windowBackground">@color/custom_theme_color</item>
   <item name="android:colorBackground">@color/custom_theme_color</item>
</style>

En este caso, para crear un tema se hereda de un tema existente y se le hace las modificaciones que queremos.


Android, theme.Light es uno claro, con android studio se pueden ver los temas fácilmente, y podemos ver un color que esta predefinido. Los estilos se crean de la misma manera que los estilos de vista pero se usa el color standard.


Ejemplo.