<img src = "https://www.androidhive.info/wp-content/uploads/2019/02/android -image-pick-and-crop-tutorial-1.jpg "alt =" android-image-pick-and-crop-tutorial (1) [19659006] 1. uCrop - biblioteca de recorte
Para funcionalidad de recorte , utilizaremos la biblioteca uCrop. Esta biblioteca es utilizada por muchas aplicaciones populares y probada en varios dispositivos / versiones del sistema operativo. Aunque la biblioteca ofrece la mejor experiencia de recorte, no proporcionará una opción para elegir la imagen. entrada de la cámara o galería. Todo lo que necesita es un mapa de bits y devuelve el mapa de bits recortado.
En este artículo usamos la misma biblioteca de recorte, pero por encima, crearemos una función para para elegir el imagen de la cámara o galería .
Para obtener información sobre uCrop, visite la documentación oficial.
2. Inicio de una nueva tarjeta project / profile rm
Nuestro objetivo es crear una interfaz de usuario de perfil social simple (como Instagram) y utilizar la función de recorte de imagen para aplicar la imagen de perfil. Puede tomar una foto con la cámara o elegir de la galería, recortarla y configurarla como una foto de perfil. Comencemos creando un nuevo proyecto en Android Studio.
1 . Cree un nuevo proyecto en Android Studio desde Archivo ⇒ Nuevo proyecto y seleccione Actividades básicas de los modelos. Di el nombre de mi paquete como info.androidhive.imagepicker
2 . Abra app / build.gradle y agregue las dependencias Dexter, ButterKnife, Glide, CircularImageView y uCrop.
dependencias {
// ...
// Cuchillo de mantequilla
implementación "com.jakewharton: butterknife: 8.8.1"
AnnotationProcessor & # 39; com.jakewharton: compilador de navajas: 8.8.1 & # 39;
// permisos dexter
implementación "com.karumi: dexter: 5.0.0"
// vista de imagen circular
implementación & # 39; com.mikhaellopez: circularimageview: 3.2.0 & # 39;
// deslizamiento
implementación & # 39; com.github.bumptech.glide: glide: 4.7.1 & # 39;
implementación "com.github.bumptech.glide: anotaciones: 4.7.1"
implementación (& # 39; com.github.bumptech.glide: okhttp3 -integration: 4.0.0 & # 39;) {
excluir grupo: & # 39; glide-parent & # 39;
}
AnnotationProcessor & # 39; com.github.bumptech.glide: compilador: 4.7.1 & # 39;
implementación & # 39; com.github.yalantis: ucrop: 2.2.2 & # 39;
}
3 . Agregue los siguientes recursos a sus respectivos archivos strings.xml dimen.xml y colors.xml .
Selección de imagen & amp; Crop
Configuración
Rowan Sebastian Atkinson CBE es un actor, comediante y guionista inglés
Sr. Bean
seguidor
seguidor
seguidor
. No se puede configurar la imagen de perfil. ¡Inténtalo de nuevo!
Establecer imagen de perfil
Tomar una foto
Elegir de la galería
¡Falta la opción para seleccionar las imágenes!
sans-serif-light
sans-serif-medium
sans-serif
sans-serif-condensed
sans-serif-black
sans-serif-thin
Autorizaciones concesión
Esta aplicación requiere autorización para usar esta función. Puede otorgarlos en la configuración de la aplicación.
CONFIGURACIONES GOTO
16dp
90dp
20dp
16dp
23dp
13dp
20dp
12dp
12dp
196590469 28dp [1990#5770f3[19659048] # 5770f3 [19659049] # D81B60 [19659050] # 5770f3 [19659051] # 8e5aeb [19659052] # D1D1FF [19659053] # 000000 [19659054] # e0e0e0
4 . Descargue esta carpeta res y agregue el contenido a la carpeta res de su proyecto. Esta carpeta contiene los iconos necesarios para crear la pantalla de perfil.
5 . Abra el archivo de diseño de su actividad principal ( activity_main.xml ) y agregue el siguiente código para obtener el diseño del perfil.
Cree un nuevo diseño xml layout_toolbar_profile.xml y agregue el siguiente código.
Ahora, si ejecuta su proyecto, debería poder ver la pantalla como se muestra a continuación.
3. Agregar la selección de imagen y la función de recorte
Ahora que la parte de la interfaz de usuario está terminada, veamos cómo agregar la funcionalidad de selección de imagen tocando la imagen de perfil o el ícono más.
6 . Cree un archivo xml llamado file_paths.xml en la carpeta res ⇒ xml . Si no ve la carpeta xml debajo de res, cree una nueva carpeta con el mismo nombre. Aquí estamos definiendo una ruta FileProvider para almacenar imágenes de la cámara en una ubicación en caché en lugar de almacenarlas en la galería.
7 . Abra AndroidManifest.xml y realice los siguientes cambios.
> Agregar INTERNET CÁMARA y 1901 [45autorizaciones
> Agregar UCropActivity intención de comenzar El negocio del recorte.
> Agregar FileProvider usamos la información x definida en el paso anterior.
8 . Mientras usamos Glide para mostrar la imagen, cree una clase llamada MyGlideModule y observe la clase con @GlideModule .
información del paquete.androidhive.imagepicker;
import com.bumptech.glide.annotation.GlideModule;
importar com.bumptech.glide.module.AppGlideModule;
@GlideModule
clase pública MyGlideModule extiende AppGlideModule {
}
9 . Para reducir la complejidad, escribí una actividad que trata con la elección de la imagen y el recorte. Todo lo que tiene que hacer es agregar este negocio a su proyecto y llamar a un par de líneas para comenzar el negocio. Eso es todo.
Cree una actividad vacía ImagePickerActivity.java y agregue el siguiente código.
paquete info.androidhive.imagepicker;
importar android.Manifest;
importar android.app.Activity;
importar android.content.ContentResolver;
importar android.content.Context;
importar android.content.Intent;
importar android.database.Cursor;
importar android.net.Uri;
importar android.os.Bundle;
importar android.provider.MediaStore;
importar android.provider.OpenableColumns;
importar android.support.v4.content.ContextCompat;
importar android.support.v7.app.AlertDialog;
importar android.support.v7.app.AppCompatActivity;
importar android.util.Log;
importar android.widget.Toast;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
import com.yalantis.ucrop.UCrop;
import java.io.File;
import java.util.List;
importar android.support.v4.content.FileProvider.getUriForFile estático;
ImagePickerActivity de clase pública extiende AppCompatActivity {
Cadena final estática privada TAG = ImagePickerActivity.class.getSimpleName ();
cadena estática pública final INTENT_IMAGE_PICKER_OPTION = "image_picker_option";
cadena estática pública final INTENT_ASPECT_RATIO_X = "Aspect_ratio_x";
cadena estática final pública INTENT_ASPECT_RATIO_Y = "Aspect_ratio_Y";
cadena estática pública final INTENT_LOCK_ASPECT_RATIO = "lock_aspect_ratio";
cadena estática final pública INTENT_IMAGE_COMPRESSION_QUALITY = "compresión_calidad";
cadena estática pública final INTENT_SET_BITMAP_MAX_WIDTH_HEIGHT = "set_bitmap_max_width_height";
cadena estática pública final INTENT_BITMAP_MAX_WIDTH = "max_width";
cadena estática pública final INTENT_BITMAP_MAX_HEIGHT = "max_height";
stat pública final int REQUEST_IMAGE_CAPTURE = 0;
estadística final pública estática REQUEST_GALLERY_IMAGE = 1;
private boolean lockAspectRatio = false, setBitmapMaxWidthHeight = false;
private int ASPECT_RATIO_X = 16, ASPECT_RATIO_Y = 9, bitmapMaxWidth = 1000, bitmapMaxHeight = 1000;
private int IMAGE_COMPRESSION = 80;
nombre de archivo de cadena estática pública;
interfaz pública PickerOptionListener {
anular onTakeCameraSelected ();
nulo enChooseGallerySelected ();
}
@Oltrepassare
Void onCreate protegido (paquete savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_image_picker);
Intención intent = getIntent ();
if (intento == nulo) {
Toast.makeText (getApplicationContext (), getString (R.string.toast_image_intent_null), Toast.LENGTH_LONG) .show ();
regreso;
}
ASPECT_RATIO_X = intent.getIntExtra (INTENT_ASPECT_RATIO_X, ASPECT_RATIO_X);
ASPECT_RATIO_Y = intent.getIntExtra (INTENT_ASPECT_RATIO_Y, ASPECT_RATIO_Y);
IMAGE_COMPRESSION = intent.getIntExtra (INTENT_IMAGE_COMPRESSION_QUALITY, IMAGE_COMPRESSION);
lockAspectRatio = intent.getBooleanExtra (INTENT_LOCK_ASPECT_RATIO, falso);
setBitmapMaxWidthHeight = intent.getBooleanExtra (INTENT_SET_BITMAP_MAX_WIDTH_HEIGHT, falso);
bitmapMaxWidth = intent.getIntExtra (INTENT_BITMAP_MAX_WIDTH, bitmapMaxWidth);
bitmapMaxHeight = intent.getIntExtra (INTENT_BITMAP_MAX_HEIGHT, bitmapMaxHeight);
int requestCode = intent.getIntExtra (INTENT_IMAGE_PICKER_OPTION, -1);
if (requestCode == REQUEST_IMAGE_CAPTURE) {
takeCameraImage ();
} otro {
chooseImageFromGallery ();
}
}
public static void showImagePickerOptions (Contexto contextual, Lister PickerOptionListener) {
// configurar el generador de alertas
AlertDialog.Builder builder = nuevo AlertDialog.Builder (contexto);
builder.setTitle (context.getString (R.string.lbl_set_profile_photo));
// agrega una lista
Cadena [] animales = {context.getString (R.string.lbl_take_camera_picture), context.getString (R.string.lbl_choose_from_gallery)};
builder.setItems (animales, (diálogo, cuál) -> {
cambiar (cuál) {
caso 0:
listener.onTakeCameraSelected ();
descanso;
caso 1:
listener.onChooseGallerySelected ();
descanso;
}
});
// crea y muestra la ventana de advertencia
AlertDialog dialog = builder.create ();
Dialog.Show ();
}
private void takeCameraImage () {
Dexter.withActivity (this)
.withPermissions (Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.withListener (nuevo MultiplePermissionsListener () {
@Oltrepassare
public void onPermissionsChecked (informe MultiplePermissionsReport) {
if (report.areAllPermissionsGranted ()) {
fileName = System.currentTimeMillis () + ".jpg";
Intento takePictureIntent = nuevo intento (MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra (MediaStore.EXTRA_OUTPUT, getCacheImagePath (fileName));
if (takePictureIntent.resolveActivity (getPackageManager ())! = null) {
startActivityForResult (takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
@Oltrepassare
public void onPermissionRationaleShouldBeShown (Lista de autorización token PermissionToken) {
token.continuePermissionRequest ();
}
}). echar un vistazo ();
}
privado en blanco chooseImageFromGallery () {
Dexter.withActivity (this)
.withPermissions (Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.withListener (nuevo MultiplePermissionsListener () {
@Oltrepassare
public void onPermissionsChecked (informe MultiplePermissionsReport) {
if (report.areAllPermissionsGranted ()) {
Intención pickPhoto = nueva intención (Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult (pickPhoto, REQUEST_GALLERY_IMAGE);
}
}
@Oltrepassare
public void onPermissionRationaleShouldBeShown (Lista de autorización token PermissionToken) {
token.continuePermissionRequest ();
}
}). echar un vistazo ();
}
vacío protegido en OnActivityResult (int requestCode, int resultCode, Intent data) {
switch (requestCode) {
Caso REQUEST_IMAGE_CAPTURE:
if (resultCode == RESULT_OK) {
cropImage (getCacheImagePath (fileName));
} otro {
setResultCancelled ();
}
descanso;
Caso REQUEST_GALLERY_IMAGE:
if (resultCode == RESULT_OK) {
Uri imageUri = data.getData ();
cropImage (imageUri);
} otro {
setResultCancelled ();
}
descanso;
UCrop.REQUEST_CROP casas:
if (resultCode == RESULT_OK) {
handleUCropResult (datos);
} otro {
setResultCancelled ();
}
descanso;
Caso UCrop.RESULT_ERROR:
final Throwable cropError = UCrop.getError (datos);
Log.e (TAG, "Error de recorte:" + cropError);
setResultCancelled ();
descanso;
defecto:
setResultCancelled ();
}
}
privado vacío cropImage (Uri sourceUri) {
Uri destinationUri = Uri.fromFile (nuevo archivo (getCacheDir (), queryName (getContentResolver (), sourceUri)));
Opciones de UCrop.Options = new UCrop.Options ();
options.setCompressionQuality (IMAGE_COMPRESSION);
options.setToolbarColor (ContextCompat.getColor (este, R.color.colorPrimary));
options.setStatusBarColor (ContextCompat.getColor (este, R.color.colorPrimary));
options.setActiveWidgetColor (ContextCompat.getColor (este, R.color.colorPrimary));
if (lockAspectRatio)
options.withAspectRatio (ASPECT_RATIO_X, ASPECT_RATIO_Y);
if (setBitmapMaxWidthHeight)
opciones.conMaxResultSize (bitmapMaxWidth, bitmapMaxHeight);
UCrop.of (sourceUri, destinationUri)
.withOptions (opciones)
.start (esto);
}
mango vacío privadoUCropResult (Datos de intención) {
if (datos == nulo) {
setResultCancelled ();
regreso;
}
Resultado final Uri = UCrop.getOutput (datos);
setResultOk (resultUri);
}
setResultOk privado vacío (Uri imagePath) {
Intención intención = nueva intención ();
intent.putExtra ("ruta", imagePath);
setResult (Activity.RESULT_OK, intento);
para terminar();
}
privado void setResultCancelled () {
Intención intención = nueva intención ();
setResult (Activity.RESULT_CANCELED, intento);
para terminar();
}
Private Uri getCacheImagePath (String fileName) {
Ruta del archivo = archivo nuevo (getExternalCacheDir (), "camera");
if (! path.exists ()) path.mkdirs ();
Imagen de archivo = archivo nuevo (ruta, nombre de archivo);
return getUriForFile (ImagePickerActivity.this, getPackageName () + ".provider", image);
}
queryName de cadena estática privada (solucionador ContentResolver, Uri uri) {
Cursor returnCursor =
resolver.query (uri, nulo, nulo, nulo, nulo);
afirmar returnCursor! = nulo;
int nameIndex = returnCursor.getColumnIndex (OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst ();
Nombre de cadena = returnCursor.getString (nameIndex);
returnCursor.close ();
nombre de retorno;
}
/ **
* Llamar de esta manera eliminará las imágenes del directorio de caché
* útil para borrar algo de memoria
* /
public static void clearCache (contexto de contexto) {
Ruta del archivo = archivo nuevo (context.getExternalCacheDir (), "camera");
if (path.exists () && path.isDirectory ()) {
for (Archivo secundario: path.listFiles ()) {
child.delete ();
}
}
}
}
3.1 Inicio de la actividad de copiado
Para mostrar las opciones de selección de imagen, llame al método ImagePickerActivity.showImagePickerOptions () .
ImagePickerActivity.showImagePickerOptions (esto, nuevoPPerer ImagePicker (ImagePicker)
@Oltrepassare
public void onTakeCameraSelected () {
// launchCameraIntent ();
}
@Oltrepassare
public void onChooseGallerySelected () {
// launchGalleryIntent ();
}
});
Después de seleccionar una opción, puede pasar datos de intención según su elección. Por ejemplo, para seleccionar la imagen de la galería con una relación de aspecto 1 × 1 puede usar la intención a continuación.
Intención intención = nueva intención (MainActivity.this, ImagePickerActivity.class);
intent.putExtra (ImagePickerActivity.INTENT_IMAGE_PICKER_OPTION, ImagePickerActivity.REQUEST_IMAGE_CAPTURE);
// establecer la relación de aspecto
intent.putExtra (ImagePickerActivity.INTENT_LOCK_ASPECT_RATIO, verdadero);
intent.putExtra (ImagePickerActivity.INTENT_ASPECT_RATIO_X, 1); // 16x9, 1x1, 3: 4, 3: 2
intent.putExtra (ImagePickerActivity.INTENT_ASPECT_RATIO_Y, 1);
startActivityForResult (intento, REQUEST_IMAGE);
10 . Ahora veremos cómo se puede aplicar esto a nuestra actividad de perfil. Abra MainActivity.java y llame a la actividad de selección de imagen tocando la foto de perfil o el ícono más.
paquete info.androidhive.imagepicker;
importar android.Manifest;
importar android.app.Activity;
importar android.content.Intent;
importar android.graphics.Bitmap;
importar android.net.Uri;
importar android.os.Bundle;
importar android.provider.MediaStore;
importar android.provider.Settings;
importar android.support.annotation.Nullable;
importar android.support.v4.content.ContextCompat;
importar android.support.v7.app.AlertDialog;
importar android.support.v7.app.AppCompatActivity;
importar android.support.v7.widget.Toolbar;
importar android.util.Log;
importar android.widget.ImageView;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
import java.io.IOException;
import java.util.List;
importar butterknife.BindView;
Cuchillo de mantequilla de importación. ButterKnife;
Cuchillo de mantequilla de importación. OnClick;
clase pública MainActivity extiende AppCompatActivity {
Cadena de finalización estática privada TAG = MainActivity.class.getSimpleName ();
stat pública final int REQUEST_IMAGE = 100;
@BindView (R.id.img_profile)
ImageView imgProfile;
@Oltrepassare
Void onCreate protegido (paquete savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_main);
ButterKnife.bind (esto);
Barra de herramientas barra de herramientas = findViewById (R.id.toolbar);
setSupportActionBar (barra de herramientas);
getSupportActionBar () setDisplayHomeAsUpEnabled (true).;
. GetSupportActionBar () setTitle (null);
loadProfileDefault ();
// Eliminar imágenes antiguas del directorio de caché
// no llame a esta línea si desea elegir varias imágenes en la misma actividad
// llama a esto una vez que hayas terminado de usar el mapa de bits
ImagePickerActivity.clearCache (esto);
}
private void loadProfile (URL de cadena) {
Log.d (TAG, "Ruta de caché de imagen:" + url);
GlideApp.with (this) .load (url)
.into (imgProfile);
imgProfile.setColorFilter (ContextCompat.getColor (this, android.R.color.transparent));
}
private void loadProfileDefault () {
GlideApp.with (this) .load (R.drawable.baseline_account_circle_black_48)
.into (imgProfile);
imgProfile.setColorFilter (ContextCompat.getColor (este, R.color.profile_default_tint));
}
@OnClick ({R.id.img_plus, R.id.img_profile})
anular onProfileImageClick () {
Dexter.withActivity (this)
.withPermissions (Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.withListener (nuevo MultiplePermissionsListener () {
@Oltrepassare
public void onPermissionsChecked (informe MultiplePermissionsReport) {
if (report.areAllPermissionsGranted ()) {
showImagePickerOptions ();
}
if (report.isAnyPermissionPermanentlyDenied ()) {
showSettingsDialog ();
}
}
@Oltrepassare
public void onPermissionRationaleShouldBeShown (Lista de autorización token PermissionToken) {
token.continuePermissionRequest ();
}
}). echar un vistazo ();
}
privado vacío showImagePickerOptions () {
ImagePickerActivity.showImagePickerOptions (esto, nuevo ImagePickerActivity.PickerOptionListener () {
@Oltrepassare
public void onTakeCameraSelected () {
launchCameraIntent ();
}
@Oltrepassare
public void onChooseGallerySelected () {
launchGalleryIntent ();
}
});
}
private void launchCameraIntent () {
Intención intención = nueva intención (MainActivity.this, ImagePickerActivity.class);
intent.putExtra (ImagePickerActivity.INTENT_IMAGE_PICKER_OPTION, ImagePickerActivity.REQUEST_IMAGE_CAPTURE);
// establecer la relación de aspecto
intent.putExtra (ImagePickerActivity.INTENT_LOCK_ASPECT_RATIO, verdadero);
intent.putExtra (ImagePickerActivity.INTENT_ASPECT_RATIO_X, 1); // 16x9, 1x1, 3: 4, 3: 2
intent.putExtra (ImagePickerActivity.INTENT_ASPECT_RATIO_Y, 1);
// establecer el ancho y alto máximos del mapa de bits
intent.putExtra (ImagePickerActivity.INTENT_SET_BITMAP_MAX_WIDTH_HEIGHT, verdadero);
intent.putExtra (ImagePickerActivity.INTENT_BITMAP_MAX_WIDTH, 1000);
intent.putExtra (ImagePickerActivity.INTENT_BITMAP_MAX_HEIGHT, 1000);
startActivityForResult (intento, REQUEST_IMAGE);
}
private void launchGalleryIntent () {
Intención intención = nueva intención (MainActivity.this, ImagePickerActivity.class);
intent.putExtra (ImagePickerActivity.INTENT_IMAGE_PICKER_OPTION, ImagePickerActivity.REQUEST_GALLERY_IMAGE);
// establecer la relación de aspecto
intent.putExtra (ImagePickerActivity.INTENT_LOCK_ASPECT_RATIO, verdadero);
intent.putExtra (ImagePickerActivity.INTENT_ASPECT_RATIO_X, 1); // 16x9, 1x1, 3: 4, 3: 2
intent.putExtra (ImagePickerActivity.INTENT_ASPECT_RATIO_Y, 1);
startActivityForResult (intento, REQUEST_IMAGE);
}
@Oltrepassare
protegido en onActivityResult vacío (int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == REQUEST_IMAGE) {
if (resultCode == Activity.RESULT_OK) {
Uri uri = data.getParcelableExtra ("ruta");
tratar {
// Puede actualizar este mapa de bits en su servidor
Mapa de bits mapa de bits = MediaStore.Images.Media.getBitmap (this.getContentResolver (), uri);
// cargando la imagen de perfil desde el caché local
Perfil de carga (uri.toString ());
} catch (IOException e) {
e.printStackTrace ();
}
}
}
}
/ **
* Visualización de la ventana de advertencia con la opción Configuración
* Navegue al usuario a la configuración de la aplicación
* NOTA: mantenga el título y el mensaje correctos según su aplicación
* /
showSettingsDialog privado privado () {
AlertDialog.Builder builder = nuevo AlertDialog.Builder (MainActivity.this);
builder.setTitle (getString (R.string.dialog_permission_title));
builder.setMessage (getString (R.string.dialog_permission_message));
builder.setPositiveButton (getString (R.string.go_to_settings), (diálogo, que) -> {
dialog.cancel ();
configuración abierta ();
});
builder.setNegativeButton (getString (android.R.string.cancel), (dialog, that) -> dialog.cancel ());
builder.show ();
}
// navega al usuario a la configuración de la aplicación
nulo privado openSettings () {
Intención intención = nueva intención (Configuración.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts ("paquete", getPackageName (), nulo);
intent.setData (uri);
startActivityForResult (intento, 101);
}
}
Ahora ejecuta y prueba la aplicación. Debería poder configurar la imagen de perfil desde la cámara o galería.
Hola, soy fundador de androidhive y entusiasta de la programación. Mis habilidades incluyen Android, iOS, PHP, Ruby on Rails y mucho más. ¿Tienes alguna idea de que te gustaría que desarrolle? Hablamos: ravi@androidhive.info
Entradas relacionadas