This article is based on the ideas required by the project to learn from the improved ideas of other bloggers. The ideas will be the same, but this article does belong to my original creation, and the reference link will be displayed at the end of the article (ah, good official...)
Let's talk about the functional requirements of the project, which is similar to the interface of QQ and wechat when reporting / complaining users. Users need to upload chat screenshots of relevant violations. Of course, users have saved screenshots in mobile phone photo albums before realizing this function, so the function of multi image upload is relatively simple, At that time, I also found a lot of information from the Internet when doing this function. At the beginning, my idea was to adjust the system album with code, and then select pictures from the system album, but after running, I found that only one picture can be selected, not more than one, This is not in line with the development logic (the main reason is that I don't know there is a picture selector framework due to my lack of experience). I found that there are many kinds of frames related to picture selectors, including native ones and ones directly typed by Daniel with code hands, (but I prefer the original ones, because Daniel's ideas are not understood by everyone...) so I won't talk about Daniel's more. Let me give some examples of the original ones, which are easy to understand by junior coders. Oh, no, let's introduce them to you directly!
Layout code: only show the part of the code that displays the picture
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <GridView android:id="@+id/add_pic" android:layout_width="200dp" android:layout_height="fill_parent" android:layout_marginStart="30dp" android:background="@drawable/input_bg" android:minHeight="56dp" android:scrollbars="none" android:layout_margin="10dp" android:visibility="gone" android:gravity="fill_horizontal" android:stretchMode="columnWidth" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toLeftOf="@id/btn_add_pic" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> //Click this button to jump to the system picture selector <Button android:id="@+id/btn_add_pic" android:layout_width="56dp" android:layout_height="56dp" android:layout_margin="10dp" android:background="@drawable/add_picture_bg" android:foreground="@mipmap/add" android:foregroundGravity="center" app:backgroundTint="#EFEFEF" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toEndOf="@+id/add_pic" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
The layout made according to the project requirements is in this style:
Next is the function implementation of java code:
public class btnAddPicOnClickListener implements View.OnClickListener { @Override public void onClick(View v) { //Turn on the multi graph selector Intent intent=new Intent(MainActivity.this, ImagesSelectorActivity.class); //Sets the maximum number of selected pictures intent.putExtra(SelectorSettings.SELECTOR_MAX_IMAGE_NUMBER,3); //Setting the minimum size of the displayed image; Filter small images (mainly icons) intent.putExtra(SelectorSettings.SELECTOR_MIN_IMAGE_SIZE,100000); //Show camera intent.putExtra(SelectorSettings.SELECTOR_SHOW_CAMERA,false); //Takes the currently selected image set as the initial value intent.putStringArrayListExtra(SelectorSettings.SELECTOR_INITIAL_SELECTED_LIST,imagePaths); //Jump to multi graph selector startActivityForResult(intent,REQUEST_CODE); } } //Get the image path response startActivityForResult and display the image in the grid layout @SuppressLint("LongLogTag") @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); //requestCode: status identification code if (requestCode==REQUEST_CODE){ //resultCode: result identification code if (resultCode==RESULT_OK){ //Get selection results from selector ArrayList<String> list=data.getStringArrayListExtra(SelectorSettings.SELECTOR_RESULTS); //Displays the selected picture loadAdapter(list); Log.i("jjjj", "list: "+ list.toString()); //The grid layout is hidden at the beginning, mainly to make the displayed layout look good, and then display it after selecting the picture gvPic.setVisibility(View.VISIBLE); //Sets the maximum number of columns for the grid layout gvPic.setNumColumns(list.size()); } } }
Of course, the custom adapter is used for grid layout. The BaseAdapter code is as follows:
private void loadAdapter(ArrayList<String> paths){ //First, empty the collection of picture paths if (imagePaths!=null&& imagePaths.size()>0){ imagePaths.clear(); } //Also clear the useless data in paths if (paths.contains("000000")){ paths.remove("000000"); } // paths.add("000000"); imagePaths.addAll(paths); adapter=new GridAdapter(imagePaths,MainActivity.this); // adapter.notifyDataSetChanged(); gvPic.setAdapter(adapter); } private class GridAdapter extends BaseAdapter{ //Create entry parameters, data list, layout filler, context content private ArrayList<String> listUrls; private LayoutInflater inflater; private Context context; public GridAdapter(ArrayList<String> listUrls,Context context){ this.listUrls=listUrls; this.context=context; inflater=LayoutInflater.from(MainActivity.this); } //How many items can I get list data @Override public int getCount() { return listUrls.size(); } //Get a piece of data in the list @Override public Object getItem(int position) { return listUrls.get(position); } //Gets the location of a piece of data in the list @Override public long getItemId(int position) { return position; } //Draw list @Override public View getView(int position, View convertView, ViewGroup parent) { //Materialized view holder class ViewHolder holder=null; //Empty content view if (convertView==null){ holder=new ViewHolder(); //Fill content view (R.layout.add_pic_item is a sub layout of grid layout) convertView=inflater.inflate(R.layout.add_pic_item,parent,false); //Assign the control id in the content view to the control in the view holder holder.image=(ImageView) convertView.findViewById(R.id.img_pic); holder.image.setBackground(getResources().getDrawable(R.drawable.add_picture_bg)); convertView.setTag(holder); }else { holder= (ViewHolder) convertView.getTag(); } //Arrange the picture in the view final String path=listUrls.get(position); if (path.equals("000000")){ // holder.image.setImageResource(R.mipmap.ic_launcher); // listUrls.clear(); listUrls.remove("000000"); }else{ //Load pictures through Glide picture caching mechanism framework Glide.with(MainActivity.this) .load(path) .placeholder(R.mipmap.ic_launcher_round) .error(R.mipmap.ic_launcher_round) .centerCrop() .crossFade() .into(holder.image); //If the number of pictures reaches 3, hide the Add button to control user behavior if(listUrls.size()==3){ // Toast.makeText(context), "only 3 pieces can be selected!", Toast.LENGTH_SHORT).show(); btnAddPic.setVisibility(View.GONE); } } return convertView; } //Create view holder class class ViewHolder{ ImageView image; } }
Points to note when writing java code:
1. When writing java code, add the dependency of "multiple images selector" multi graph selector in the project:
2. When opening the picture selector, you need to open the permission to read the system album and network access.
3. Add a picture selector.
//In build Add to the gradle file, and then synchronize the project implementation 'com.zfdang.multiple-images-selector:multiple-images-selector:1.1.5' //Because it is the image displayed by the glide image loader, you also need to add glide dependencies implementation 'com.github.bumptech.glide:glide:3.7.0'
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> //The following two permissions are the permissions you want to take pictures in the picture selector <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application ... android:name=".DemoApplication" ... <activity android:name="com.zfdang.multiple_images_selector.ImagesSelectorActivity" android:configChanges="orientation|screenSize"/> </application>
Of course, Android 6 After version 0, you also need to manually add the permission to read the album when the program runs. The code is as follows:
//Higher version manual access public void myPermission() { int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE); if (permission != PackageManager.PERMISSION_GRANTED) { // We don't have permission so prompt the user ActivityCompat.requestPermissions( this, PERMISSIONS_STORAGE, IMAGE_OPEN ); } } //Request callback @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case IMAGE_OPEN: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) { isGreen = false; } else { isGreen = true; } break; } }
- Application initialization
public class DemoApplication extends Application { @Override public void onCreate() { super.onCreate(); // the following line is important Fresco.initialize(getApplicationContext()); } }
The above is a native framework of the multi graph selector I used in the company's project. It is relatively simple and easy to understand, and suitable for junior developers. Let's see the source code document of the framework github: Click here to enter the portal
Of course, this is not the only framework in android. Let's continue:
Detailed explanation of the use of Matisse picture selector
1, Introduction
- Easy to use
- Support day and night mode, and you can customize the theme
- Customize the maximum number of selected pictures
- Display of JPEG, PNG, GIF picture types
- Supports the orderly selection of pictures, that is, when selecting pictures, there will be 1, 2, 3, 4... Style checkboxes;
- Support user-defined filtering and completely customize filtering rules
- You can define the zoom scale of the picture thumbnail.
- Support horizontal and vertical screens. Matisse did the state saving
- Different picture loading libraries are supported. Currently, glass and Picasso are supported
2, Use steps
1. Add dependency
build. Code in gradle file:
repositories { jcenter() } dependencies { compile 'com.zhihu.android:matisse:0.5.0-alpha4' compile 'com.github.bumptech.glide:glide:3.7.0' }
2. Add related permissions
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> //android6. The requirements for permission application of version 0 are the same as those of multiple images selector
3. Start selector
If you don't need to click to take photos and have no requirements for filtering, you can use it directly
intent jump to MatisseActivity from your current Activity or Fragment
Basic usage
1. Define constants
private static final int REQUEST_CODE_CHOOSE = 23;//Define request code constants
2. Start MatisseActivity
Matisse .from(MainActivity.this) .choose(MimeType.allOf())//Show all photos and videos .countable(true)//Select pictures in order .maxSelectable(9)//The maximum number of choices is 9 .gridExpectedSize(120)//The picture shows the size of the table getResources() .getDimensionPixelSize(R.dimen.grid_expected_size) .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)//Select the desired orientation for the image and preview activity. .thumbnailScale(0.85f)//Scale .theme(R.style.Matisse_Zhihu)//Theme dark theme r.style Matisse_ Dracula .imageEngine(new GlideEngine())//Loading mode .forResult(REQUEST_CODE_CHOOSE);//Request code
3. Accept the result of the selection
List<Uri> mSelected; @Override //Receive returned address protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_CHOOSE && resultCode == RESULT_OK) { mSelected = Matisse.obtainResult(data); Log.d("Matisse", "mSelected: " + mSelected); } }
Of course, if you want to try to implement photography and filter, you can refer to this Daniel's blog , (click to have a surprise)
Well, finally, let's take a look at the operation effect:
Picture selector operation effect
Well, the above is the content of this article. It's all the native framework of android. You can use it. Just understand the logic. Of course, my introduction is also very simple and easy to understand, because it's just to select pictures and display them. The logic is easy to understand. Of course, if you want to further explore the processing and cutting of pictures, you can refer to: Click to enter the new world
After such a long time to write a blog again, I'm a little hand-made. I should get familiar with it as soon as possible!!!