Author: Summer solstice, welcome to reprint, but please keep this statement, thank you. Blog.csdn.net/u011418943/…

First, a good rule to see your own implementation:

Of course, github’s various open source libraries only cover Android’s own features.

In fact, this is not difficult, the key points are nothing more than two:

  • Get the uri of the camera after 7.0
  • Uri retrieval at clipping time

Here you can see the layout of the popupWindow at the bottom, and you can also see my PopupWindow wrapper: reject useless work and encapsulate a universal PopupWindow


       
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/pop_root_ly"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp"
    android:orientation="vertical">
    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardCornerRadius="5dp">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <TextView
                android:id="@+id/pop_pic"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:gravity="center"
                android:text="@string/pic"
                android:textColor="@color/black"
                android:textSize="18sp" />
            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="? android:attr/listDivider"
                android:padding="2dp" />
            <TextView
                android:id="@+id/pop_camera"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:gravity="center"
                android:text="@string/camera"
                android:textColor="@color/black"
                android:textSize="18sp" />
        </LinearLayout>
    </android.support.v7.widget.CardView>
    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/pop_cancel"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:gravity="center"
            android:text="Cancel"
            android:textColor="@color/black"
            android:textSize="18sp" />
    </android.support.v7.widget.CardView>
</LinearLayout>Copy the code

For avatars, I use an open source framework, CircleiamgeView, which is used to handle circular avatars. I won’t post it here, but the link is as follows:

compile 'DE. Hdodenhof: circleimageview: 2.1.0'Copy the code

Click on the following events:

/*Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image*// / / * * * "); startActivityForResult(intent,ToolUtils.SCAN_OPEN_PHONE); * /
   // Due to the refresh problem of the simulator gallery, the following opening mode is adopted. In actual development, please use the above one
    Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(intent, ToolUtils.SCAN_OPEN_PHONE);Copy the code

Camera:

 /**
     * 打开相册
     */
    private void cameraPic() {
        // Create a file to store the photos taken after the photo is taken
        File outputfile = new File(mActivity.getExternalCacheDir(),"output.png");
        try {
            if (outputfile.exists()){
                outputfile.delete();/ / delete
            }
            outputfile.createNewFile();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Uri imageuri ;
        if (Build.VERSION.SDK_INT >= 24){
            imageuri = FileProvider.getUriForFile(mActivity,
                    "com.rachel.studyapp.fileprovider".// Can be any string
                    outputfile);
        }else{
            imageuri = Uri.fromFile(outputfile);
        }
        // Start the camera program
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
        intent.putExtra(MediaStore.EXTRA_OUTPUT,imageuri);
        startActivityForResult(intent,ToolUtils.PHONE_CAMERA);
    }
Copy the code

FileProvider is used to encapsulate urIs, which are used to save the uris of photos taken after they are taken. Can be simply understood as the index of the picture.

Attention!! If it is a 6.0 mobile phone, please add permission application. I have sealed it here, so I will not post it to disturb you.

Add the provider attribute to your Androidmanifest.xml file as follows:

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.rachel.studyapp.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <! -- Provide shared path -->
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
        </provider>Copy the code

After logging in to getUriForFile, the authorities exported must be set to false. After logging in to getUriForFile, the authorities exported must be set to false. Add a mete-data tag below to provide the fileProvider’s shared path. Create a new XML folder with the following code in the file_paths file:


       
<resources>
    <paths>
        <external-path path="" name="camera_photos" />
    </paths>
</resources>Copy the code

The explanation is as follows:

  • External-path specifies the share path
  • Name is arbitrary, just a label, buy a pass, as explained below
  • If path is not set, the SD card will be shared. For example, if path is set to “Pictrues”, only the Pictures folder under the SD card will be shared

Now that everything is configured, let’s print the mCameraUri above, as follows:

cameraPic: content://com.rachel.studyapp.fileprovider/camera_photos/Android/data/com.rachel.studyapp/cache/output.pngCopy the code

So if you look at this camera_photos thing, it’s just a virtual directory, you can ignore it. This is what uri encapsulation looks like after 7.0.

OnActivityReslut is also very simple. Since we have obtained the correct URI from both the album and the album, after obtaining this URI, we can start the clipped activity, as shown below:

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK){
            switch (requestCode){
                case ToolUtils.SCAN_OPEN_PHONE: // The uri returned after the photo from the album
                    // Start clipping
                    startActivityForResult(CutForPhoto(data.getData()),ToolUtils.PHONE_CROP);
                    break;
                case ToolUtils.PHONE_CAMERA: // The uri returned by the camera
                    // Start clipping
                    String path = mActivity.getExternalCacheDir().getPath();
                    String name = "output.png";
                    startActivityForResult(CutForCamera(path,name),ToolUtils.PHONE_CROP);
                    break;
                case ToolUtils.PHONE_CROP:
                    try {
                        // Get the cropped image and display it
                        Bitmap bitmap = BitmapFactory.decodeStream(
                                mActivity.getContentResolver().openInputStream(mCutUri));
                        mUserLogoIcon.setImageBitmap(bitmap);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                    break; }}}Copy the code

As you can see, the cropping is divided into two parts, one is taken from the album, and the other is taken after the cropping. The difference, look down: Photo album clipping:

/** ** @param uri
     * @return* /
    @NonNull
    private Intent CutForPhoto(Uri uri) {
        try {
            // Direct clipping
            Intent intent = new Intent("com.android.camera.action.CROP");
            // Set the clipped image path file
            File cutfile = new File(Environment.getExternalStorageDirectory().getPath(),
                    "cutcamera.png"); // Call it anything
            if (cutfile.exists()){ // If it already exists, delete it first
                cutfile.delete();
            }
            cutfile.createNewFile();
            // Initialize the URI
            Uri imageUri = uri; // The returned URI
            Uri outputUri = null; // The real URI
            Log.d(TAG, "CutForPhoto: "+cutfile);
            outputUri = Uri.fromFile(cutfile);
            mCutUri = outputUri;
            Log.d(TAG, "mCameraUri: "+mCutUri);
            // Crop true is set to crop the view displayed in the intent that is started
            intent.putExtra("crop".true);
            // aspectX,aspectY is the ratio of width to height
            intent.putExtra("aspectX".1);
            intent.putExtra("aspectY".1);
            // Set the width and height to crop
            intent.putExtra("outputX", ToolUtils.dip2px(mActivity,200)); //200dp
            intent.putExtra("outputY",ToolUtils.dip2px(mActivity,200));
            intent.putExtra("scale".true);
            // If the image is too large, it will result in oom, set to false
            intent.putExtra("return-data".false);
            if(imageUri ! =null) {
                intent.setDataAndType(imageUri, "image/*");
            }
            if(outputUri ! =null) {
                intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
            }
            intent.putExtra("noFaceDetection".true);
            // Compress the image
            intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
            return intent;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }Copy the code

Camera cropping:

 /** * After the photo is taken, start cropping * @paramCamerapath path * @paramImgname Name of img * @return* /
    @NonNull
    private Intent CutForCamera(String camerapath,String imgname) {
        try {

            // Set the clipped image path file
            File cutfile = new File(Environment.getExternalStorageDirectory().getPath(),
                    "cutcamera.png"); // Call it anything
            if (cutfile.exists()){ // If it already exists, delete it first
                cutfile.delete();
            }
            cutfile.createNewFile();
            // Initialize the URI
            Uri imageUri = null; // The returned URI
            Uri outputUri = null; // The real URI
            Intent intent = new Intent("com.android.camera.action.CROP");
            // Take a photo
            File camerafile = new File(camerapath,imgname);
            if (Build.VERSION.SDK_INT >= 24) {
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                imageUri = FileProvider.getUriForFile(mActivity,
                        "com.rachel.studyapp.fileprovider",
                        camerafile);
            } else {
                imageUri = Uri.fromFile(camerafile);
            }
            outputUri = Uri.fromFile(cutfile);
            // Provide the URI and parse it into a bitmap
            mCutUri = outputUri;
            // Crop true is set to crop the view displayed in the intent that is started
            intent.putExtra("crop".true);
            // aspectX,aspectY is the ratio of width to height
            intent.putExtra("aspectX".1);
            intent.putExtra("aspectY".1);
            // Set the width and height to crop
            intent.putExtra("outputX", ToolUtils.dip2px(mActivity,200));
            intent.putExtra("outputY",ToolUtils.dip2px(mActivity,200));
            intent.putExtra("scale".true);
            // If the image is too large, it will result in oom, set to false
            intent.putExtra("return-data".false);
            if(imageUri ! =null) {
                intent.setDataAndType(imageUri, "image/*");
            }
            if(outputUri ! =null) {
                intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
            }
            intent.putExtra("noFaceDetection".true);
            // Compress the image
            intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
            return intent;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }Copy the code

The above two, very similar, the difference is that the album is directly obtained from the URI, while the camera is obtained from the URI after taking the photo, you can combine here, but the parameters are different, here I want to let you have a comparison effect, I separate out.

Intent.putextra (” return-data “,false); If this is set to true, it will return a BTImap, but this will return OOM if memory is insufficient. Therefore, it is correct to generate a cropped image locally, obtain the cropped URI, and parse it out. So set it to false and use McUturi as the URI for the local store.

So that’s it. Github, SmartCropper, SmartCropper, SmartCropper, SmartCropper

https://github.com/pqpo/SmartCropperCopy the code

TakePhoto:

https://github.com/crazycodeboy/TakePhoto/Copy the code