相册(1) ---- 获取所有照片并按照时间分组


效果图

相册(1) ---- 获取所有照片并按照时间分组

一. 使用的第三方依赖及知识点

1. recyclerView适配器BaseRecyclerViewAdapterHelper

https://github.com/CymChad/BaseRecyclerViewAdapterHelper/releases

使用
  • (1) 继承 BaseMultiItemQuickAdapter
    因为集合中有两个种集合对象, 而这两种集合对象都实现了MultiItemEntity接口, 所以此处实体写为MultiItemEntity
  • (2) 在构造方法中添加两种布局的
    //TYPE_HEADER和TYPE_DATA为定义的两个常量
    //实现MultiItemEntity接口的实体类需要实现getItemType()方法,返回值即为TYPE_HEADER或TYPE_DATA
    addItemType(TYPE_HEADER, R.layout.tab1_item_header)
    addItemType(TYPE_DATA, R.layout.tab1_item_photo)
    
  • (3) 实体类实现MultiItemEntity接口, getItemType()方法返回两种TYPE

2. 粘性头部 PinnedSectionItemDecoration

https://github.com/oubowu/PinnedSectionItemDecoration

使用
  • (1) 在adapter中添加如下代码
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
    super.onAttachedToRecyclerView(recyclerView)
    FullSpanUtil.onAttachedToRecyclerView(recyclerView, this, TYPE_HEADER)
}

override fun onViewAttachedToWindow(holder: BaseViewHolder) {
    super.onViewAttachedToWindow(holder)
    FullSpanUtil.onViewAttachedToWindow(holder, this, TYPE_HEADER)
}

注: 此处提供一个通用的BaseHeaderAdapter

abstract class BaseHeaderAdapter<T : MultiItemEntity>(data: List<T>) :
    BaseMultiItemQuickAdapter<T, BaseViewHolder>(data) {

    init {
        addItemTypes()
    }

    protected abstract fun addItemTypes()

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        FullSpanUtil.onAttachedToRecyclerView(recyclerView, this, TYPE_HEADER)
    }

    override fun onViewAttachedToWindow(holder: BaseViewHolder) {
        super.onViewAttachedToWindow(holder)
        FullSpanUtil.onViewAttachedToWindow(holder, this, TYPE_HEADER)
    }
}
  • (2) 在代码中添加
view.rv_tab_photo.addItemDecoration(
    PinnedHeaderItemDecoration.Builder(TYPE_HEADER)
        .disableHeaderClick(false)	
        .create()
)

3. 要点:

  • 头部时间和照片均为list对象, 通过MultiItemEntity接口中的getItemType自动识别为头部或者照片
  • 将时间list和照片list合并, 按照时间戳, 进行倒序排列设置进adapter即可

4. 逻辑

  • 获取手机全部照片对象MultiPhotoEntity, 对象实现MultiItemEntity接口

    fun getLocalPhotosMulti(context: Context): List<MultiPhotoEntity> {
        val list = ArrayList<MultiPhotoEntity>()
        val projection = arrayOf(
            MediaStore.Images.Media.DATA,
            MediaStore.Images.Media.DISPLAY_NAME,
            MediaStore.Images.Media.SIZE
        )
        val where = (MediaStore.Images.Media.MIME_TYPE + "=? or " +
                MediaStore.Images.Media.MIME_TYPE + "=? or " +
                MediaStore.Images.Media.MIME_TYPE + "=? or " +
                MediaStore.Images.Media.MIME_TYPE + "=?")
        //指定格式
        val whereArgs = arrayOf(
            "image/jpeg",
            "image/png",
            "image/jpg",
            "image/gif"
        )
        val cursor = context.contentResolver.query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            projection,
            where,
            whereArgs,
            MediaStore.Images.Media.DATE_MODIFIED + " desc "
        ) ?: return list
        //没有图片的时候反回0,所以不用try-catch
        while (cursor.moveToNext()) {
            val multiPhotoEntity = MultiPhotoEntity()
            val imageInfo = ImageInfo()
            //获取图片的名称
            imageInfo.title = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME))
            val data = cursor.getBlob(cursor.getColumnIndex(MediaStore.Images.Media.DATA))
            val path = String(data, 0, data.size - 1)
            multiPhotoEntity.modifyDate = DateUtil.timeStampToString(File(path).lastModified(), "yyyy-MM-dd EEEE")
            multiPhotoEntity.timestamp = File(path).lastModified()
            imageInfo.modifyTimestamp = File(path).lastModified()
            imageInfo.modifyTimeString = DateUtil.timeStampToString(File(path).lastModified(), "yyyy-MM-dd EEEE")
            imageInfo.filePath = path
            imageInfo.fileSize = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE))
            imageInfo.isChecked = false
            imageInfo.fileType = 6
            multiPhotoEntity.imageInfo = imageInfo
            list.add(multiPhotoEntity)
        }
        cursor.close()
        return list
    }
    
  • 通过手机照片对象的时间, 将其中的时间取出来组成MultiHeaderEntity头部对象(例如三张照片, 时间分别是2019-05-14, 2019-05-15, 2019-05-15, 则头部对象长度为2个)

    /**
     * 所有照片的时间, 获取时间集合, 转化为有时间的跟照片对象类型(均实现了MultiItemEntity接口)一样的头部对象
     */
    fun getHeaderInfo(context: Context): List<MultiHeaderEntity> {
    	//获取本地所有的照片
        val imageInfos: List<ImageInfo?>? = getLocalPhotos(context)
        val multiPhotoEntities = mutableListOf<MultiHeaderEntity>()
        if (imageInfos != null && imageInfos.isNotEmpty()) {
            for (i in 0 until imageInfos.size) {
                var isAdd = false
                if (multiPhotoEntities.size > 0) {
                    for (j in 0 until multiPhotoEntities.size) {
                        if ((multiPhotoEntities[j] as MultiHeaderEntity).header == imageInfos[i]?.modifyTimeString) {
    //                            (multiPhotoEntities[j] as MultiHeaderEntity).imageInfo = imageInfos[i]
                            isAdd = true
                            break
                        }
                    }
                }
                if (!isAdd) {
                    val photoHeaderEntity = MultiHeaderEntity()
                    photoHeaderEntity.header = (imageInfos[i]?.modifyTimeString)
                    //时间戳转换为日期,去掉分时,将日期转为时间戳,因为是倒序排列,所以需要添加一天的长度,否则出现照片在时间头下面的情况
                    photoHeaderEntity.timestamp = DateUtil.dateToTimestamp(DateUtil.timeStampToString(imageInfos[i]?.modifyTimestamp!! + 1 * 24 * 60 * 60 * 1000, "yyyy-MM-dd"))
    //                    photoHeaderEntity.imageInfo = imageInfos[i]
                    multiPhotoEntities.add(photoHeaderEntity)
                }
            }
        }
        return multiPhotoEntities
    }
    
  • 合并头部list 和照片list

    //获取所有头部list
       val headerList = PhotoUtil.getHeaderInfo(activity!!)       //例长度80 
       //获取所有照片list
       val photosList = PhotoUtil.getLocalPhotosMulti(activity!!) 	//例长度为2000
       //创建一个新集合,将头部和照片添加,并倒序排列
       val list = mutableListOf<MultiItemEntityWithTimestamp>()	//因为要用时间戳进行排列,所以需要获取时间戳,所以定义一个实现了getStamp的方法的MultiItemEntityWithTimestamp接口,该接口也继承MultiItemEntity
    list.addAll(headerList)
    list.addAll(photosList)
    //按照时间戳进行倒序排列	
    list.sortByDescending {
        it.getStamp()
    }