Con la conferencia de Google I / O 2017 programada para menos de 2 meses, pensé que sería una buena idea estructurar mis pensamientos y la experiencia que obtuve con los productos presentados en el evento del año pasado. Desde la perspectiva del tiempo, tiene mucho sentido averiguar si los productos pasaron la prueba de viabilidad.
Compatibilidad con pantallas múltiples en Android N
Android N mostró la nueva función multitarea en forma de modo de ventana múltiple, lo que permite tener dos aplicaciones trabajando en una pantalla al mismo tiempo. En un televisor, puede tener un modo de imagen en imagen con un video reproduciéndose mientras usa otra aplicación en la misma pantalla. Los tamaños de las ventanas se pueden cambiar mediante las manipulaciones del divisor entre ellos.
Hay dos formas de habilitar el modo de ventanas múltiples:
- Al abrir la pantalla Recientes y hacer clic largo en el nombre de la operación que lo hace arrastrable a un área de pantalla seleccionada y cambiarlo al modo de ventanas múltiples.
- Al hacer clic largo en el botón Recientes que le indica a la aplicación que cambie la operación actual al modo de ventanas múltiples. Luego, el dispositivo abre la pantalla Recientes para que un usuario seleccione la segunda operación para la visualización simultánea.
Para aplicaciones (pantalla de configuración y Youtube) que funcionan en modo de múltiples ventanas.
Para habilitar el modo de ventanas múltiples para su aplicación Android N, aplique los siguientes cambios al archivo AndroidManifest.xml :
1. En el nodo o , inserte el atributo android: resizeableActivity .
2. Proporcione el [“verdadero” | Valor de atributo “falso”] para habilitar / deshabilitar el modo de ventanas múltiples.
Si el valor del atributo se establece en verdadero , la operación se puede iniciar en modo de pantalla dividida y de forma libre. Si el valor es falso , la operación no admite ventanas múltiples y el intento de iniciar la operación en pantalla dividida da como resultado la visualización de pantalla completa.
El comportamiento predeterminado de la aplicación Android N es el verdadero , cuando el valor del atributo no está establecido.
3. Establezca el valor de atributo android: supportsPictureInPicture en verdadero para el soporte del modo “imagen en imagen”. Nota: el valor de atributo resizeableActivity: debe establecerse como verdadero .
4. Ejecute la nueva actividad en el modo de ventanas múltiples para que la nueva ventana se coloque junto a otra. Use el indicador Intent.FLAG_ACTIVITY_LAUNCH_TO_ADJACENT que solicita el siguiente comportamiento:
- Si el dispositivo está en el modo de ventanas múltiples, el sistema intenta crear una nueva ventana de operación junto a la ventana de la operación que lo lanzó, para colocar los dos en la misma pantalla. El éxito no está garantizado, pero si es posible, el sistema cambia a ventanas múltiples.
- Si el dispositivo no está en el modo de pantalla dividida, se ignora la bandera.
Soporte de Android N Arrastrar y soltar entre actividades
Desde Android N en adelante, los usuarios pueden arrastrar y soltar objetos entre múltiples actividades. Para esto, se utilizan las clases ClipData y DragEvent . En el lado de envío donde se inicia el arrastre, los datos se empaquetan mediante la clase ClipData .
Los siguientes tipos de datos están disponibles para transferir:
- ClipDescription.MIMETYPE_TEXT_HTML: para la transferencia de texto HTML.
- ClipDescription.MIMETYPE_TEXT_INTENT: para la transferencia de intención .
- ClipDescription.MIMETYPE_TEXT_PLAIN: para la transferencia de texto simple.
- ClipDescription.MIMETYPE_TEXT_URILIST: para la transferencia de URI.
Echemos un vistazo más de cerca al arrastrar y soltar objetos de una Actividad a otra, específicamente, un texto simple y una imagen. Como ejemplo, usaré dos actividades de una aplicación, aunque se puede hacer lo mismo entre dos aplicaciones separadas. Para iniciar el arrastre de objetos, utilizo el método View.startDragAndDrop . En la aplicación receptora, instalo el oyente DragEvent . Además, es obligatorio establecer el valor del atributo android: resizeableActivity en verdadero .
textView.setOnLongClickListener (nueva View.OnLongClickListener () {
@Anular
public boolean onLongClick (Ver vista) {
ClipData.Item item = new ClipData.Item (textView.getText ());
ClipData clip = new ClipData (textView.getText (),
nueva Cadena [] {ClipDescription.MIMETYPE_TEXT_PLAIN}, elemento);
View.DragShadowBuilder dragShadowBuilder = nuevo View.DragShadowBuilder (ver);
textView.startDragAndDrop (clip, dragShadowBuilder, nulo, View.DRAG_FLAG_GLOBAL);
volver verdadero;
}
});
imageView.setOnLongClickListener (ver -> {
Cadena PACKAGE_NAME = getApplicationContext (). GetPackageName ();
Uri uri = Uri.parse (“android.resource: //” + PACKAGE_NAME + “/ drawable / test_img”);
ClipData.Item item = nuevo ClipData.Item (uri);
ClipData clip = new ClipData ((CharSequence) view.getTag (),
nueva Cadena [] {ClipDescription.MIMETYPE_TEXT_URILIST}, elemento);
View.DragShadowBuilder dragShadowBuilder = nuevo View.DragShadowBuilder (ver);
imageView.startDragAndDrop (clip, dragShadowBuilder, null, View.DRAG_FLAG_GLOBAL
El | View.DRAG_FLAG_GLOBAL_URI_READ | Ver.DRAG_FLAG_GLOBAL_URI_WRITE);
volver verdadero;
});
El ejemplo de un código fuente del transmisor de actividad.
Los objetos TextView e ImageView son suministrados por los oyentes de clics largos apropiados. Un clic largo inicia el arrastrar y soltar. El sistema crea los dos objetos ClipData.Item . Con TextView , el objeto relevante recibe el texto mismo y, en cuanto a ImageView , recibe el URI de la imagen que se almacena en los recursos de la aplicación.
Luego, la instancia de la clase ClipData.Item se empaqueta en la instancia de la clase de nivel superior de ClipData con los indicadores correspondientes:
- MIMETYPE_TEXT_PLAIN para texto
- MIMETYPE_TEXT_URILIST para una imagen.
Para el efecto de sombra durante el arrastre, se utiliza la clase DragShadowBuilder .
Los siguientes indicadores controlan el arrastre en la clase startDragAndDrop que inicia el arrastre:
- El indicador View.DRAG_FLAG_GLOBAL permite arrastrar entre Actividades.
- El indicador View.DRAG_FLAG_GLOBAL_URI_READ permite la lectura de URI.
- El indicador View.DRAG_FLAG_GLOBAL_URI_WRITE permite la escritura de URI.
En el extremo de recepción de actividad, se instalan componentes de vista similares para aceptar los objetos arrastrados. El oyente de transición OnDragListener está conectado a ellos para rastrear el movimiento del objeto.
Se rastrean los siguientes eventos:
- ACTION_DROP: el objeto se ha dejado caer en el área de recepción.
- ACTION_DRAG_ENTERED: el objeto está dentro de los límites del área de recepción.
- ACTION_DRAG_EXITED: el objeto ha abandonado el área de recepción.
Además, es necesario asegurarse de que el objeto ImageView se haya dejado caer en su ImageView receptor, y del mismo modo, el objeto TextView . Para verificar, ejecute lo siguiente:
- event.getClipDescription (). getMimeType (0) .equals ( MIMETYPE_TEXT_URILIST ) -para URI y específicamente para la imagen en este ejemplo.
- event.getClipDescription (). getMimeType (0) .equals ( MIMETYPE_TEXT_PLAIN ) – para texto.
textView.setOnDragListener (new View.OnDragListener () {
@Anular
public boolean onDrag (Ver v, evento DragEvent) {
switch (event.getAction ()) {
caso DragEvent.ACTION_DROP:
requestDragAndDropPermissions (evento);
ClipData.Item item = event.getClipData (). GetItemAt (0);
if (event.getClipDescription (). getMimeType (0) .equals (MIMETYPE_TEXT_PLAIN)) {
CharSequence text = item.getText ();
textView.setText (texto);
}
}
volver verdadero;
}
});
imageView.setOnDragListener ((v, event) -> {
switch (event.getAction ()) {
caso DragEvent.ACTION_DRAG_ENTERED:
if (event.getClipDescription (). getMimeType (0) .equals (MIMETYPE_TEXT_URILIST)) {
imageView.setBackgroundResource (R.color.colorBgDrag);
}
descanso;
caso DragEvent.ACTION_DRAG_EXITED:
if (event.getClipDescription (). getMimeType (0) .equals (MIMETYPE_TEXT_URILIST)) {
imageView.setBackgroundResource (R.color.colorBg);
}
descanso;
caso DragEvent.ACTION_DROP:
requestDragAndDropPermissions (evento);
ClipData.Item item = event.getClipData (). GetItemAt (0);
if (event.getClipDescription (). getMimeType (0) .equals (MIMETYPE_TEXT_URILIST)) {
Uri uri = item.getUri ();
imageView.setImageURI (uri);
}
}
volver verdadero;
});
El ejemplo de un código fuente del receptor de actividad.
Así es como se ve una aplicación de prueba con capacidades de transmisión de objetos:
Las capacidades de Java 8 en Android N
Android N introdujo el soporte de lenguaje Java 8 que incluye las siguientes capacidades:
- Métodos estáticos y predeterminados en las IU.
- Lambda-expresiones.
- Repetir anotaciones.
Java 8 requiere la cadena de herramientas Jack con la ayuda de la cual Android compila el código fuente de Java en un bytecode legible ejecutable (dex) de Android Dalvik.
Configuración de Gradle:
android {
compileSdkVersion 25
buildToolsVersion “25.0.2”
defaultConfig {
applicationId “example.test.com.testproject”
minSdkVersion 19
targetSdkVersion 25
versionCode 1
versionName “1.0”
testInstrumentationRunner “android.support.test.runner.AndroidJUnitRunner”
jackOptions {
habilitado verdadero
}
}
buildTypes {
lanzamiento {
minifyEnabled false
proguardFiles getDefaultProguardFile (‘proguard-android.txt’), ‘proguard-rules.pro’
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
El ejemplo de la configuración de Java 8 en Gradle.
De la presentación de Google I / O 2016:
@TargetApi (Build.VERSION_CODES.N)
Interfaz pública Renderable {
sorteo vacío (lienzo c);
booleano predeterminado isHardwareAccelerated () {
falso retorno;
}
static int getMaxTextureSize () {
volver 2048;
}
}
@TargetApi (Build.VERSION_CODES.N)
interfaz pública FrameListener {
vacío predeterminado onFrameStarted () {}
vacío predeterminado onFrameEnded () {}
}
El ejemplo de métodos estáticos y predeterminados en la interfaz de usuario.
@Retention (RetentionPolicy.RUNTIME)
public @interface Figures {
Shape [] value () default {};
}
@TargetApi (Build.VERSION_CODES.N)
@Repeatable (value = Figures.class)
public @interface Shape {
Tipo de cadena ();
}
@ Forma (tipo = “rectángulo”)
@Shape (type = “cubo”)
@Shape (type = “circle”)
@Shape (type = “oval”)
clase pública MyShape {
}
El ejemplo de repetir anotaciones.
imageView.setOnClickListener (v -> {
List list = getArrayList ();
Collections.sort (list, (o1, o2) -> {
devuelva o1.compareTo (o2);
});
});
El ejemplo de expresiones Lambda.
Apoye las innovaciones de la biblioteca en Android N
La conferencia Google I / O 2016 introdujo algunas características nuevas de la biblioteca de soporte como:
- El ciclo de vida mejorado de los fragmentos: una confirmación sincrónica a través del método commitNow () .
- El nuevo estilo visual de notificaciones.
- Personalizaciones de IU: colores personalizados. Nueva barra de herramientas y acciones de la barra inferior. Nuevas transiciones de entrada / salida.
- El soporte de imágenes vectoriales en las versiones de Android inferiores a 5.0.
- La función RecyclerView AutoMeasure permite que RecyclerView cambie su tamaño dependiendo del tamaño de su contenido. Esto significa que los escenarios previamente no disponibles como el uso de la función WRAP-CONTENT para dimensionar RecyclerView ahora son posibles. Todos los componentes integrados de LayoutManagers ahora admiten la medición automática. Debido a esa medida, los parámetros de diseño (como MATCH_PARENT en la dirección de desplazamiento) que se habían ignorado antes, ahora se tendrán en cuenta.
- La animación mejorada de cambio de elementos de RecyclerView .
AppCompat
1. El modo Día / Noche fue presentado por la nueva familia de temas DayNight , que permite el cambio automático entre los temas claros y oscuros según la hora del día.
Declaración de cambio de tema:
Theme.AppCompat.DayNight permite el cambio entre el Theme.AppCompat oscuro y el Theme.AppCompatLight claro según el día de la hora. Esta función con la versión 14 y posterior de la API, las versiones anteriores tienen el tema ligero por defecto.
Para habilitar la función en la aplicación:
Invoque el método estático AppCompatDelegate.setDefaultNightMode () que adopta uno de los cuatro valores:
- MODE_NIGHT_NO: siempre utiliza el tema claro.
- MODE_NIGHT_YES : siempre usa el tema oscuro.
- MODE_NIGHT_AUTO : cambio automático de tema según la hora del día.
- MODE_NIGHT_FOLLOW_SYSTEM : parámetro predeterminado del sistema de MODE_NIGHT_NO .
También en una actividad separada, puede redefinir los valores de los parámetros del tema de forma predeterminada con la ayuda del método setLocalNightMode () que se invoca en la Actividad ejecutando lo siguiente:
getDelegate().setLocalNightMode(@NightMode
mode);
int
getDelegate().setLocalNightMode(@NightMode
mode);
Este método también es bueno para la verificación de temas, de modo que no tenga que esperar a cierta hora del día.
2. ColorStateList.
El ejemplo de ColorStateList con atributos de tema agregados:
-
-
-
-
- android: alpha = “? android: disabledAlpha”
- android: state_enabled = “false” />
-
-
Res / colors / tint_normal.xml
ColorStateList colorStateList = AppCompatResources.getColorStateList (esto, R.color.tint_normal);
Botón botón = (Botón) findViewById (R.id.test_button);
button.setBackgroundTintList (colorStateList);
Aplicación de color para un botón de texto.
Diseño en Android N
Hojas inferiores
Las hojas inferiores son una pantalla de contenido adicional que puede extraer desde la parte inferior de la pantalla del dispositivo. La Biblioteca de soporte de diseño permite cumplir con esta funcionalidad en las versiones anteriores de Android.
Para implementar esta herramienta, agregue las siguientes dependencias en el archivo gradle:
compile
'com.android.support:appcompat-v7:XX.XX'
compile ‘com.android.support:design:XX.X.X’
Hay dos tipos de láminas inferiores:
- Hojas de fondo persistentes que están integradas con la aplicación para mostrar el contenido.
http://schemas.android.com/apk/res/android" ;
xmlns: tools = ” http://schemas.android.com/tools" ;
xmlns: app = ” http://schemas.android.com/apk/res-auto" ;
android: id = “@ + id / activity_main3”
android: layout_width = “match_parent”
android: layout_height = “match_parent”
herramientas: context = “example.test.com.testproject.Main3Activity”>
android: id = “@ + id / bg_view”
android: layout_width = “match_parent”
android: layout_height = “match_parent”
android: orientación = “horizontal”>
android: layout_width = “match_parent”
android: layout_height = “wrap_content”
android: text = “diseño de contenido principal” />
android: id = “@ + id / bottom_sheet”
android: layout_width = “match_parent”
android: layout_height = “match_parent”
aplicación: layout_behavior = “android.support.design.widget.BottomSheetBehavior”
android: orientación = “vertical”
aplicación: behaviour_peekHeight = “80dp”
android: elevación = “6dp”
android: background = “@ color / colorBgDrag”>
android: layout_width = “match_parent”
android: layout_height = “wrap_content”
android: text = “Contenido inferior”
android: gravity = “center” />
android: id = “@ + id / switch_bg_button”
android: layout_width = “match_parent”
android: layout_height = “wrap_content”
android: layout_marginTop = “200dp”
android: text = “Cambiar color de fondo” />
Diseño de hoja inferior persistente.
behavior_peekHeight
define la altura de la parte visible.
Behavior_hideable
define si la pantalla inferior se puede ocultar deslizando hacia abajo.
La app:layout_behavior=
"android.support.design.widget.BottomSheetBehavior":
línea significa que el diseño pertenece a la hoja inferior.
También puede vincular una devolución de llamada a la hoja inferior para ayudarlo a descubrir el estado de la pantalla que aparece:
Ver bottomSheet = findViewById (R.id.bottom_sheet);
Comportamiento de BottomSheetBehavior = BottomSheetBehavior.from (bottomSheet);
behaviour.setBottomSheetCallback (nuevo BottomSheetBehavior.BottomSheetCallback () {
@Anular
public void onStateChanged (@NonNull View bottomSheet, int newState) {
Log.v (“BOTTOM_SHEET_STATE”, String.valueOf (newState));
}
@Anular
public void onSlide (@NonNull View bottomSheet, float slideOffset) {
}
});
Devolución de llamada estado de la hoja inferior
Hay cinco estados posibles:
1. STATE_COLLAPSED es un estado colapsado por defecto que solo muestra el diseño parcialmente en la parte inferior. La altura puede ser gestionada por la aplicación: atributo behaviour_peekHeight con 0 por defecto.
2. STATE_DRAGGING es un estado intermedio durante el deslizamiento.
3. STATE_SETTLING es un breve momento entre el lanzamiento de la vista y cae en la posición final.
4. STATE_EXPANDED es un estado del componente de la hoja inferior completamente desplegado y visible (si su altura es menor que en CoordinatorLayout o se llena todo CoordinatorLayout ).
5. STATE_HIDDEN es un estado deshabilitado por defecto (por la aplicación: atributo behaviureable). Habilitarlo significa que un usuario es capaz de ocultar el componente de las hojas inferiores deslizando hacia abajo.
Ejemplo de rendimiento de la hoja inferior persistente:
Al hacer clic en el botón Cambiar color de fondo, se cambia el fondo de la ventana de actividad.
findViewById (R.id.switch_bg_button) .setOnClickListener (v -> {
findViewById (R.id.bg_view) .setBackgroundColor (Color.CYAN):
}):
- Modal Bottom Sheets es un cuadro de diálogo deslizante que no forma parte de la jerarquía de vista principal. Básicamente es una alternativa a un menú o un cuadro de diálogo simple. También puede entregar el contenido profundamente conectado de otras aplicaciones.
The BottomSheetDialogFragment
El fragmento sirve como una ventana modal con todo el contenido. Un deslizamiento hacia abajo cierra la ventana.
http://schemas.android.com/apk/res/android" ;
xmlns: tools = ” http://schemas.android.com/tools" ;
xmlns: app = ” http://schemas.android.com/apk/res-auto" ;
android: layout_width = “match_parent”
android: layout_height = “match_parent”
android: paddingLeft = “@ dimen / activity_vertical_margin”
android: paddingRight = “@ dimen / activity_vertical_margin”
android: paddingBottom = “@ dimen / activity_vertical_margin”
android: orientación = “vertical”
aplicación: behaviour_peekHeight = “280dp”
android: paddingTop = “@ dimen / activity_vertical_margin”>
android: layout_width = “match_parent”
android: layout_height = “wrap_content”
android: orientación = “horizontal”
android: gravity = “center”>
android: id = “@ + id / ic_image”
android: src = “@ mipmap / ic_launcher”
android: layout_width = “wrap_content”
android: layout_height = “wrap_content” />
android: layout_width = “wrap_content”
android: layout_height = “wrap_content”
android: text = “Hola hoja inferior” />
android: id = “@ + id / textview”
android: layout_width = “match_parent”
android: layout_height = “wrap_content” />
android: id = “@ + id / switch_bg_button”
android: layout_width = “match_parent”
android: layout_height = “wrap_content”
android: text = “Cambiar color de fondo” />
Diseño de la hoja inferior modal.
clase pública MyModalFragment extiende BottomSheetDialogFragment {
private OnFragmentInteractionListener mListener;
público estático MyModalFragment getInstance () {
devolver nuevo MyModalFragment ();
}
@Anular
Vista pública onCreateView (inflador LayoutInflater, contenedor @Nullable ViewGroup, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate (R.layout.layout_custom_bottom_sheet, contenedor, falso);
((TextView) view.findViewById (R.id.textview)). SetText (LoremIpsum.LOREM_IPSUM);
view.findViewById (R.id.switch_bg_button) .setOnClickListener (v -> {
mListener.onFragmentInteraction ();
});
vista de retorno;
}
@Anular
public void onAttach (contexto contextual) {
super.onAttach (contexto);
if (instancia de contexto de OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) contexto;
} más {
lanzar nueva RuntimeException (context.toString ()
+ “debe implementar OnFragmentInteractionListener”);
}
}
@Anular
public void onDetach () {
super.onDetach ();
mListener = nulo;
}
interfaz pública OnFragmentInteractionListener {
anular onFragmentInteraction ();
}
}
Fragmento modal
ModalActivity de clase pública extiende AppCompatActivity implementa MyModalFragment.OnFragmentInteractionListener {
@Anular
vacío protegido onCreate (Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_modal);
MyModalFragment bottomSheetDialog = MyModalFragment.getInstance ();
bottomSheetDialog.show (getSupportFragmentManager (), “Hoja inferior personalizada”);
}
@Anular
public void onFragmentInteraction () {
findViewById (R.id.activity_modal) .setBackgroundColor (Color.MAGENTA);
}
}
Inicialización de fragmentos modales.
Ejemplo de rendimiento de la hoja inferior modal:
Google I / O 2016 Outtakes
Algunas de las características introducidas en Google I / O 2016 han demostrado ser un gran avance en la industria y, en ese sentido, tener el control de las nuevas tecnologías y características podría darle una ventaja sobre el resto de ellas en el desarrollo de aplicaciones.
Claramente, no hay ninguna razón por la que deba descuidar cualquiera de las ideas y características recién introducidas, ya que su viabilidad es a menudo impredecible y dictada por el mercado de manera espontánea. Es por eso que explorar tantas tecnologías populares como haya disponibles es vital para sus habilidades de desarrollo competitivo. Observemos de cerca lo que vendrá en 2017.
Más en nuestro blog!
Shakuro | Diseño web y desarrollo