PhotoPickerNewDemo【PhotoPicker0.9.12的个性化修改以及使用(内部glide版本号是4.1.1)】

版权声明:本文为HaiyuKing原创文章,转载请注明出处!

前言

本Demo使用的是PhotoPicker 0.9.12版本,里面集成的glide版本号是4.1.1。这里就不进行特殊的个性化处理了(比如新增NewImagePagerDialogFragment.java用于对话框样式预览图片、新增NewPhotoPickerFragment.java用于单独作为自定义DialogFragment的其中一个Fragment和其他Fragment共存),而是记录下使用步骤(当然了,github上讲解的很清楚了,大家可以直接参考《donglua/PhotoPicker》)。

不过,本文对PhotoPicker进行了简单的修改,对UI进行了部分修改。【所以本Demo最后使用的是方式2——通过引入PhotoPicker这个module的方式】

效果图

  

代码分析

引入PhotoPicker有两种方式【二选一】

1、通过Gradle方式,在APP的build.gradle中引用【见导入步骤

2、下载整个压缩包,然后导入PhotoPicker的module,然后修改图片资源

2.1、下载压缩包

2.2、导入PhotoPicker的Module

提示下面的错误:

2.3、解决Plugin with id 'com.novoda.bintray-release' not found.问题

在项目的build.gradle文件中添加以下代码

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        //解决PhotoPicker的Plugin with id 'com.novoda.bintray-release' not found.
        classpath 'com.novoda:bintray-release:0.5.0'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

 2.4、修改图片资源(比如__picker_ic_photo_black_48dp.png、__picker_checkbox_marked.png、__picker_checkbox_n.png)

注意:需要修改所有drawable-xxxx目录下的图片

原始的图片资源:

修改后的图片资源:

2.5、添加图片资源【__picker_transparent_bg.png、down_arrow.png、up_arrow.png】

添加到drawable-xxhdpi目录下

2.6、修改drawable目录下的__picker_photo_bg.xml和__picker_checkbox_bg.xml【主要用于替换图片列表项的底部背景图】

原代码1:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

  <item android:state_selected="true">
    <shape>
      <stroke android:color="@color/__picker_item_photo_border_selected"
          android:width="1dip"/>
    </shape>
  </item>

  <item>
    <shape>
      <stroke android:color="@color/__picker_item_photo_border_n"
          android:width="1dip"/>
    </shape>
  </item>


</selector>
__picker_photo_bg.xml

修改后的代码:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_selected="true">
    <shape android:shape="rectangle">
      <stroke android:width="2dip"
              android:color="@color/__picker_item_photo_border_selected"/>
      <solid android:color="@color/__picker_selected_bg"/>
      <solid></solid>
    </shape>
  </item>

  <item android:drawable="@drawable/__picker_transparent_bg">
    <shape android:shape="rectangle">
      <stroke android:width="2dip"
              android:color="@color/__picker_item_photo_border_n"/>
      <!--<solid android:color="#00000000"/>-->
    </shape>
  </item>
</selector>

原代码2:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

  <item android:state_selected="true">
    <layer-list>
      <item>
        <shape>
          <corners android:radius="2dip"/>
          <padding android:top="-2dip"
              android:left="-2dip"
              android:bottom="-2dip"
              android:right="-2dip"/>
          <stroke android:width="1dip"
              android:color="@android:color/white"/>
        </shape>
      </item>
      <item android:drawable="@drawable/__picker_checkbox_marked"/>
    </layer-list>
  </item>

  <item>
    <layer-list>
      <item>
        <shape>
          <corners android:radius="2dip"/>
          <padding android:top="-2dip"
              android:left="-2dip"
              android:bottom="-2dip"
              android:right="-2dip"/>
          <stroke android:width="1dip"
              android:color="@android:color/white"/>
        </shape>
      </item>
      <item android:drawable="@drawable/__picker_checkbox_n"/>
    </layer-list>
  </item>

</selector>
__picker_checkbox_bg.xml

修改后的

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

  <item android:state_selected="true">
    <layer-list>
      <!--<item>
        <shape>
          <corners android:radius="10dip"/>
          <padding android:top="-2dip"
              android:left="-2dip"
              android:bottom="-2dip"
              android:right="-2dip"/>
          <stroke android:width="1dip"
              android:color="@android:color/white"/>
          <solid android:color="@android:color/white"></solid>
        </shape>
      </item>-->
      <item android:drawable="@drawable/__picker_checkbox_marked"/>
    </layer-list>
  </item>

  <item>
    <layer-list>
      <!--<item>
        <shape>
          <corners android:radius="10dip"/>
          <padding android:top="-2dip"
              android:left="-2dip"
              android:bottom="-2dip"
              android:right="-2dip"/>
          <stroke android:width="1dip"
              android:color="@android:color/white"/>
          <solid android:color="@android:color/white"></solid>
        </shape>
      </item>-->
      <item android:drawable="@drawable/__picker_checkbox_n"/>
    </layer-list>
  </item>

</selector>

2.7、修改__picker_fragment_photo_picker.xml文件【主要用于添加图片目录的上下箭头图标】

原代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

  <android.support.v7.widget.RecyclerView
      android:id="@+id/rv_photos"
      android:layout_width="match_parent"
      android:gravity="center"
      android:layout_weight="1"
      android:layout_height="0dip"
      />


  <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="?attr/colorPrimary"
      >
        <Button
            android:id="@+id/button"
            android:text="@string/__picker_all_image"
            android:layout_width="wrap_content"
            android:gravity="center"
            android:layout_height="wrap_content"
            style="@style/Widget.AppCompat.ActionButton"
            />

  </LinearLayout>

</LinearLayout>
__picker_fragment_photo_picker.xml

修改后的代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
    >

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_photos"
        android:layout_width="match_parent"
        android:gravity="center"
        android:layout_weight="1"
        android:layout_height="0dip"
        />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#e9e9e9"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        >
        <!--<Button
            android:id="@+id/button"
            android:text="@string/__picker_all_image"
            android:layout_width="wrap_content"
            android:gravity="center"
            android:layout_height="wrap_content"
            style="@style/Widget.AppCompat.ActionButton"
            />-->

        <TextView
            android:id="@+id/button"
            android:layout_width="0.0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            android:text="@string/__picker_all_image"
            android:textColor="@color/__picker_text_120"
            android:textSize="16sp"
            android:drawableRight="@drawable/up_arrow"
            android:drawablePadding="8dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:gravity="center_vertical"
            style="@style/Widget.AppCompat.ActionButton"
            />
        <!-- 现在用不到,只是占位用 -->
        <ImageView
            android:layout_width="0.0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            android:src="@drawable/__picker_camera"
            android:layout_gravity="center_vertical"
            android:paddingLeft="15dp"
            android:paddingRight="15dp"
            android:visibility="invisible"/>

    </LinearLayout>

</LinearLayout>

2.8、修改PhotoPickerFragment.java文件【主要是实现上下箭头的更换功能】

搜索why,查看改动的代码:

package me.iwf.photopicker.fragment;

import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.ListPopupWindow;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.PopupWindow;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import me.iwf.photopicker.PhotoPickerActivity;
import me.iwf.photopicker.R;
import me.iwf.photopicker.adapter.PhotoGridAdapter;
import me.iwf.photopicker.adapter.PopupDirectoryListAdapter;
import me.iwf.photopicker.entity.Photo;
import me.iwf.photopicker.entity.PhotoDirectory;
import me.iwf.photopicker.event.OnPhotoClickListener;
import me.iwf.photopicker.utils.AndroidLifecycleUtils;
import me.iwf.photopicker.utils.ImageCaptureManager;
import me.iwf.photopicker.utils.MediaStoreHelper;
import me.iwf.photopicker.utils.PermissionsConstant;
import me.iwf.photopicker.utils.PermissionsUtils;

import static android.app.Activity.RESULT_OK;
import static me.iwf.photopicker.PhotoPicker.DEFAULT_COLUMN_NUMBER;
import static me.iwf.photopicker.PhotoPicker.EXTRA_PREVIEW_ENABLED;
import static me.iwf.photopicker.PhotoPicker.EXTRA_SHOW_GIF;
import static me.iwf.photopicker.utils.MediaStoreHelper.INDEX_ALL_PHOTOS;

/**
 * Created by donglua on 15/5/31.
 */
public class PhotoPickerFragment extends Fragment {

  private ImageCaptureManager captureManager;
  private PhotoGridAdapter photoGridAdapter;

  private PopupDirectoryListAdapter listAdapter;
  //所有photos的路径
  private List<PhotoDirectory> directories;
  //传入的已选照片
  private ArrayList<String> originalPhotos;

  private int SCROLL_THRESHOLD = 30;
  int column;
  //目录弹出框的一次最多显示的目录数目
  public static int COUNT_MAX = 4;
  private final static String EXTRA_CAMERA = "camera";
  private final static String EXTRA_COLUMN = "column";
  private final static String EXTRA_COUNT = "count";
  private final static String EXTRA_GIF = "gif";
  private final static String EXTRA_ORIGIN = "origin";
  private ListPopupWindow listPopupWindow;
  private RequestManager mGlideRequestManager;

  public static PhotoPickerFragment newInstance(boolean showCamera, boolean showGif,
      boolean previewEnable, int column, int maxCount, ArrayList<String> originalPhotos) {
    Bundle args = new Bundle();
    args.putBoolean(EXTRA_CAMERA, showCamera);
    args.putBoolean(EXTRA_GIF, showGif);
    args.putBoolean(EXTRA_PREVIEW_ENABLED, previewEnable);
    args.putInt(EXTRA_COLUMN, column);
    args.putInt(EXTRA_COUNT, maxCount);
    args.putStringArrayList(EXTRA_ORIGIN, originalPhotos);
    PhotoPickerFragment fragment = new PhotoPickerFragment();
    fragment.setArguments(args);
    return fragment;
  }

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setRetainInstance(true);

    mGlideRequestManager = Glide.with(this);

    directories = new ArrayList<>();
    originalPhotos = getArguments().getStringArrayList(EXTRA_ORIGIN);

    column = getArguments().getInt(EXTRA_COLUMN, DEFAULT_COLUMN_NUMBER);
    boolean showCamera = getArguments().getBoolean(EXTRA_CAMERA, true);
    boolean previewEnable = getArguments().getBoolean(EXTRA_PREVIEW_ENABLED, true);

    photoGridAdapter = new PhotoGridAdapter(getActivity(), mGlideRequestManager, directories, originalPhotos, column);
    photoGridAdapter.setShowCamera(showCamera);
    photoGridAdapter.setPreviewEnable(previewEnable);

    listAdapter  = new PopupDirectoryListAdapter(mGlideRequestManager, directories);

    Bundle mediaStoreArgs = new Bundle();

    boolean showGif = getArguments().getBoolean(EXTRA_GIF);
    mediaStoreArgs.putBoolean(EXTRA_SHOW_GIF, showGif);
    MediaStoreHelper.getPhotoDirs(getActivity(), mediaStoreArgs,
        new MediaStoreHelper.PhotosResultCallback() {
          @Override public void onResultCallback(List<PhotoDirectory> dirs) {
            directories.clear();
            directories.addAll(dirs);
            photoGridAdapter.notifyDataSetChanged();
            listAdapter.notifyDataSetChanged();
            adjustHeight();
          }
        });

    captureManager = new ImageCaptureManager(getActivity());
  }

  @Override
  public void onResume() {
    super.onResume();
    if(getActivity() instanceof PhotoPickerActivity){
      PhotoPickerActivity photoPickerActivity = (PhotoPickerActivity) getActivity();
      photoPickerActivity.updateTitleDoneItem();
    }
  }


  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {

    final View rootView = inflater.inflate(R.layout.__picker_fragment_photo_picker, container, false);

    RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.rv_photos);
    StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(column, OrientationHelper.VERTICAL);
    layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(photoGridAdapter);
    recyclerView.setItemAnimator(new DefaultItemAnimator());

    //final Button btSwitchDirectory = (Button) rootView.findViewById(R.id.button);
    final TextView btSwitchDirectory = (TextView) rootView.findViewById(R.id.button);//why

    listPopupWindow = new ListPopupWindow(getActivity());
    listPopupWindow.setWidth(ListPopupWindow.MATCH_PARENT);
    listPopupWindow.setAnchorView(btSwitchDirectory);
    listPopupWindow.setAdapter(listAdapter);
    listPopupWindow.setModal(true);
    listPopupWindow.setDropDownGravity(Gravity.BOTTOM);

    listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
      @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        listPopupWindow.dismiss();

        PhotoDirectory directory = directories.get(position);

        btSwitchDirectory.setText(directory.getName());

        photoGridAdapter.setCurrentDirectoryIndex(position);
        photoGridAdapter.notifyDataSetChanged();
      }
    });

    //添加popwindow隐藏的监听--why
    listPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
      @Override
      public void onDismiss() {
        //监听popwindow隐藏的时候的操作
        Drawable drawableUp = ContextCompat.getDrawable(getActivity(),R.drawable.up_arrow);
        drawableUp.setBounds(0, 0, drawableUp.getMinimumWidth(), drawableUp.getMinimumHeight());
        btSwitchDirectory.setCompoundDrawables(null,null,drawableUp,null);
      }
    });

    photoGridAdapter.setOnPhotoClickListener(new OnPhotoClickListener() {
      @Override public void onClick(View v, int position, boolean showCamera) {
        final int index = showCamera ? position - 1 : position;

        List<String> photos = photoGridAdapter.getCurrentPhotoPaths();

        ImagePagerFragment imagePagerFragment =
            ImagePagerFragment.newInstance(photos, index);

        ((PhotoPickerActivity) getActivity()).addImagePagerFragment(imagePagerFragment);
      }
    });

    photoGridAdapter.setOnCameraClickListener(new OnClickListener() {
      @Override public void onClick(View view) {
        if (!PermissionsUtils.checkCameraPermission(PhotoPickerFragment.this)) return;
        if (!PermissionsUtils.checkWriteStoragePermission(PhotoPickerFragment.this)) return;
        openCamera();
      }
    });

    btSwitchDirectory.setOnClickListener(new OnClickListener() {
      @Override public void onClick(View v) {

        if (listPopupWindow.isShowing()) {
          listPopupWindow.dismiss();
        } else if (!getActivity().isFinishing()) {
          adjustHeight();
          //why
          Drawable drawableDown = ContextCompat.getDrawable(getActivity(),R.drawable.down_arrow);
          drawableDown.setBounds(0, 0, drawableDown.getMinimumWidth(), drawableDown.getMinimumHeight());
          btSwitchDirectory.setCompoundDrawables(null,null,drawableDown,null);
          listPopupWindow.show();
        }
      }
    });


    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
      @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        // Log.d(">>> Picker >>>", "dy = " + dy);
        if (Math.abs(dy) > SCROLL_THRESHOLD) {
          mGlideRequestManager.pauseRequests();
        } else {
          resumeRequestsIfNotDestroyed();
        }
      }
      @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
          resumeRequestsIfNotDestroyed();
        }
      }
    });

    return rootView;
  }

  private void openCamera() {
    try {
      Intent intent = captureManager.dispatchTakePictureIntent();
      startActivityForResult(intent, ImageCaptureManager.REQUEST_TAKE_PHOTO);
    } catch (IOException e) {
      e.printStackTrace();
    } catch (ActivityNotFoundException e) {
      Log.e("PhotoPickerFragment", "No Activity Found to handle Intent", e);
    }
  }

  @Override public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == ImageCaptureManager.REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {

      if (captureManager == null) {
        FragmentActivity activity = getActivity();
        captureManager = new ImageCaptureManager(activity);
      }

      captureManager.galleryAddPic();
      if (directories.size() > 0) {
        String path = captureManager.getCurrentPhotoPath();
        PhotoDirectory directory = directories.get(INDEX_ALL_PHOTOS);
        directory.getPhotos().add(INDEX_ALL_PHOTOS, new Photo(path.hashCode(), path));
        directory.setCoverPath(path);
        photoGridAdapter.notifyDataSetChanged();
      }
    }
  }

  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (grantResults.length > 0
            && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
      switch (requestCode) {
        case PermissionsConstant.REQUEST_CAMERA:
        case PermissionsConstant.REQUEST_EXTERNAL_WRITE:
          if (PermissionsUtils.checkWriteStoragePermission(this) &&
                  PermissionsUtils.checkCameraPermission(this)) {
            openCamera();
          }
          break;
      }
    }
  }

  public PhotoGridAdapter getPhotoGridAdapter() {
    return photoGridAdapter;
  }


  @Override public void onSaveInstanceState(Bundle outState) {
    captureManager.onSaveInstanceState(outState);
    super.onSaveInstanceState(outState);
  }


  @Override public void onViewStateRestored(Bundle savedInstanceState) {
    captureManager.onRestoreInstanceState(savedInstanceState);
    super.onViewStateRestored(savedInstanceState);
  }

  public ArrayList<String> getSelectedPhotoPaths() {
    return photoGridAdapter.getSelectedPhotoPaths();
  }

  public void adjustHeight() {
    if (listAdapter == null) return;
    int count = listAdapter.getCount();
    count = count < COUNT_MAX ? count : COUNT_MAX;
    if (listPopupWindow != null) {
      listPopupWindow.setHeight(count * getResources().getDimensionPixelOffset(R.dimen.__picker_item_directory_height));
    }
  }

  @Override public void onDestroy() {
    super.onDestroy();

    if (directories == null) {
      return;
    }

    for (PhotoDirectory directory : directories) {
      directory.getPhotoPaths().clear();
      directory.getPhotos().clear();
      directory.setPhotos(null);
    }
    directories.clear();
    directories = null;
  }

  private void resumeRequestsIfNotDestroyed() {
    if (!AndroidLifecycleUtils.canLoadImage(this)) {
      return;
    }

    mGlideRequestManager.resumeRequests();
  }
}
PhotoPickerFragment.java

2.9、修改__picker_item_photo.xml,设置图片列表项的内边距值

<?xml version="1.0" encoding="utf-8"?>
<me.iwf.photopicker.widget.SquareItemLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="3dp"
    >
  <ImageView
      android:padding="1dip"
      android:layout_gravity="center"
      android:id="@+id/iv_photo"
      android:scaleType="centerCrop"
      android:layout_width="match_parent"
      android:background="@drawable/__picker_photo_bg"
      android:layout_height="match_parent"
      android:adjustViewBounds="true"
      />

  <ImageView
      android:layout_alignParentTop="true"
      android:layout_alignParentRight="true"
      android:clickable="true"
      android:paddingTop="10dip"
      android:paddingRight="10dip"
      android:paddingLeft="20dip"
      android:paddingBottom="20dip"
      android:id="@+id/v_selected"
      android:src="@drawable/__picker_checkbox_bg"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      />

</me.iwf.photopicker.widget.SquareItemLayout>

2.10、修改图片列表项选中后的颜色值(colors.xml文件中修改)

<?xml version="1.0" encoding="utf-8"?>
<resources>

  <color name="__picker_pager_bg">#CA000000</color>
  <color name="__picker_selected_bg">#44000000</color>
  <color name="__picker_black_40">#282828</color>
  <color name="__picker_common_primary">#f3f3f3</color>

  <color name="__picker_text_40">#282828</color>
  <color name="__picker_text_80">#505050</color>
  <color name="__picker_text_120">#787878</color>
  <!--<color name="__picker_item_photo_border_selected">#ff99cc00</color>-->
  <!--why-->
  <color name="__picker_item_photo_border_selected">#1A78EC</color>
  <color name="__picker_item_photo_border_n">#33ffffff</color>

</resources>

至此,PhotoPicker基本上修改完了,后续可以根据需求继续修改。下面就是运用到APP中的步骤【导入步骤跟方式1几乎一样,不同的就是app的build.gradle导入的photopicker不一样】。

2.11、在APP的build.gradle文件添加以下代码

apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "com.why.project.photopickernewdemo"
        minSdkVersion 16
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    //PhotoPicker
    //compile 'me.iwf.photopicker:PhotoPicker:0.9.12@aar'
    //方式2:使用自己导入并且修改后的module
    implementation project(':PhotoPicker')
    //compile 'com.android.support:appcompat-v7:27.1.1'//需要注释,因为新建项目都会自动引用这个appcompat-v7
    compile 'com.android.support:recyclerview-v7:27.1.1'
    compile 'com.android.support:design:27.1.1'
    compile 'com.github.bumptech.glide:glide:4.1.1'
}

2.12、在APP的AndroidManifest.xml中添加以下代码

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.why.project.photopickernewdemo">

    <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">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <!-- PhotoPicker -->
        <activity android:name="me.iwf.photopicker.PhotoPickerActivity"
                  android:theme="@style/customTheme"
            />
        <activity android:name="me.iwf.photopicker.PhotoPagerActivity"
                  android:theme="@style/customTheme"/>
    </application>

</manifest>

2.13、在styles.xml文件中添加以下代码

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>


    <!-- PhotoPicker -->
    <style name="customTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- 解开注释的话,右侧的完成文本始终是设置的颜色,无法实现禁用状态下是灰色的功能 -->
        <!--<item name="actionBarTheme">@style/actionBarTheme</item>-->
        <!--背景颜色值-->
        <item name="colorPrimary">#ffffff</item>
        <!--导航栏高度值-->
        <item name="actionBarSize">52dp</item>
        <!-- 状态栏着色 -->
        <item name="colorPrimaryDark">#378dfc</item>
    </style>
    <style name="actionBarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
        <!--标题颜色值-->
        <item name="android:textColorPrimary">#434343</item>
        <!--右侧完成文本的大小值-->
        <item name="android:textSize">16sp</item>
        <!--右侧完成文本的颜色值-->
        <item name="android:actionMenuTextColor">#1A78EC</item>
    </style>

</resources>

 具体使用参考《三、使用方法》

使用步骤

一、项目组织结构图

注意事项:

1、  导入类文件后需要change包名以及重新import R文件路径

2、  Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖

二、导入步骤【方式1的导入步骤】

(1)在app的build.gradle文件中导入PhotoPicker【修改recyclerview、design的版本号和appcompat-v7统一】

注意:appcompat-v7version >= 23.0.0

apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "com.why.project.photopickernewdemo"
        minSdkVersion 16
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    //PhotoPicker
    compile 'me.iwf.photopicker:PhotoPicker:0.9.12@aar'
    //compile 'com.android.support:appcompat-v7:27.1.1'//需要注释,因为新建项目都会自动引用这个appcompat-v7
    compile 'com.android.support:recyclerview-v7:27.1.1'
    compile 'com.android.support:design:27.1.1'
    compile 'com.github.bumptech.glide:glide:4.1.1'
}

(2)在APP的styles.xml文件中自定义样式(颜色、高度值等)

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>


    <!-- PhotoPicker -->
    <style name="customTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- 解开注释的话,右侧的完成文本始终是设置的颜色,无法实现禁用状态下是灰色的功能 -->
        <!--<item name="actionBarTheme">@style/actionBarTheme</item>-->
        <!--背景颜色值-->
        <item name="colorPrimary">#ffffff</item>
        <!--导航栏高度值-->
        <item name="actionBarSize">52dp</item>
        <!-- 状态栏着色 -->
        <item name="colorPrimaryDark">#378dfc</item>
    </style>
    <style name="actionBarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
        <!--标题颜色值-->
        <item name="android:textColorPrimary">#434343</item>
        <!--右侧完成文本的大小值-->
        <item name="android:textSize">16sp</item>
        <!--右侧完成文本的颜色值-->
        <item name="android:actionMenuTextColor">#1A78EC</item>
    </style>

</resources>

(3)在APP的AndroidManifest.xml中添加以下代码【注意:使用上面自定义的样式

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.why.project.photopickernewdemo">

    <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">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <!-- PhotoPicker -->
        <activity android:name="me.iwf.photopicker.PhotoPickerActivity"
                  android:theme="@style/customTheme"
            />
        <activity android:name="me.iwf.photopicker.PhotoPagerActivity"
                  android:theme="@style/customTheme"/>
    </application>

</manifest>

三、使用方法

(1)在项目中实现Recyclerview基本数据展现【比较简单,省略】【或者参考《Android快速开发常用知识点系列目录》下的RecyclerView篇章相关文章】

 注意:PictureAdapter.java中使用的Glide是4.1.1版本,所以写法跟之前的Glide3.7.0版本是不一样的。

package com.why.project.photopickernewdemo.adapter;

import android.content.Context;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
import com.why.project.photopickernewdemo.R;
import com.why.project.photopickernewdemo.bean.PictureBean;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;

/**
 * Created by HaiyuKing
 * Used 照片网格适配器
 */

public class PictureAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{

    private static final String TAG = PictureAdapter.class.getSimpleName();

    /**上下文*/
    private Context myContext;
    /**自定义列表项标题集合*/
    private ArrayList<PictureBean> listitemList;

    final static int TYPE_ADD = 1;
    final static int TYPE_PHOTO = 2;

    public final static int MAX = 15;//总数目,这里根据实际情况设置,设置100基本上表明无限制了

    /*
    * 构造函数
    */
    public PictureAdapter(Context context, ArrayList<PictureBean> itemlist) {
        myContext = context;
        listitemList = itemlist;
    }

    /**
     * 获取总的条目数
     */
    @Override
    public int getItemCount() {
        Log.w(TAG,"{getItemCount}listitemList.size()="+listitemList.size());
        int count = listitemList.size();
        if (count > MAX) {
            count = MAX;
        }
        count = count + 1;
        return count;
    }

    @Override
    public int getItemViewType(int position) {
        Log.w(TAG,"{getItemViewType}position="+position);
        Log.w(TAG,"{getItemViewType}listitemList.size()="+listitemList.size());
        return (position == listitemList.size()) ? TYPE_ADD : TYPE_PHOTO;
    }

    /**
     * 创建ViewHolder
     */
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if(viewType == TYPE_ADD) {
            View viewfoot = LayoutInflater.from(myContext).inflate(R.layout.pic_grid_foot_item, parent, false);
            ItemFootViewHolder itemfootViewHolder = new ItemFootViewHolder(viewfoot);
            return itemfootViewHolder;
        } else if(viewType == TYPE_PHOTO) {
            View view = LayoutInflater.from(myContext).inflate(R.layout.pic_grid_item, parent, false);
            ItemViewHolder itemViewHolder = new ItemViewHolder(view);
            return itemViewHolder;
        }
        return null;
    }

    /**
     * 声明列表项ViewHolder*/
    static class ItemViewHolder extends RecyclerView.ViewHolder
    {
        public ItemViewHolder(View view)
        {
            super(view);
            griditemLayout = (LinearLayout) view.findViewById(R.id.griditemLayout);
            griditemimgLayout = (RelativeLayout) view.findViewById(R.id.griditemimgLayout);
            grid_img = (ImageView) view.findViewById(R.id.grid_img);
            grid_img_state = (TextView) view.findViewById(R.id.grid_img_state);
        }

        LinearLayout griditemLayout;
        RelativeLayout griditemimgLayout;
        ImageView grid_img;

        TextView grid_img_state;
    }

    /**
     * 声明最后一个ViewHolder*/
    static class ItemFootViewHolder extends RecyclerView.ViewHolder
    {
        public ItemFootViewHolder(View view)
        {
            super(view);
            gridfootitemLayout = (RelativeLayout) view.findViewById(R.id.gridfootitemLayout);
        }
        RelativeLayout gridfootitemLayout;
    }

    /**
     * 将数据绑定至ViewHolder
     */
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int index) {

        if(viewHolder instanceof ItemViewHolder){
            PictureBean listItemModel = listitemList.get(index);
            final ItemViewHolder itemViewHold = ((ItemViewHolder)viewHolder);

            Uri uri = Uri.fromFile(new File(listItemModel.getPicPath()));

            RequestOptions options = new RequestOptions()
                    //设置等待时的图片
                    .placeholder(R.drawable.img_loading)
                    //设置加载失败后的图片显示
                    .error(R.drawable.img_error)
                    //缓存策略,跳过内存缓存【此处应该设置为false,否则列表刷新时会闪一下】
                    .skipMemoryCache(false)
                    //缓存策略,硬盘缓存-仅仅缓存最终的图像,即降低分辨率后的(或者是转换后的)
                    .diskCacheStrategy(DiskCacheStrategy.ALL)
                    //设置图片加载的优先级
                    .priority(Priority.HIGH);

            Glide.with(myContext)
                    .load(uri)
                    .apply(options)
                    //默认淡入淡出动画
                    .transition(withCrossFade())
                    .into(itemViewHold.grid_img);

            itemViewHold.grid_img_state.setText("(" + (index+1) + "/" + listitemList.size() + ")");

            //如果设置了回调,则设置点击事件
            if (mOnItemClickLitener != null)
            {
                itemViewHold.grid_img.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        int position = itemViewHold.getLayoutPosition();//在增加数据或者减少数据时候,position和index就不一样了
                        mOnItemClickLitener.onItemClick(view,position);
                    }
                });
            }
        }else if(viewHolder instanceof ItemFootViewHolder){
            final ItemFootViewHolder itemFootViewHold = ((ItemFootViewHolder)viewHolder);
            //如果设置了回调,则设置点击事件
            if (mOnItemClickLitener != null)
            {
                itemFootViewHold.gridfootitemLayout.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        mOnItemClickLitener.onItemAddClick();
                    }
                });
            }
        }

    }

    /**
     * 添加Item--用于动画的展现*/
    public void addItem(int position,PictureBean itemModel) {
        listitemList.add(position,itemModel);
        notifyItemInserted(position);
    }
    /**
     * 删除Item--用于动画的展现*/
    public void removeItem(int position) {
        listitemList.remove(position);
        notifyItemRemoved(position);
    }

    /*=====================添加OnItemClickListener回调================================*/
    public interface OnItemClickLitener
    {
        /**图片的点击事件*/
        void onItemClick(View view, int position);
        /**添加的点击事件*/
        void onItemAddClick();
    }

    private OnItemClickLitener mOnItemClickLitener;

    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
    {
        this.mOnItemClickLitener = mOnItemClickLitener;
    }

    //返回当前图片集合的所有路径集合【用于预览】
    public List<String> getAllPhotoPaths() {
        List<String> allPhotoPaths = new ArrayList<String>(listitemList.size());
        for (PictureBean  pictureBean: listitemList) {
            allPhotoPaths.add(pictureBean.getPicPath());
        }
        return allPhotoPaths;
    }

}

(2)常规使用

package com.why.project.photopickernewdemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.why.project.photopickernewdemo.adapter.PictureAdapter;
import com.why.project.photopickernewdemo.bean.PictureBean;
import com.why.project.photopickernewdemo.utils.Globals;

import java.util.ArrayList;

import me.iwf.photopicker.PhotoPicker;
import me.iwf.photopicker.PhotoPreview;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();

    private RecyclerView mRecyclerView;
    private ArrayList<PictureBean> mPictureBeansList;
    private PictureAdapter mPictureAdapter;

    private ArrayList<String> selPhotosPath = null;//选中的图片路径集合

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initViews();
        initDatas();
        initEvents();
    }

    private void initViews() {
        mRecyclerView = findViewById(R.id.picture_grid);
    }

    private void initDatas() {
        selPhotosPath = new ArrayList<String>();
        //=============图片九宫格=========================
        mPictureAdapter = null;
        mPictureBeansList = new ArrayList<PictureBean>();
        //设置布局管理器
        GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3);
        mRecyclerView.setLayoutManager(gridLayoutManager);

        if(mPictureAdapter == null){
            //设置适配器
            mPictureAdapter = new PictureAdapter(this, mPictureBeansList);
            mRecyclerView.setAdapter(mPictureAdapter);
            //添加分割线
            //设置添加删除动画
            //调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局
            mRecyclerView.setSelected(true);
        }else{
            mPictureAdapter.notifyDataSetChanged();
        }
    }

    private void initEvents() {
        //图片九宫格点击事件
        mPictureAdapter.setOnItemClickLitener(new PictureAdapter.OnItemClickLitener() {
            @Override
            public void onItemClick(View v, int position) {
                //打开图片预览界面
                ArrayList<String> photos = (ArrayList<String>) mPictureAdapter.getAllPhotoPaths();
                PhotoPreview.builder()
                        .setPhotos(photos)
                        .setCurrentItem(position)
                        .setShowDeleteButton(false)
                        .start(MainActivity.this);
            }

            @Override
            public void onItemAddClick() {
                PhotoPicker.builder()
                        .setPhotoCount(mPictureAdapter.MAX)
                        .setGridColumnCount(3)
                        //.setSelected(selPhotosPath)
                        .start(MainActivity.this, Globals.CHOOSE_PIC_REQUEST_CODE);
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        Log.w(TAG, "{onActivityResult}resultCode="+resultCode);
        Log.w(TAG, "{onActivityResult}requestCode="+requestCode);
        if (resultCode == Activity.RESULT_OK) {
            //选择照片
            if(requestCode == Globals.CHOOSE_PIC_REQUEST_CODE){

                if (data != null) {
                    selPhotosPath = data.getStringArrayListExtra(PhotoPicker.KEY_SELECTED_PHOTOS);
                }
                if (selPhotosPath != null) {

                    //下面的代码主要用于这样一个场景,就是注释了.setSelected(selPhotosPath)之后,还想要保证选择的图片不重复
                    /*for(String path : selPhotosPath){
                        Log.w(TAG,"path="+path);///storage/emulated/0/tempHxzk/IMG_1498034535796.jpg
                        boolean existThisPic = false;
                        for(int i=0;i<mPictureBeansList.size();i++){
                            if(path.equals(mPictureBeansList.get(i).getPicPath())){
                                //如果新选择的图片集合中存在之前选中的图片,那么跳过去
                                existThisPic = true;
                                break;
                            }
                        }
                        if(! existThisPic){
                            PictureBean pictureBean = new PictureBean();
                            pictureBean.setPicPath(path);
                            pictureBean.setPicName(getFileName(path));
                            //去掉总数目的限制,这里通过增大MAX的数字来实现
                            if (mPictureBeansList.size() < mPictureAdapter.MAX) {
                                mPictureBeansList.add(pictureBean);
                            } else {
                                Toast.makeText(MainActivity.this, "最多可以选择" + mPictureAdapter.MAX + "张图片", Toast.LENGTH_SHORT).show();
                                break;
                            }
                        }
                    }*/

                    //是常规操作,和上面的代码不可共存
                    for (String path : selPhotosPath) {
                        PictureBean pictureBean = new PictureBean();
                        pictureBean.setPicPath(path);
                        pictureBean.setPicName(Globals.getFileName(path));
                        //去掉总数目的限制,这里通过增大MAX的数字来实现
                        if (mPictureBeansList.size() < mPictureAdapter.MAX) {
                            mPictureBeansList.add(pictureBean);
                        } else {
                            Toast.makeText(MainActivity.this, "最多可以选择" + mPictureAdapter.MAX + "张图片", Toast.LENGTH_SHORT).show();
                            break;
                        }
                    }
                    mPictureAdapter.notifyDataSetChanged();
                }
            }
        }
    }
}

混淆配置

# PhotoPicker混淆
# Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
    **[] $VALUES;
    public *;
}
# support-v7-appcompat
-keep public class android.support.v7.widget.** { *; }
-keep public class android.support.v7.internal.widget.** { *; }
-keep public class android.support.v7.internal.view.menu.** { *; }
-keep public class * extends android.support.v4.view.ActionProvider {
    public <init>(android.content.Context);
}
# support-design
-dontwarn android.support.design.**
-keep class android.support.design.** { *; }
-keep interface android.support.design.** { *; }
-keep public class android.support.design.R$* { *; }

参考资料

donglua/PhotoPicker

项目demo下载地址

https://github.com/haiyuKing/PhotoPickerNewDemo

posted @ 2018-08-04 09:40  HaiyuKing  阅读(1472)  评论(0编辑  收藏  举报