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