我们在做相册这块内容的时候,会发现调用android相册时,只能返回一张图片,而不是多张,所以需要我们自己重写一个相册,类似微信,微博等发布状态的需求!
一般微信,微博等都是上传9张图片,而且都是九宫格形式展示,可以使用GridView或者GridLayout等实现。
下边主要讲一下RecyclerView的实现,借助此来记录一下RecyclerView子Item宽高正方形适配的方案!
先来张图吧!
首先我们要在adapter子item布局,重新测量:
public class SquareItemLayout extends RelativeLayout {
public SquareItemLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public SquareItemLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareItemLayout(Context context) {
super(context);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
this.setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));
int childWidthSize = this.getMeasuredWidth();
heightMeasureSpec = widthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
然后在子item布局中作为父布局使用:
<xx.xxxx.xxxx.SquareItemLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/img_add"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="1dp"
android:layout_gravity="center"
android:scaleType="centerCrop"
android:src="@mipmap/pic_add"
android:adjustViewBounds="true"/>
<ImageView
android:id="@+id/img_del"
android:clickable="true"
android:paddingTop="2dp"
android:paddingRight="2dp"
android:paddingLeft="10dp"
android:paddingBottom="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/img_add"
android:layout_alignRight="@id/img_add"
android:src="@mipmap/pic_del" />
xx.xxxx.xxxx.SquareItemLayout>
然后是我们的atapter,这个没有什么好说的,就是加载两种布局,一个添加图片的加号,一个是添加的图片,加号一直在最后!
public class PhotoAdapter extends RecyclerView.Adapter {
private ArrayList photoPaths = new ArrayList<>();
private LayoutInflater inflater;
private Context mContext;
public final static int TYPE_ADD = 1;
public final static int TYPE_PHOTO = 2;
public final static int MAX = 9;
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
private OnItemClickListener mOnItemClickListener;
public void setOnItemClickListener(OnItemClickListener mOnItemClickListener) {
this.mOnItemClickListener = mOnItemClickListener;
}
public PhotoAdapter(Context mContext, ArrayList photoPaths) {
this.photoPaths = photoPaths;
this.mContext = mContext;
inflater = LayoutInflater.from(mContext);
}
@Override public PhotoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = inflater.inflate(R.layout.layout_photo_item, parent, false);
return new PhotoViewHolder(itemView);
}
@Override
public void onBindViewHolder(final PhotoViewHolder holder, int position) {
if(mOnItemClickListener!=null){
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onItemClick(v,holder.getAdapterPosition());
}
});
}
if (getItemViewType(position) == TYPE_PHOTO) {
//图片
//这里加上自己的图片加载逻辑
}
holder.ivPhoto_del.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//删除图片
photoPaths.remove(holder.getAdapterPosition());
notifyDataSetChanged();
}
});
}else{
holder.ivPhoto_del.setVisibility(View.GONE);
}
}
@Override
public int getItemCount() {
int count = photoPaths.size() + 1;
if (count > MAX) {
count = MAX;
}
return count;
}
@Override
public int getItemViewType(int position) {
return (position == photoPaths.size() && position != MAX) ? TYPE_ADD : TYPE_PHOTO;
}
public static class PhotoViewHolder extends RecyclerView.ViewHolder {
private ImageView ivPhoto;
private ImageView ivPhoto_del;
public PhotoViewHolder(View itemView) {
super(itemView);
ivPhoto = (ImageView) itemView.findViewById(R.id.img_add);
ivPhoto_del =(ImageView) itemView.findViewById(R.id.img_del);
}
}
}
最后在activity中的使用:
PhotoAdapter photoAdapter = new PhotoAdapter(getActivity(), pathList);
recyclerView.setLayoutManager(new GridLayoutManager(3, OrientationHelper.VERTICAL));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(photoAdapter);
photoAdapter.setOnItemClickListener(new PhotoAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
if (photoAdapter.getItemViewType(position) == PhotoAdapter.TYPE_ADD) {
//这里点击的是加号
//添加自己处理相册多选跳转的逻辑
} else {
//这里点击的是图片
//添加自己处理图片点击事件逻辑
}
}
});
}
还有一个比较恶心的问题:就是选择GridLayoutManager的时候,这里我们想设置自己的间距。这里在网上找到一个,记录一下!
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;//跟LayoutManager参数一样
private int spacing;//自己想要设置的间距大小
private boolean includeEdge;//边缘是否设置间距
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item position
int column = position % spanCount; // item column
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)
if (position < spanCount) { // top edge
outRect.top = spacing;
}
outRect.bottom = spacing; // item bottom
} else {
outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
if (position >= spanCount) {
outRect.top = spacing; // item top
}
}
}
}
PhotoPicker
项目地址:https://github.com/donglua/PhotoPicker
Album
项目地址:https://github.com/yanzhenjie/Album
我们经常会遇到这样的问题,就是调用相机拍完照以后,拍的图片会保存在我们指定的目录下,但是在系统相册中却看不到这一张图片。
怎么解决这个问题呢,就需要我们去通知系统相册去更新内容:
这块在PhotoPicker的示例demo中也有涉及到,这里单独拿出来说一下:
//调用相机拍照的Intent
public Intent dispatchTakePictureIntent(){
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(mContext.getPackageManager()) != null) {
// Create the File where the photo should go
File file = createImageFile();
Uri photoFile;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String authority = mContext.getApplicationInfo().packageName + ".provider";
photoFile = FileProvider.getUriForFile(this.mContext.getApplicationContext(), authority, file);
} else {
photoFile = Uri.fromFile(file);
}
// Continue only if the File was successfully created
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoFile);
}
}
return takePictureIntent;
}
//通知相册更新内容
public void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
if (TextUtils.isEmpty(mCurrentPhotoPath)) {
return;
}
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
mContext.sendBroadcast(mediaScanIntent);
}
这样我们在调用系统相机拍完照之后,系统的相册也会有拍完的照片!
这块可以参考下面这篇文章,提供一个思路:
Android_优化查询加载大数量的本地相册图片