java - studio - programacion android pdf 2018
Cómo tener una imagen de fondo a pantalla completa(con centro-recorte) que no cambia de tamaño (6)
Estoy tratando de establecer una foto como fondo de una Activity
. Quiero que el fondo sea una imagen de pantalla completa (sin bordes) .
Como quiero que la imagen llene el fondo de toda la actividad sin estirar / exprimir (es decir, escalas no proporcionales para X e Y) y no me importa si la foto debe recortarse, estoy usando un RelativeLayout
con un ImageView
(con android:scaleType="centerCrop"
) y el resto de mi diseño que consiste en un ScrollView
y sus hijos.
<!-- Tried this with a FrameLayout as well... -->
<RelativeLayout>
<!-- Background -->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
<!-- Form -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView>
<LinearLayout>
...
<EditText/>
</LinearLayout>
</ScrollView>
</LinearLayout>
</RelativeLayout>
El problema es que el resto del diseño tiene algunas vistas de EditText
y cuando aparece el teclado, el ImageView se redimensiona. Me gustaría que el fondo siguiera siendo el mismo, independientemente de si la softkeyboard es visible o no.
He visto muchas preguntas sobre SO acerca de cómo se redimensiona ImageViews pero (imo) no hay respuestas satisfactorias. La mayoría de ellos solo consiste en configurar el android:windowSoftInputMode="adjustPan"
, lo que no siempre es práctico, especialmente si desea que el usuario pueda desplazarse en la actividad, o usar getWindow().setBackgroundDrawable()
que no recortar la imagen.
Me las arreglé para sub-clase ImageView y anular su onMeasure()
(vea mi respuesta aquí: ImageView cambia de tamaño cuando se abre el teclado ) para que pueda forzar un alto y ancho fijos, igual a las dimensiones de la pantalla del dispositivo, de acuerdo con una bandera pero Me pregunto si hay una mejor manera de lograr el resultado que quiero.
Entonces, para resumir, mi pregunta es: ¿Cómo puedo configurar el fondo de una Actividad para que sea una foto de pantalla completa?
con el tipo de escala = "centerCrop", de modo que la foto se escala de manera uniforme (manteniendo su relación de aspecto) y, por lo tanto, ambas dimensiones (ancho y alto) serán iguales o más grandes que la dimensión correspondiente de la vista;
que no se redimensiona cuando se abre un softkeyboard;
RESPONDER:
Terminé siguiendo los consejos de BitmapDrawable
y subclasificé BitmapDrawable
(vea su respuesta a continuación). Tuve que hacer algunos ajustes para asegurarme de que BackgroundBitmapDrawable
siempre se escala y se corta de una manera que llena la pantalla.
Aquí está mi clase final, adaptada de su respuesta:
public class BackgroundBitmapDrawable extends BitmapDrawable {
private Matrix mMatrix = new Matrix();
private int moldHeight;
boolean simpleMapping = false;
public BackgroundBitmapDrawable(Resources res, Bitmap bitmap) {
super(res, bitmap);
}
@Override
protected void onBoundsChange(Rect bounds) {
if (bounds.height() > moldHeight) {
moldHeight = bounds.height();
Bitmap b = getBitmap();
RectF src = new RectF(0, 0, b.getWidth(), b.getHeight());
RectF dst;
if (simpleMapping) {
dst = new RectF(bounds);
mMatrix.setRectToRect(src, dst, ScaleToFit.CENTER);
} else {
// Full Screen Image -> Always scale and center-crop in order to fill the screen
float dwidth = src.width();
float dheight = src.height();
float vwidth = bounds.width();
float vheight = bounds.height();
float scale;
float dx = 0, dy = 0;
if (dwidth * vheight > vwidth * dheight) {
scale = (float) vheight / (float) dheight;
dx = (vwidth - dwidth * scale) * 0.5f;
} else {
scale = (float) vwidth / (float) dwidth;
dy = (vheight - dheight * scale) * 0.5f;
}
mMatrix.setScale(scale, scale);
mMatrix.postTranslate(dx, dy);
}
}
}
@Override
public void draw(Canvas canvas) {
canvas.drawColor(0xaa00ff00);
canvas.drawBitmap(getBitmap(), mMatrix, null);
}
}
Entonces solo es cuestión de crear un BackgroundBitmapDrawable
y configurarlo como el fondo de la vista raíz.
Cambia tu ScaleType
android:scaleType="FitXY"
y en tu manifiesto
<activity
android:name=".activity.MainActivity"
android:windowSoftInputMode="adjustPan|stateHidden" />
Crea un ImageView en tu xml. Colóquelo debajo de su etiqueta de diseño. Establezca la traducciónZ en un valor positivo, por ejemplo, 10dp y scaleType en centerCrop.
Después de rascarme la cabeza por un tiempo, esta ha sido mi solución "buena por ahora".
Compartir un ejemplo de XML que podría ser útil para cualquier persona.
<!-- RelativeLayout so that Views can overlap each other.
I believe a FrameLayout would work as well. -->
<RelativeLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- I''ve put the ImageView inside
a ScrollView with android:fillViewport="true" and android:isScrollContainer="false" -->
<ScrollView
android:id="@+id/backgroundScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:isScrollContainer="false" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- The FullScreen, Center-Cropped Image Background -->
<ImageView
android:id="@+id/backgroundImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/background_image" />
</LinearLayout>
</ScrollView>
<!-- The rest of the Views, containing the data entry form... -->
<LinearLayout
android:id="@+id/form"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ScrollView
android:id="@+id/formScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical" >
<!-- The "Form", with EditTexts, Checkboxes and whatnot... -->
</LinearLayout>
</ScrollView>
</LinearLayout>
</RelativeLayout>
Con este diseño, logro dos cosas:
formScrollView
, que contiene el "formulario" con los EditTexts, etc., se redimensiona (como quiero) y se puede desplazar cuando aparece la tecla programable.backgroundScrollView
, que contiene ImageView, no se redimensiona (debido aandroid:isScrollContainer="false"
) y llena toda la vista (android:fillViewport="true"
). Por lo tanto, el fondo sigue siendo el mismo, independientemente de si el teclado es visible o no.
No es una solución perfecta ya que ImageView
sufre de alguna manera una variación muy pequeña en su tamaño, pero el resultado es suficiente por ahora. Si alguien sabe una solución mejor, por favor hágamelo saber.
La solución en la respuesta es la mejor, para usarla:
Resources res = getActivity().getResources();
Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.some_image);
BackgroundBitmapDrawable background = new BackgroundBitmapDrawable(res, bitmap);
view.setBackgroundDrawable(background);
o
view.setBackground(background);
para API 16 y superior.
Ponga todo en un FrameLayout, con el primer hijo una vista de imagen que coincidirá con su padre (frameLayout) y usted lo configurará como desee en su fondo, y delante de la vista de imagen colocará lo que quiera (LinearLayout, supongo)
pruebe este LayerDrawable (res / drawable / backlayer.xml):
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
>
<item>
<shape>
<solid android:color="#f00" />
</shape>
</item>
<item>
<bitmap
android:gravity="top" android:src="@drawable/back1">
</bitmap>
</item>
</layer-list>
y configúrelo en su diseño de nivel superior: android: background = "@ drawable / backlayer"
ACTUALIZACIÓN: pruebe este BitmapDrawadle, configúrelo en el diseño de nivel superior (setBackgroundDrawable ()), si simpleMapping == true es suficiente, puede eliminar la rama "else":
class D extends BitmapDrawable {
private Matrix mMatrix = new Matrix();
private int moldHeight;
public D(Resources res, Bitmap bitmap) {
super(res, bitmap);
}
@Override
protected void onBoundsChange(Rect bounds) {
if (bounds.height() > moldHeight) {
moldHeight = bounds.height();
Bitmap b = getBitmap();
RectF src = new RectF(0, 0, b.getWidth(), b.getHeight());
RectF dst;
// if simpleMapping is good enough then remove "else" branch and
// declare "dst" as:
// RectF dst = new RectF(bounds);
boolean simpleMapping = true;
if (simpleMapping) {
dst = new RectF(bounds);
} else {
float x = bounds.exactCenterX();
dst = new RectF(x, 0, x, bounds.height());
float scale = bounds.height() / src.height();
float dx = scale * src.width() / 2;
dst.inset(-dx, 0);
}
mMatrix.setRectToRect(src, dst, ScaleToFit.CENTER);
}
}
@Override
public void draw(Canvas canvas) {
canvas.drawColor(0xaa00ff00);
canvas.drawBitmap(getBitmap(), mMatrix, null);
}
}