Aplikasi Sosmed Sederhana dengan Image Cropping Android Studio

posted in: Tutorial | 0

Pernah penasaran gak bagaimana aplikasi sosial media seperti Instagram, WhatsApp, dan sebagainya dibuat? Nah kali ini walaupun belum sampai sejauh itu, tapi kita akan mencoba belajar membuat aplikasi sosmed sederhana dengan image cropping menggunakan Android Studio.

Mengambil gambar dari kamera atau galeri adalah fitur penting untuk aplikasi yang menyertakan media dalam aplikasi mereka.

Aplikasi catatan sederhana mungkin memerlukan gambar profil untuk membuat catatan lebih pribadi.

Mendapatkan gambar mini dari kamera itu mudah, tetapi kadang-kadang Anda menginginkan gambar resolusi penuh tanpa menyimpannya di galeri, memotongnya dan menghindari kemungkinan pengecualian memori.

Dalam tutorial ini kita akan belajar membangun UI profil media sederhana, memilih gambar profil dari kamera atau galeri dengan fitur crop dan transformasi gambar.

uCrop – Cropping Library

Untuk fungsi cropping, kita akan menggunakan library tambahan yakni uCrop. Library ini digunakan banyak aplikasi populer dan diuji pada berbagai perangkat / versi OS. Meskipun library ini memberikan pengalaman pemangkasan terbaik, namun tidak akan memberikan opsi untuk memilih gambar input dari kamera atau galeri. Yang diperlukan hanyalah bitmap dan mengembalikan bitmap yang dipotong.

Di artikel ini kami menggunakan pustaka pemangkasan yang sama tetapi di atasnya, kami akan membangun fitur untuk memilih gambar dari kamera atau galeri.

Preview aplikasi cropping
Preview aplikasi cropping

Memulai Project Baru/Profile Screen

Tujuan aplikasi ini adalah untuk membangun UI profil sosial media sederhana (seperti Instagram) dan menggunakan fungsionalitas pemangkasan gambar untuk menerapkan gambar profil. Anda dapat mengambil gambar menggunakan kamera atau memilih dari galeri, memotong dan mengaturnya sebagai gambar profil. Jadi mari kita mulai dengan membuat proyek baru di Android Studio.

  1. Buat project baru di Android Studio dari File ⇒ New Project dan pilih Basic Activity dari template. Berikan nama paket misalnya sebagai info.androidhive.imagepicker
  2. Buka app/build.gradle dan tambahkan dependensi Dexter, ButterKnife, Glide, CircularImageView, dan uCrop.
    build.gradle
dependencies {
    // ...
 
    //Butterknife
    implementation 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
 
    //dexter permissions
    implementation "com.karumi:dexter:5.0.0"
 
    // circular imageview
    implementation 'com.mikhaellopez:circularimageview:3.2.0'
 
    //Glide
    implementation 'com.github.bumptech.glide:glide:4.7.1'
    implementation 'com.github.bumptech.glide:annotations:4.7.1'
    implementation('com.github.bumptech.glide:okhttp3-integration:4.0.0') {
        exclude group: 'glide-parent'
    }
    annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
 
    implementation 'com.github.yalantis:ucrop:2.2.2'
}

  1. Tambahkan resource di bawah ini ke file strings.xml, dimen.xml dan colors.xml masing-masing.
    strings.xml
<resources>
    <string name="app_name">Image Pick &amp; Crop</string>
    <string name="action_settings">Settings</string>
    <string name="profile_desc">Rowan Sebastian Atkinson CBE is an English actor,  comedian and screenwriter</string>
    <string name="profile_title">Mr Bean</string>
    <string name="posts">posts</string>
    <string name="followers">followers</string>
    <string name="following">following</string>
    <string name="msg_error_unable_select_profile_pic">Unable to set profile image. Please try again!</string>
    <string name="lbl_set_profile_photo">Set profile image</string>
    <string name="lbl_take_camera_picture">Take a picture</string>
    <string name="lbl_choose_from_gallery">Choose from gallery</string>
    <string name="toast_image_intent_null">Image picker option is missing!</string>
 
    <!-- font families -->
    <string name="font_family_light">sans-serif-light</string>
    <string name="font_family_medium">sans-serif-medium</string>
    <string name="font_family_regular">sans-serif</string>
    <string name="font_family_condensed">sans-serif-condensed</string>
    <string name="font_family_black">sans-serif-black</string>
    <string name="font_family_thin">sans-serif-thin</string>
    <string name="dialog_permission_title">Grant Permissions</string>
    <string name="dialog_permission_message">This app needs permission to use this feature. You can grant them in app settings.</string>
    <string name="go_to_settings">GOTO SETTINGS</string>
</resources>

dimen.xml

<resources>
    <dimen name="fab_margin">16dp</dimen>
    <dimen name="toolbar_profile_width">90dp</dimen>
    <dimen name="dimen_20dp">20dp</dimen>
    <dimen name="activity_padding">16dp</dimen>
    <dimen name="profile_title">23dp</dimen>
    <dimen name="profile_desc">13dp</dimen>
    <dimen name="meta_count">20dp</dimen>
    <dimen name="meta_label">12dp</dimen>
    <dimen name="dimen_40dp">40dp</dimen>
    <dimen name="ic_plus_width">28dp</dimen>
</resources>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#5770f3</color>
    <color name="colorPrimaryDark">#5770f3</color>
    <color name="colorAccent">#D81B60</color>
    <color name="gradient_start">#5770f3</color>
    <color name="gradient_end">#8e5aeb</color>
    <color name="profile_desc">#D1D1FF</color>
    <color name="bg_meta_container">#000000</color>
    <color name="profile_default_tint">#e0e0e0</color>
</resources>

  1. Unduh folder res di link https://api.androidhive.info/res/image-picker/res.zip
    Kemudian tambahkan konten ke folder res project kalian. Folder ini berisi ikon-ikon yang diperlukan untuk membangun layar profil.

  2. Buka layout file activity utama (activity_main.xml) dan tambahkan kode di bawah ini untuk mencapai tata letak profil.
    activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
 
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">
 
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />
 
        <include layout="@layout/layout_toolbar_profile" />
 
    </android.support.design.widget.AppBarLayout>
 
    <include layout="@layout/content_main" />
 
</android.support.design.widget.CoordinatorLayout>

Buat layout xml baru  yang bernama layout_toolbar_profile.xml lalu tambahkan kode berikut.

layout_toolbar_profile.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:orientation="vertical">
 
    <RelativeLayout
        android:layout_width="@dimen/toolbar_profile_width"
        android:layout_height="wrap_content">
 
        <com.mikhaellopez.circularimageview.CircularImageView
            android:id="@+id/img_profile"
            android:layout_width="@dimen/toolbar_profile_width"
            android:layout_height="@dimen/toolbar_profile_width"
            android:layout_marginTop="@dimen/activity_padding"
            android:layout_marginBottom="@dimen/activity_padding"
            android:scaleType="centerInside"
            android:src="@drawable/baseline_account_circle_black_48"
            app:civ_border_color="@android:color/white"
            app:civ_border_width="2dp" />
 
        <com.mikhaellopez.circularimageview.CircularImageView
            android:id="@+id/img_plus"
            android:layout_width="@dimen/ic_plus_width"
            android:layout_height="@dimen/ic_plus_width"
            android:layout_alignBottom="@id/img_profile"
            android:layout_alignParentRight="true"
            android:src="@drawable/ic_plus"
            app:civ_shadow="true"
            app:civ_shadow_radius="1" />
    </RelativeLayout>
 
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:fontFamily="@string/font_family_medium"
        android:text="@string/profile_title"
        android:textColor="@android:color/white"
        android:textSize="@dimen/profile_title" />
 
    <TextView
        android:id="@+id/profile_desc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/dimen_40dp"
        android:gravity="center_horizontal"
        android:paddingLeft="@dimen/dimen_20dp"
        android:paddingRight="@dimen/dimen_20dp"
        android:text="@string/profile_desc"
        android:textColor="@color/profile_desc"
        android:textSize="@dimen/profile_desc" />
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/bg_meta_container"
        android:orientation="horizontal"
        android:paddingTop="@dimen/activity_padding"
        android:paddingBottom="@dimen/activity_padding"
        android:weightSum="3">
 
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="vertical">
 
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="1320"
                android:textColor="@android:color/white"
                android:textSize="@dimen/meta_count"
                android:textStyle="bold" />
 
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fontFamily="@string/font_family_condensed"
                android:text="@string/posts"
                android:textColor="@android:color/white"
                android:textSize="@dimen/meta_label" />
        </LinearLayout>
 
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="vertical">
 
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="4.3m"
                android:textColor="@android:color/white"
                android:textSize="@dimen/meta_count"
                android:textStyle="bold" />
 
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fontFamily="@string/font_family_condensed"
                android:text="@string/followers"
                android:textColor="@android:color/white"
                android:textSize="@dimen/meta_label" />
        </LinearLayout>
 
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="vertical">
 
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="123"
                android:textColor="@android:color/white"
                android:textSize="@dimen/meta_count"
                android:textStyle="bold" />
 
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fontFamily="@string/font_family_condensed"
                android:text="@string/following"
                android:textColor="@android:color/white"
                android:textSize="@dimen/meta_label" />
        </LinearLayout>
    </LinearLayout>
 
</LinearLayout>

Sekarang jalankan project kalian, apakah muncul tampilan layar seperti di bawah ini?

Tampilan sementara aplikasi sosmed sederhana
Tampilan sementara aplikasi sosmed sederhana

Jika iya, berarti kalian boleh lanjut. Jika tidak, pasti ada yang salah dengan kode kalian. Coba dicek lagi. Ada kesulitan? Tinggalkan jejak di kolom komentar

Menambahkan Fungsionalitas Ambil dan Crop Gambar

Sekarang setelah bagian UI selesai, mari kita lihat bagaimana cara menambahkan fungsionalitas pengambilan gambar dengan men-tap gambar profil atau ikon plus.

  1. Buat file xml bernama file_paths.xml di bawah folder res ⇒ xml. Jika kalian tidak melihat folder xml di bawah res, buat folder baru dengan nama yang sama. Di sini kita mendefinisikan FileProvider untuk menyimpan gambar kamera di lokasi yang di-cache alih-alih menyimpannya di galeri.

file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-cache-path
        name="cache"
        path="camera" />
</paths>

  1. Buka AndroidManifest.xml dan lakukan perubahan di bawah ini.
    • > Tambahkan izin INTERNET, CAMERA dan STORAGE.
    • > Tambahkan maksud UCropActivity untuk meluncurkan aktivitas crop.
    • > Tambahkan informasi FileProvider menggunakan xml yang telah kami tentukan pada langkah di atas.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="info.androidhive.imagepicker">
 
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="GoogleAppIndexingWarning">
        <activity android:name=".ImagePickerActivity" />
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
        <!-- uCrop cropping activity -->
        <activity
            android:name="com.yalantis.ucrop.UCropActivity"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme.NoActionBar" />
 
        <!-- cache directory file provider paths -->
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>
 
</manifest>

  1. Kita akan menggunakan Glide untuk menampilkan gambar, buat kelas bernama MyGlideModule dan beri catatan pada kelas dengan @GlideModule.

MyGlideModule.java

package info.androidhive.imagepicker;
 
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;
 
@GlideModule
public class MyGlideModule extends AppGlideModule {
}

  1. Untuk mengurangi kerumitan, saya telah menulis kegiatan yang menangani pemilihan gambar dan pemotongan. Yang harus Anda lakukan adalah, tambahkan aktivitas ini ke proyek Anda dan panggil beberapa baris untuk memulai aktivitas. Itu saja.

    Buat activity kosong bernama ImagePickerActivity.java dan tambahkan kode di bawah ini.

ImagePickerActivity.java

package info.androidhive.imagepicker;
 
import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import 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;
 
import static android.support.v4.content.FileProvider.getUriForFile;
 
public class ImagePickerActivity extends AppCompatActivity {
    private static final String TAG = ImagePickerActivity.class.getSimpleName();
    public static final String INTENT_IMAGE_PICKER_OPTION = "image_picker_option";
    public static final String INTENT_ASPECT_RATIO_X = "aspect_ratio_x";
    public static final String INTENT_ASPECT_RATIO_Y = "aspect_ratio_Y";
    public static final String INTENT_LOCK_ASPECT_RATIO = "lock_aspect_ratio";
    public static final String INTENT_IMAGE_COMPRESSION_QUALITY = "compression_quality";
    public static final String INTENT_SET_BITMAP_MAX_WIDTH_HEIGHT = "set_bitmap_max_width_height";
    public static final String INTENT_BITMAP_MAX_WIDTH = "max_width";
    public static final String INTENT_BITMAP_MAX_HEIGHT = "max_height";
 
 
    public static final int REQUEST_IMAGE_CAPTURE = 0;
    public static final int 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;
    public static String fileName;
 
    public interface PickerOptionListener {
        void onTakeCameraSelected();
 
        void onChooseGallerySelected();
    }
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_image_picker);
 
        Intent intent = getIntent();
        if (intent == null) {
            Toast.makeText(getApplicationContext(), getString(R.string.toast_image_intent_null), Toast.LENGTH_LONG).show();
            return;
        }
 
        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, false);
        setBitmapMaxWidthHeight = intent.getBooleanExtra(INTENT_SET_BITMAP_MAX_WIDTH_HEIGHT, false);
        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();
        } else {
            chooseImageFromGallery();
        }
    }
 
    public static void showImagePickerOptions(Context context, PickerOptionListener listener) {
        // setup the alert builder
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle(context.getString(R.string.lbl_set_profile_photo));
 
        // add a list
        String[] animals = {context.getString(R.string.lbl_take_camera_picture), context.getString(R.string.lbl_choose_from_gallery)};
        builder.setItems(animals, (dialog, which) -> {
            switch (which) {
                case 0:
                    listener.onTakeCameraSelected();
                    break;
                case 1:
                    listener.onChooseGallerySelected();
                    break;
            }
        });
 
        // create and show the alert dialog
        AlertDialog dialog = builder.create();
        dialog.show();
    }
 
    private void takeCameraImage() {
        Dexter.withActivity(this)
                .withPermissions(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                .withListener(new MultiplePermissionsListener() {
                    @Override
                    public void onPermissionsChecked(MultiplePermissionsReport report) {
                        if (report.areAllPermissionsGranted()) {
                            fileName = System.currentTimeMillis() + ".jpg";
                            Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, getCacheImagePath(fileName));
                            if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
                                startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
                            }
                        }
                    }
 
                    @Override
                    public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
                        token.continuePermissionRequest();
                    }
                }).check();
    }
 
    private void chooseImageFromGallery() {
        Dexter.withActivity(this)
                .withPermissions(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                .withListener(new MultiplePermissionsListener() {
                    @Override
                    public void onPermissionsChecked(MultiplePermissionsReport report) {
                        if (report.areAllPermissionsGranted()) {
                            Intent pickPhoto = new Intent(Intent.ACTION_PICK,
                                    android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                            startActivityForResult(pickPhoto, REQUEST_GALLERY_IMAGE);
                        }
                    }
 
                    @Override
                    public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
                        token.continuePermissionRequest();
                    }
                }).check();
 
    }
 
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case REQUEST_IMAGE_CAPTURE:
                if (resultCode == RESULT_OK) {
                    cropImage(getCacheImagePath(fileName));
                } else {
                    setResultCancelled();
                }
                break;
            case REQUEST_GALLERY_IMAGE:
                if (resultCode == RESULT_OK) {
                    Uri imageUri = data.getData();
                    cropImage(imageUri);
                } else {
                    setResultCancelled();
                }
                break;
            case UCrop.REQUEST_CROP:
                if (resultCode == RESULT_OK) {
                    handleUCropResult(data);
                } else {
                    setResultCancelled();
                }
                break;
            case UCrop.RESULT_ERROR:
                final Throwable cropError = UCrop.getError(data);
                Log.e(TAG, "Crop error: " + cropError);
                setResultCancelled();
                break;
            default:
                setResultCancelled();
        }
    }
 
    private void cropImage(Uri sourceUri) {
        Uri destinationUri = Uri.fromFile(new File(getCacheDir(), queryName(getContentResolver(), sourceUri)));
        UCrop.Options options = new UCrop.Options();
        options.setCompressionQuality(IMAGE_COMPRESSION);
        options.setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary));
        options.setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimary));
        options.setActiveWidgetColor(ContextCompat.getColor(this, R.color.colorPrimary));
 
        if (lockAspectRatio)
            options.withAspectRatio(ASPECT_RATIO_X, ASPECT_RATIO_Y);
 
        if (setBitmapMaxWidthHeight)
            options.withMaxResultSize(bitmapMaxWidth, bitmapMaxHeight);
 
        UCrop.of(sourceUri, destinationUri)
                .withOptions(options)
                .start(this);
    }
 
    private void handleUCropResult(Intent data) {
        if (data == null) {
            setResultCancelled();
            return;
        }
        final Uri resultUri = UCrop.getOutput(data);
        setResultOk(resultUri);
    }
 
    private void setResultOk(Uri imagePath) {
        Intent intent = new Intent();
        intent.putExtra("path", imagePath);
        setResult(Activity.RESULT_OK, intent);
        finish();
    }
 
    private void setResultCancelled() {
        Intent intent = new Intent();
        setResult(Activity.RESULT_CANCELED, intent);
        finish();
    }
 
    private Uri getCacheImagePath(String fileName) {
        File path = new File(getExternalCacheDir(), "camera");
        if (!path.exists()) path.mkdirs();
        File image = new File(path, fileName);
        return getUriForFile(ImagePickerActivity.this, getPackageName() + ".provider", image);
    }
 
    private static String queryName(ContentResolver resolver, Uri uri) {
        Cursor returnCursor =
                resolver.query(uri, null, null, null, null);
        assert returnCursor != null;
        int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
        returnCursor.moveToFirst();
        String name = returnCursor.getString(nameIndex);
        returnCursor.close();
        return name;
    }
 
    /**
     * Calling this will delete the images from cache directory
     * useful to clear some memory
     */
    public static void clearCache(Context context) {
        File path = new File(context.getExternalCacheDir(), "camera");
        if (path.exists() &amp;&amp; path.isDirectory()) {
            for (File child : path.listFiles()) {
                child.delete();
            }
        }
    }
}

Menjalankan aktivitas copping

Untuk menampilkan pilihan pengambilan gambar, panggil metode ImagePickerActivity.showImagePickerOptions ()

ImagePickerActivity.showImagePickerOptions(this, new ImagePickerActivity.PickerOptionListener() {
            @Override
            public void onTakeCameraSelected() {
                // launchCameraIntent();
            }
 
            @Override
            public void onChooseGallerySelected() {
                // launchGalleryIntent();
            }
        });

Setelah opsi dipilih, kalian dapat mengirimkan data Intent sesuai pada pilihan. Misalnya, untuk memilih gambar dari galeri dengan rasio aspek 1 × 1, intent di bawah ini dapat digunakan.

Intent intent = new Intent(MainActivity.this, ImagePickerActivity.class);
intent.putExtra(ImagePickerActivity.INTENT_IMAGE_PICKER_OPTION, ImagePickerActivity.REQUEST_IMAGE_CAPTURE);
 
// setting aspect ratio
intent.putExtra(ImagePickerActivity.INTENT_LOCK_ASPECT_RATIO, true);
intent.putExtra(ImagePickerActivity.INTENT_ASPECT_RATIO_X, 1); // 16x9, 1x1, 3:4, 3:2
intent.putExtra(ImagePickerActivity.INTENT_ASPECT_RATIO_Y, 1);
 
startActivityForResult(intent, REQUEST_IMAGE);

  1. Sekarang kita akan melihat bagaimana ini dapat diterapkan pada activity profil kita. Buka MainActivity.java dan panggil aktivitas pemilih gambar untuk mengetuk gambar profil atau ikon plus.

MainActivity.java

package info.androidhive.imagepicker;
 
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import 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;
 
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
 
public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();
    public static final int REQUEST_IMAGE = 100;
 
    @BindView(R.id.img_profile)
    ImageView imgProfile;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setTitle(null);
 
        loadProfileDefault();
 
        // Clearing older images from cache directory
        // don't call this line if you want to choose multiple images in the same activity
        // call this once the bitmap(s) usage is over
        ImagePickerActivity.clearCache(this);
    }
 
    private void loadProfile(String url) {
        Log.d(TAG, "Image cache path: " + 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(this, R.color.profile_default_tint));
    }
 
    @OnClick({R.id.img_plus, R.id.img_profile})
    void onProfileImageClick() {
        Dexter.withActivity(this)
                .withPermissions(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                .withListener(new MultiplePermissionsListener() {
                    @Override
                    public void onPermissionsChecked(MultiplePermissionsReport report) {
                        if (report.areAllPermissionsGranted()) {
                            showImagePickerOptions();
                        }
 
                        if (report.isAnyPermissionPermanentlyDenied()) {
                            showSettingsDialog();
                        }
                    }
 
                    @Override
                    public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
                        token.continuePermissionRequest();
                    }
                }).check();
    }
 
    private void showImagePickerOptions() {
        ImagePickerActivity.showImagePickerOptions(this, new ImagePickerActivity.PickerOptionListener() {
            @Override
            public void onTakeCameraSelected() {
                launchCameraIntent();
            }
 
            @Override
            public void onChooseGallerySelected() {
                launchGalleryIntent();
            }
        });
    }
 
    private void launchCameraIntent() {
        Intent intent = new Intent(MainActivity.this, ImagePickerActivity.class);
        intent.putExtra(ImagePickerActivity.INTENT_IMAGE_PICKER_OPTION, ImagePickerActivity.REQUEST_IMAGE_CAPTURE);
 
        // setting aspect ratio
        intent.putExtra(ImagePickerActivity.INTENT_LOCK_ASPECT_RATIO, true);
        intent.putExtra(ImagePickerActivity.INTENT_ASPECT_RATIO_X, 1); // 16x9, 1x1, 3:4, 3:2
        intent.putExtra(ImagePickerActivity.INTENT_ASPECT_RATIO_Y, 1);
 
        // setting maximum bitmap width and height
        intent.putExtra(ImagePickerActivity.INTENT_SET_BITMAP_MAX_WIDTH_HEIGHT, true);
        intent.putExtra(ImagePickerActivity.INTENT_BITMAP_MAX_WIDTH, 1000);
        intent.putExtra(ImagePickerActivity.INTENT_BITMAP_MAX_HEIGHT, 1000);
 
        startActivityForResult(intent, REQUEST_IMAGE);
    }
 
    private void launchGalleryIntent() {
        Intent intent = new Intent(MainActivity.this, ImagePickerActivity.class);
        intent.putExtra(ImagePickerActivity.INTENT_IMAGE_PICKER_OPTION, ImagePickerActivity.REQUEST_GALLERY_IMAGE);
 
        // setting aspect ratio
        intent.putExtra(ImagePickerActivity.INTENT_LOCK_ASPECT_RATIO, true);
        intent.putExtra(ImagePickerActivity.INTENT_ASPECT_RATIO_X, 1); // 16x9, 1x1, 3:4, 3:2
        intent.putExtra(ImagePickerActivity.INTENT_ASPECT_RATIO_Y, 1);
        startActivityForResult(intent, REQUEST_IMAGE);
    }
 
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (requestCode == REQUEST_IMAGE) {
            if (resultCode == Activity.RESULT_OK) {
                Uri uri = data.getParcelableExtra("path");
                try {
                    // You can update this bitmap to your server
                    Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
 
                    // loading profile image from local cache
                    loadProfile(uri.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
 
    /**
     * Showing Alert Dialog with Settings option
     * Navigates user to app settings
     * NOTE: Keep proper title and message depending on your app
     */
    private void showSettingsDialog() {
        AlertDialog.Builder builder = new 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), (dialog, which) -> {
            dialog.cancel();
            openSettings();
        });
        builder.setNegativeButton(getString(android.R.string.cancel), (dialog, which) -> dialog.cancel());
        builder.show();
 
    }
 
    // navigating user to app settings
    private void openSettings() {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", getPackageName(), null);
        intent.setData(uri);
        startActivityForResult(intent, 101);
    }
}

Sekarang jalankan dan uji aplikasi. Kalian harusnya sudah bisa mengatur gambar profil dari kamera atau galeri.

Tampilan aplikasi sosmed sederhana yang sudah selesai
Tampilan aplikasi sosmed sederhana yang sudah selesai

Jika kalian memiliki pertanyaan atau problem, silakan posting di bagian komentar di bawah ya.

Oiya, source code lengkap bisa kalian download di link berikut.

Download Image Picker Sosmed Sederhana

Happy coding 🙂

Sumber: www.androidhive.info

Muhammad Faizin
Follow Faizin:

Writer and Developer

Dulu suka menulis kode dan sejenisnya sampe malem, sekarang juga masih. Kesukaan pada menulis cerita sedikit demi sedikit terpupuk, apalagi sebagai mantan anak sekolahan dengan cita-cita kuliah di luar negeri.