本次主要将上周实现的图片加载方面的功能整合到photoSelectActivity。效果如下图所示:
左图为图片显示及选择界面,分为3列;右图为不同图片文件夹的选择。
主要内容如下
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photo_selector);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);//弹出一个窗口,让背后的窗口变暗一点
initView();
initImageList();
initPopupWindow();
loadImageData();
}
1.initView主要绑定view id及设置OnClickListenere;
private void initView() {
mImageListView = (RecyclerView) findViewById(R.id.recycler_view);
mBtnSource = (RadioButton) findViewById(R.id.btn_source_img);
mTvFolderName = (TextView) findViewById(R.id.tv_folder_name);
mTvPreview = (TextView) findViewById(R.id.tv_preview);
mIvBack = (ImageView) findViewById(R.id.iv_back);
mTvSend = (TextView) findViewById(R.id.tv_send);
mLayoutBottom = (RelativeLayout) findViewById(R.id.layout_bottom);
mIvBack.setOnClickListener(this);
mTvSend.setOnClickListener(this);
mTvFolderName.setOnClickListener(this);
mTvPreview.setOnClickListener(this);
mBtnSource.setOnClickListener(this);
// 文件选择按钮,只有在加载数据完成并且数据不为空的时候才可以点击
mTvFolderName.setClickable(false);
// 发送和预览按钮只有在有照片选择的情况下才可以点击
mTvPreview.setClickable(false);
mTvSend.setClickable(false);
}
2.initImageList主要用于初始化照片选择列表,使用recycle view显示
private void initImageList() {
mImageBeans = new ArrayList<>();
mImageListView.setLayoutManager(new GridLayoutManager(this, 3));
mImageListView.addItemDecoration(new GridItemDecoration(this));
mImageAdapter = new RecycleViewAdapter<ImageBean>(this, mImageBeans) {
@Override
public int setItemLayoutId(int position) {
return R.layout.item_image_sel;
}
@Override
public void bindView(RViewHolder holder, final int position) {
// 使用Glide加载照片,它有缓存策略,避免 OOM
final ImageBean item = mImageBeans.get(position);
ImageView imageView = holder.getImageView(R.id.iv_img);//有就拿到,没有就先加入RViewHolder的mViews列表再返回
Glide.with(PhotoSelectActivity.this)
.load(item.getPath()).diskCacheStrategy(DiskCacheStrategy.ALL)
.error(R.drawable.bg_img_defalut)
.into(imageView);
// 单击照片本身,在预览窗口打开该照片
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mShowItem = item;
previewByItem();
}
});
// 照片右上角的选择器,根据照片被选择与否显示不同状态 icon
final RadioButton radioButton = (RadioButton) holder.getConvertView()
.findViewById(R.id.img_sel_status);
radioButton.setChecked(item.isSelected());
// 选择框单击事件监听,用于更新照片选择状态
radioButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ImageBean imageBean = mImageBeans.get(position);
if (imageBean.isSelected()) {
radioButton.setChecked(false);
imageBean.setSelected(false);
mSelectedImages.remove(imageBean);
updateBtnState();
} else if (mSelectedImages.size() < 9) {
radioButton.setChecked(true);
imageBean.setSelected(true);
mSelectedImages.add(imageBean);
updateBtnState();
} else {
radioButton.setChecked(false);
Toast.makeText(PhotoSelectActivity.this,
"一次只能选择9张喔~",Toast.LENGTH_SHORT).show();
}
}
});
}
};
mImageListView.setAdapter(mImageAdapter);
}
选择框状态改变需相应的改变“预览”和“发送”按钮的显示文字和可点击状态:
private void updateBtnState() {
String size = String.valueOf(mSelectedImages.size());
String tvSend = "发送(" + size + "/9)";
String tvPre = "预览(" + size + "/9)";
mTvSend.setText(tvSend);
mTvPreview.setText(tvPre);
if (mSelectedImages.isEmpty()) {
mTvSend.setClickable(false);
mTvSend.setTextColor(getResources().getColor(R.color.blue_gray));
mTvPreview.setClickable(false);
mTvPreview.setTextColor(getResources().getColor(R.color.blue_gray));
} else {
mTvSend.setClickable(true);
mTvSend.setTextColor(getResources().getColor(R.color.colorAccent));
mTvPreview.setClickable(true);
mTvPreview.setTextColor(getResources().getColor(R.color.colorAccent));
}
}
3.initPopupWindow主要用于初始化图片文件夹选择器
private void initPopupWindow() {
// 弹窗初始化,高度设置为屏幕的 3/4
View rootView = LayoutInflater.from(this).inflate(R.layout.popup_window,
mLayoutBottom, false);
int popupHeight = (int) (this.getResources().getDisplayMetrics().heightPixels * 0.75f);
mFolderWindow = new PopupWindow(rootView, LinearLayout.LayoutParams.MATCH_PARENT, popupHeight);
mFolderWindow.setOutsideTouchable(true);
mFolderWindow.setFocusable(true);
mFolderWindow.setAnimationStyle(R.style.popup_window_anim);
// 在PopupWindow隐藏后,将背景恢复正常亮度
mFolderWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
lightOn();
}
});
// 文件夹列表初始化
mFolderBeans = new ArrayList<>();
RecyclerView folderListView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
folderListView.setLayoutManager(new LinearLayoutManager(this));
mFolderAdapter = new RecycleViewAdapter<FolderBean>(this, mFolderBeans) {
@Override
public int setItemLayoutId(int position) {
return R.layout.item_folder;
}
@Override
public void bindView(RViewHolder holder, int position) {
String name = mFolderBeans.get(position).getName();
int size = mFolderBeans.get(position).getImageList().size();
boolean selected = mFolderBeans.get(position).isSelected();
ImageBean image = mFolderBeans.get(position).getImageList().get(0);
holder.setText(R.id.tv_folder_name, name);
holder.setText(R.id.tv_image_count, String.valueOf(size) + " 张");
holder.setVisible(R.id.iv_sel_status, selected);
ImageView imageView = holder.getImageView(R.id.iv_cover);
Glide.with(PhotoSelectActivity.this)
.load(image.getPath()).diskCacheStrategy(DiskCacheStrategy.ALL)
.error(R.drawable.bg_img_defalut)
.into(imageView);
}
};
mFolderAdapter.setItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(RViewHolder holder, int position) {
// 如果选择了新的文件夹
if (position != mSelFolderIndex) {
// 将上个文件夹的选择状态去除
mFolderBeans.get(mSelFolderIndex).setSelected(false);
mFolderAdapter.notifyItemChanged(mSelFolderIndex);
// 将选择的文件夹做更新
mFolderBeans.get(position).setSelected(true);
mFolderAdapter.notifyItemChanged(position);
// 保存当前选择的文件夹
mSelFolderIndex = position;
mSelectedFolder = mFolderBeans.get(position);
mTvFolderName.setText(mSelectedFolder.getName());
// 关闭弹窗并更新图片列表
updateImageList();
}
hidePopup();
}
});
folderListView.setAdapter(mFolderAdapter);
}
4.loadImageData主要用于加载手机照片数据(另一个线程,在上周写的ImageUtils中实现)
private void loadImageData() {
ImageUtils.loadImageList(this, new ImageUtils.OnLoadImageCallBack() {
@Override
public void callBack(List<FolderBean> folderList) {
if (folderList.isEmpty()) {
Toast.makeText(PhotoSelectActivity.this,
"无照片~",Toast.LENGTH_SHORT).show();
} else {
mSelectedFolder = folderList.get(0);
mSelFolderIndex = 0;
folderList.get(0).setSelected(true);
mFolderBeans.clear();
mFolderBeans.addAll(folderList);
// 加载数据在子线程完成的,需要使用mHandler去通知主线程跟新 UI
mHandler.sendEmptyMessage(0x100);
}
}
});
}
mHandler通知主线程后,要处理Message
@SuppressLint("HandlerLeak")
private class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0x100) {
mFolderAdapter.notifyDataSetChanged();
updateImageList();
// 有照片,可以点击
mTvFolderName.setClickable(true);
}
}
}
/**
* 根据选择的文件夹,更新图片列表
*/
private void updateImageList() {
mImageBeans.clear();
mImageBeans.addAll(mSelectedFolder.getImageList());
mImageAdapter.notifyDataSetChanged();
}
5.OnClickListener的具体实现
@Override
public void onClick(View v) {
if (v.getId() == R.id.tv_folder_name) {
if (mFolderWindow.isShowing()) {
hidePopup();
} else {
showPopup();
}
} else if (v.getId() == R.id.iv_back) {
this.setResult(RESULT_CANCELED);
this.finish();
} else if (v.getId() == R.id.tv_send) {
sendImage();
} else if (v.getId() == R.id.tv_preview) {
previewByBtn();
} else if (v.getId() == R.id.btn_source_img) {
if (mBtnSource.isChecked()) {
mBtnSource.setChecked(false);
isSourceImage = false;
} else {
mBtnSource.setChecked(true);
isSourceImage = true;
}
}
}
/**
* 显示和隐藏文件夹选择框 显示在底部布局之上
*/
private void showPopup() {
int[] location = new int[2];
mLayoutBottom.getLocationOnScreen(location);
mFolderWindow.showAtLocation(mLayoutBottom, Gravity.NO_GRAVITY, location[0],
location[1] - mFolderWindow.getHeight());
lightOff();
}
private void hidePopup() {
mFolderWindow.dismiss();
}
/**
* popupWindow 显示的时候 将图片列表区域变暗
* popupWindow 隐藏的时候恢复
*/
private void lightOn(){
WindowManager.LayoutParams attributes = getWindow().getAttributes();
attributes.alpha = 1.0f;
getWindow().setAttributes(attributes);
}
private void lightOff(){
WindowManager.LayoutParams attributes = getWindow().getAttributes();
attributes.alpha = 0.3f;
getWindow().setAttributes(attributes);
}
6.图片显示RecycleView所用的ItemDecoration
mImageListView.addItemDecoration(new GridItemDecoration(this));
public class GridItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[] { android.R.attr.listDivider };
private Drawable mDivider;
public GridItemDecoration(Context context) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
drawHorizontal(c, parent);
drawVertical(c, parent);
}
private int getSpanCount(RecyclerView parent) {
// 列数
int spanCount = -1;
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
spanCount = ((StaggeredGridLayoutManager) layoutManager)
.getSpanCount();
}
return spanCount;
}
private void drawHorizontal(Canvas c, RecyclerView parent) {
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getLeft() - params.leftMargin;
final int right = child.getRight() + params.rightMargin
+ mDivider.getIntrinsicWidth();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
private void drawVertical(Canvas c, RecyclerView parent) {
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getTop() - params.topMargin;
final int bottom = child.getBottom() + params.bottomMargin;
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicWidth();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
private boolean isLastColumn(RecyclerView parent, int pos, int spanCount, int childCount) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
// 如果是最后一列,则不需要绘制右边
if ((pos + 1) % spanCount == 0) {
return true;
}
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int orientation = ((StaggeredGridLayoutManager) layoutManager)
.getOrientation();
if (orientation == StaggeredGridLayoutManager.VERTICAL) {
// 如果是最后一列,则不需要绘制右边
if ((pos + 1) % spanCount == 0) {
return true;
}
} else {
childCount = childCount - childCount % spanCount;
if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
return true;
}
}
return false;
}
private boolean isLastRaw(RecyclerView parent, int pos, int spanCount, int childCount) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
childCount = childCount - childCount % spanCount;
if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
return true;
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int orientation = ((StaggeredGridLayoutManager) layoutManager)
.getOrientation();
// StaggeredGridLayoutManager 且纵向滚动
if (orientation == StaggeredGridLayoutManager.VERTICAL) {
childCount = childCount - childCount % spanCount;
// 如果是最后一行,则不需要绘制底部
if (pos >= childCount)
return true;
} else { // StaggeredGridLayoutManager 且横向滚动
// 如果是最后一行,则不需要绘制底部
if ((pos + 1) % spanCount == 0) {
return true;
}
}
}
return false;
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
int spanCount = getSpanCount(parent);
int childCount = parent.getAdapter().getItemCount();
if (isLastRaw(parent, itemPosition, spanCount, childCount)){ // 如果是最后一行,则不需要绘制底部
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
} else if (isLastColumn(parent, itemPosition, spanCount, childCount)){// 如果是最后一列,则不需要绘制右边
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(),
mDivider.getIntrinsicHeight());
}
}
}