安卓开发中,我们知道网格布局使用GirdLayout,实现网格布局的组件是GridView。现在项目需要实现如下图的一个功能:
中间的图片显示我们可以设计3中实现方式:
1)使用GridLayout添加ItemView的方式
2)使用GridViewx控件,通过Adapter来控制显示的界面
3)使用RecyclerViewk控件,通过设置GridLayoutManager来设置Item的显示方式。
但是根据需求,需要让图片Item可以拖动到底部删除,这个功能我们会发现使用方法1会比较麻烦,因为添加图片的方式有多种,删除图片的方式也有多种,添加、删除item的方法不好控制,最重要的一点就是不够简单,复杂就代表bug多。
然后我们来说第二种和第三种方式,其实区别不大,重要的是GridView的Adapter提供了一个setOnItemLongClickListener来设置Item长按的事件,但是使用RecyclerView就需要在Adapter里面通过控件的Id来设置长按事件,长按可以拖动方法主要就是需要获取到长按控件的一个快照,然后对快照进行操作。
//通过被长按item,获取拖动item的bitmap
Bitmap dragBitmap = Bitmap.createBitmap(view.getDrawingCache());
下面是一个实现了可以拖拽的GridView自定义控件代码,只需要自己给它设置数据之后就可以执行item的拖拽事件了。
package com.example.xiaolin.draggridview.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ImageView;
import com.blankj.utilcode.util.LogUtils;
import com.example.xiaolin.draggridview.adapter.GridViewAdapter;
public class DragGridView extends GridView {
private static final int DRAG_IMG_SHOW = 1;
private static final int DRAG_IMG_NOT_SHOW = 0;
private static final String LOG_TAG = "DragGridView";
private static final float AMP_FACTOR = 1.2f;
private ImageView dragImageView;
private WindowManager.LayoutParams dragImageViewParams;
private WindowManager windowManager;
private boolean isViewOnDrag = false;
/**previous dragged over position*/
private int preDraggedOverPositon = AdapterView.INVALID_POSITION;
private int downRawX;
private int downRawY;
private OnItemLongClickListener onLongClickListener = new OnItemLongClickListener(){
@Override
//长按item开始拖动
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
//记录长按item位置
preDraggedOverPositon = position;
//获取被长按item的drawing cache
view.destroyDrawingCache();
view.setDrawingCacheEnabled(true);
//通过被长按item,获取拖动item的bitmap
Bitmap dragBitmap = Bitmap.createBitmap(view.getDrawingCache());
//设置拖动item的参数
dragImageViewParams.gravity = Gravity.TOP | Gravity.LEFT;
//设置拖动item为原item 1.2倍
dragImageViewParams.width = (int)(AMP_FACTOR*dragBitmap.getWidth());
dragImageViewParams.height = (int)(AMP_FACTOR*dragBitmap.getHeight());
//设置触摸点为绘制拖动item的中心
dragImageViewParams.x = (downRawX - dragImageViewParams.width/2);
dragImageViewParams.y = (downRawY - dragImageViewParams.height/2);
dragImageViewParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
dragImageViewParams.format = PixelFormat.TRANSLUCENT;
dragImageViewParams.windowAnimations = 0;
//dragImageView为被拖动item的容器,清空上一次的显示
if((int)dragImageView.getTag() == DRAG_IMG_SHOW) {
windowManager.removeView(dragImageView);
dragImageView.setTag(DRAG_IMG_NOT_SHOW);
}
//设置本次被长按的item
dragImageView.setImageBitmap(dragBitmap);
//添加拖动item到屏幕
windowManager.addView(dragImageView, dragImageViewParams);
dragImageView.setTag(DRAG_IMG_SHOW);
isViewOnDrag = true;
//设置被长按item不显示
((GridViewAdapter)getAdapter()).hideView(position);
return true;
}
};
public DragGridView(Context context) {
super(context);
initView();
}
public DragGridView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public DragGridView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
public void initView() {
setOnItemLongClickListener(onLongClickListener);
//初始化显示被拖动item的image view
dragImageView = new ImageView(getContext());
dragImageView.setTag(DRAG_IMG_NOT_SHOW);
//初始化用于设置dragImageView的参数对象
dragImageViewParams = new WindowManager.LayoutParams();
//获取窗口管理对象,用于后面向窗口中添加dragImageView
windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
//被按下时记录按下的坐标
if(ev.getAction() == MotionEvent.ACTION_DOWN) {
//获取触摸点相对于屏幕的坐标
downRawX = (int)ev.getRawX();
downRawY = (int)ev.getRawY();
}
//dragImageView处于被拖动时,更新dragImageView位置
else if((ev.getAction() == MotionEvent.ACTION_MOVE) && (isViewOnDrag == true)) {
Log.i(LOG_TAG, "" + ev.getRawX() + " " + ev.getRawY());
//设置触摸点为dragImageView中心
dragImageViewParams.x = (int)(ev.getRawX() - dragImageView.getWidth()/2);
dragImageViewParams.y = (int)(ev.getRawY() - dragImageView.getHeight()/2);
//更新窗口显示
windowManager.updateViewLayout(dragImageView, dragImageViewParams);
//获取当前触摸点的item position
int currDraggedPosition = pointToPosition((int)ev.getX(), (int)ev.getY());
//如果当前停留位置item不等于上次停留位置的item,交换本次和上次停留的item
if((currDraggedPosition != AdapterView.INVALID_POSITION) && (currDraggedPosition != preDraggedOverPositon)) {
((GridViewAdapter)getAdapter()).swapView(preDraggedOverPositon, currDraggedPosition);
preDraggedOverPositon = currDraggedPosition;
}
}
//释放dragImageView
else if((ev.getAction() == MotionEvent.ACTION_UP) && (isViewOnDrag == true)) {
((GridViewAdapter)getAdapter()).showHideView();
if((int)dragImageView.getTag() == DRAG_IMG_SHOW) {
windowManager.removeView(dragImageView);
((GridViewAdapter)getAdapter()).removeView(dragImageView.getId());
dragImageView.setTag(DRAG_IMG_NOT_SHOW);
}
isViewOnDrag = false;
}
return super.onTouchEvent(ev);
}
}
但是我们发现,其实我们并不需要实现图片之间的位置互换功能,只需要实现图片Item拖拽到底部进行删除的功能,那么就不需要更改Item的位置。而且RecyclerView有一个ItemTouchHelper帮助类来实现图片的手势的操作,实现方式简单,所以最后我们选用RecyclerView设置GridLayoutManager的方式来实现这个功能。
class FullyGridLayoutManager : GridLayoutManager {
private val mMeasuredDimension = IntArray(2)
internal val mState = RecyclerView.State()
constructor(context: Context, spanCount: Int) : super(context, spanCount) {}
constructor(context: Context, spanCount: Int, orientation: Int, reverseLayout: Boolean) : super(context, spanCount, orientation, reverseLayout) {}
override fun onMeasure(recycler: RecyclerView.Recycler?, state: RecyclerView.State?, widthSpec: Int, heightSpec: Int) {
val widthMode = View.MeasureSpec.getMode(widthSpec)
val heightMode = View.MeasureSpec.getMode(heightSpec)
val widthSize = View.MeasureSpec.getSize(widthSpec)
val heightSize = View.MeasureSpec.getSize(heightSpec)
var width = 0
var height = 0
val count = itemCount
val span = spanCount
for (i in 0 until count) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension)
if (orientation == LinearLayoutManager.HORIZONTAL) {
if (i % span == 0) {
width += mMeasuredDimension[0]
}
if (i == 0) {
height = mMeasuredDimension[1]
}
} else {
if (i % span == 0) {
height += mMeasuredDimension[1]
}
if (i == 0) {
width = mMeasuredDimension[0]
}
}
}
when (widthMode) {
View.MeasureSpec.EXACTLY -> width = widthSize
}
when (heightMode) {
View.MeasureSpec.EXACTLY -> height = heightSize
}
setMeasuredDimension(width, height)
}
private fun measureScrapChild(recycler: RecyclerView.Recycler?, position: Int, widthSpec: Int,
heightSpec: Int, measuredDimension: IntArray) {
val itemCount = mState.itemCount
if (position < itemCount) {
try {
val view = recycler!!.getViewForPosition(0)
if (view != null) {
val p = view.layoutParams as RecyclerView.LayoutParams
val childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
paddingLeft + paddingRight, p.width)
val childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
paddingTop + paddingBottom, p.height)
view.measure(childWidthSpec, childHeightSpec)
measuredDimension[0] = view.measuredWidth + p.leftMargin + p.rightMargin
measuredDimension[1] = view.measuredHeight + p.bottomMargin + p.topMargin
recycler.recycleView(view)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
RecyclerView的手势帮助类,最主要的是它的回调方法,我们需要实现ItemTouchHelper.Callback接口的方法来实现拖拽功能。
/**
* ItemTouchHelper 回调接口
*/
public class TouchHelperCallback extends ItemTouchHelper.Callback {
public static final float ALPHA_FULL = 1.0f;
private ConstraintLayout mDeletePicLayout;
private OnPictureItemDeleteListener mItemDeleteListener;
public TouchHelperCallback(ConstraintLayout deletePicLayout) {
mDeletePicLayout = deletePicLayout;
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
final int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
} else {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
if (source.getItemViewType() != target.getItemViewType()) {
return false;
}
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
}
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
// Fade out the view as it is swiped out of the parent's bounds
final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
viewHolder.itemView.setAlpha(alpha);
viewHolder.itemView.setTranslationX(dX);
} else {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
if(isCurrentlyActive){
mDeletePicLayout.setVisibility(View.VISIBLE);
int itemViewBottom = viewHolder.itemView.getBottom();
int itemViewTop = viewHolder.itemView.getTop();
float itemViewY = viewHolder.itemView.getY();
float deletePicLayoutTop = mDeletePicLayout.getY();
int adapterPosition = viewHolder.getAdapterPosition();
if(adapterPosition <= 1){
if((itemViewBottom+ itemViewY) >= deletePicLayoutTop){
mItemDeleteListener.onItemDeleted(viewHolder.getAdapterPosition());
}
}else {
if((itemViewTop+ itemViewY) >= deletePicLayoutTop){
mItemDeleteListener.onItemDeleted(viewHolder.getAdapterPosition());
}
}
}else{
mDeletePicLayout.setVisibility(View.GONE);
}
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
// We only want the active item to change
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
}
super.onSelectedChanged(viewHolder, actionState);
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setAlpha(ALPHA_FULL);
}
public void setOnPictureItemDeleteListener(OnPictureItemDeleteListener itemDeleteListener){
mItemDeleteListener = itemDeleteListener;
}
public interface OnPictureItemDeleteListener{
void onItemDeleted(int deletePosition);
}
}
最后就是需要给Recyclerview设置LayoutManager成我们自定义的GridLayouManager,然后把ItemToucherHelper设置给Adaptert的ViewHoder进行数据绑定。
val manager = FullyGridLayoutManager(this@HomeCreateWriteWorkActivity, 2, GridLayoutManager.VERTICAL, false)
mPictureGrideView.layoutManager = manager
val helperCallback = TouchHelperCallback(mDeletePicLayout)
val mItemDragHelper = ItemTouchHelper(helperCallback)
mImageAdapter = HomeGridImageAdapter(this@HomeCreateWriteWorkActivity, onAddPicClickListener, mItemDragHelper, helperCallback)
最后最重要的就是需要把手势处理事件添加到我们的RecyclerView:
mItemDragHelper.attachToRecyclerView(mPictureGrideView)
这样我们就可以实现图片的拖拽的功能了。
但是需要注意的就是我们这里需要有图片添加的功能,添加图片使用的也是第三方的开源框架,下面我就直接把Activity的代码贴出来:
class HomeCreateWriteWorkActivity : AbsTitleFenJiActivity() {
private var mMaxSelectedNum = 4
private var mCurrentSelectedNum = 0
private var mQuestionId: String? = null
private lateinit var mPictureGrideView: RecyclerView
private lateinit var mLlPostLoadingView: LinearLayout
private lateinit var mDeletePicLayout: ConstraintLayout
private var mImageAdapter: HomeGridImageAdapter? = null
private var selectList: ArrayList<LocalMedia> = ArrayList()
private var mPictureList: ArrayList<String> = ArrayList()
override fun getTitleString(): String {
return "写一写"
}
override fun getTitleRightString(): String {
return ""
}
override fun getTitleRightImageView(): Int {
return 0
}
override fun getLayoutId(): Int {
return R.layout.activity_create_write_work
}
override fun initViews(savedInstanceState: Bundle?) {
super.initViews(savedInstanceState)
setImmersionBar(R.color.trans, true, true)
mPictureGrideView = findView(R.id.gl_picture_recyclerview)
mDeletePicLayout = findView(R.id.cl_delete_pic_layout)
mLlPostLoadingView = findView(R.id.ll_layout_paying)
}
override fun initData(savedInstanceState: Bundle?) {
val bundle = intent.extras
if (ObjectUtils.isNotEmpty(bundle)) {
mQuestionId = bundle.getString(ConstantExtra.WRITE_QUESTION_ID)
}
val createTipsTv: AppCompatTextView = findView(R.id.tv_create_write_tips)
createTipsTv.text = "提示:请上传回答课后问题的图片,并确保图片清晰、\n" +
"字迹易辨认,老师点评后会消息及时通知,请留意微\n" +
"信消息。"
val manager = FullyGridLayoutManager(this@HomeCreateWriteWorkActivity, 2, GridLayoutManager.VERTICAL, false)
mPictureGrideView.layoutManager = manager
val helperCallback = TouchHelperCallback(mDeletePicLayout)
val mItemDragHelper = ItemTouchHelper(helperCallback)
mImageAdapter = HomeGridImageAdapter(this@HomeCreateWriteWorkActivity, onAddPicClickListener, mItemDragHelper, helperCallback)
mImageAdapter?.setList(selectList)
mImageAdapter?.setSelectMax(mMaxSelectedNum)
mPictureGrideView.adapter = mImageAdapter
mItemDragHelper.attachToRecyclerView(mPictureGrideView)
mImageAdapter?.setOnItemClickListener(object : HomeGridImageAdapter.OnItemClickListener {
override fun onItemClick(position: Int, v: View) {
if (selectList.size > 0) {
val media = selectList.get(position)
val pictureType = media.pictureType
val mediaType = PictureMimeType.pictureToVideo(pictureType)
when (mediaType) {
1 ->
PictureSelector.create(this@HomeCreateWriteWorkActivity).themeStyle(R.style.picture_default_style).openExternalPreview(position, selectList)
}
}
}
})
}
@SuppressLint("ImplicitSamInstance")
override fun initListeners() {
mHeadBackBtn.setOnClickListener { sureExitPublishWriteWorkActivity() }
val rlpostWritePicture = findView<RelativeLayout>(R.id.rl_post_write_pitures)
rlpostWritePicture.setOnClickListener {
mLlPostLoadingView.visibility = View.VISIBLE
ViewClickUtils.setViewDelaySecondsClickAble(rlpostWritePicture, mCurrentSelectedNum * 500)
mLlPostLoadingView.postDelayed({
if (mCurrentSelectedNum > 0 && mPictureList.size > 0 && mCurrentSelectedNum == mPictureList.size) {
postWriteWorkPictureList()
}
}, mCurrentSelectedNum * 500L) //延迟上传图片
}
mImageAdapter?.setOnAddPicDelectListener(object : HomeGridImageAdapter.OnAddPicDelectListener {
override fun onAddPicDelete(listSize: Int) {
if (listSize < 4) {
mMaxSelectedNum = 4 - selectList.size
}
mCurrentSelectedNum = listSize
}
})
}
/**
* 屏蔽物理返回按钮
*/
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
sureExitPublishWriteWorkActivity()
return keyCode == KeyEvent.KEYCODE_BACK
}
private fun sureExitPublishWriteWorkActivity() {
val tipMessageDialog = TipMessageDialog.Builder(context)
tipMessageDialog.setDialogBackground(R.drawable.bg_white_four_corners_r10)
tipMessageDialog.setMessage("您确定跳出该页面吗?")
tipMessageDialog.setMessageTextSize(16)
tipMessageDialog.setButtonTextAndListener("再想想", "确认", object : TipMessageDialog.OnButtonClickListener {
override fun onPositiveBtnClick() {
}
override fun onNegativeBtnClick() {
finish()
}
})
tipMessageDialog.createTipPopToShow(false)
}
private fun postWriteWorkPictureList() {
val netController = object : NetController<Any>(mDisposable) {
override fun success(result: Response<Any>?) {
mLlPostLoadingView.visibility = View.GONE
if (ObjectUtils.isNotEmpty(result)) {
finish()
}
}
override fun failure(throwable: Throwable?) {
super.failure(throwable)
mLlPostLoadingView.visibility = View.GONE
showCentreToastByText("上传失败,请重试")
}
}
val selectedPicList = ArrayList<String>()
for (index in 0 until mCurrentSelectedNum) {
selectedPicList.add(mPictureList[index])
}
if (ObjectUtils.isNotEmpty(mQuestionId)) {
netController.request(StudentApi.getService().postWriteWorkList(mQuestionId?.toLong()!!, selectedPicList.toString()))
}
}
override fun isSwipeBackAble(): Boolean {
return true
}
override fun isBindEventBus(): Boolean {
return false
}
private val onAddPicClickListener = object : HomeGridImageAdapter.onAddPicClickListener {
override fun onAddPicClick() {
// 进入相册 以下是例子:不需要的api可以不写
PictureSelector.create(this@HomeCreateWriteWorkActivity)
.openGallery(PictureMimeType.ofImage())// 全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()
.theme(R.style.picture_default_style)// 主题样式设置 具体参考 values/styles 用法:R.style.picture.white.style
.maxSelectNum(mMaxSelectedNum)// 最大图片选择数量
.minSelectNum(1)// 最小选择数量
.imageSpanCount(4)// 每行显示个数
.selectionMode(PictureConfig.MULTIPLE)// 多选 or 单选
.previewImage(false)// 是否可预览图片
.isCamera(true)// 是否显示拍照按钮
.isZoomAnim(true)// 图片列表点击 缩放效果 默认true
//.enableCrop(true)// 是否裁剪
.compress(true)// 是否压缩
.cropCompressQuality(70)
.compressSavePath(getBaseContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString())
.synOrAsy(true)//同步true或异步false 压缩 默认同步
.glideOverride(160, 160)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度
.withAspectRatio(1, 1)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定义
.hideBottomControls(true)// 是否显示uCrop工具栏,默认不显示
.isGif(false)// 是否显示gif图片
.freeStyleCropEnabled(false)// 裁剪框是否可拖拽
.circleDimmedLayer(false)// 是否圆形裁剪
.showCropFrame(false)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false
.showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false
.openClickSound(false)// 是否开启点击声音
.minimumCompressSize(100)// 小于100kb的图片不压缩
.forResult(PictureConfig.CHOOSE_REQUEST)//结果回调onActivityResult code
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
try {
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
PictureConfig.CHOOSE_REQUEST -> {
// 图片选择结果回调
val selectPictureList = PictureSelector.obtainMultipleResult(data) as ArrayList<LocalMedia>
selectList.addAll(selectPictureList)
mImageAdapter?.setList(selectList)
mImageAdapter?.setSelectMax(4)
mImageAdapter?.notifyDataSetChanged()
var headerUrl = ""
if (selectList.size <= 4) {
mMaxSelectedNum = 4 - selectList.size
mCurrentSelectedNum = selectList.size
for (index in 0 until selectList.size) {
val media = selectPictureList[index]
val compressPath = media.compressPath
val uuid = TokenManager.getInstance().uuid
val time = System.currentTimeMillis()
val key: String
key = if (ObjectUtils.isNotEmpty(uuid)) {
"avatar/" + uuid + "_" + time.toString() + index
} else {
"avatar/$time$index"
}
QiNiuUploader.newInstance().uploadPhoto(compressPath, key, object : UploadChangeListener {
override fun complete(key: String, status: Boolean, info: String) {
headerUrl = ConstantConfig.QINIU_HOST + key
mPictureList.add("\"" + headerUrl + "\"")
LogUtils.e(">>>>>>>>>>>>>>>>>", "图片上传七牛成功headerUrl:$headerUrl")
}
override fun progress(key: String, percent: Double) {
}
})
}
}
}
}
}
} catch (e: Exception) {
LogUtils.e(">>>>>>>>>>>>>>", "选择相册图片报错:$e")
}
}
}
这里最重要的需要注意我们的布局设置了,因为如果我们设置RecyclerView的高度成固定高度的话,那么我们图片Item的拖拽距离就固定在RecyclerView区域,无法实现功能上的拖拽到底部布局,这样就是不符合功能需求的。那我们该怎么解决呢?
其实我们会发现其实解决办法就是使用FrameLayout设置外层布局,然后让RecyclerView填充整个父窗体,背景设置成透明,然后在设置布局的其他元素,当然如果控件有点击事件,则需要设置在上层。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/title_layout"
layout="@layout/title_view"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/dp_1"
android:background="@color/color_f4"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title_layout"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<android.support.constraint.ConstraintLayout
android:id="@+id/cl_delete_pic_layout"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_61"
android:background="#E95454"
android:layout_gravity="bottom"
android:visibility="invisible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<android.support.v7.widget.AppCompatImageView
android:layout_width="@dimen/dp_17"
android:layout_height="@dimen/dp_16"
android:src="@drawable/ic_white_crash_bucket"
android:layout_marginTop="@dimen/dp_10"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<android.support.v7.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_35"
android:text="拖动到此处删除"
android:textColor="@color/white"
android:textSize="@dimen/dp_12"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
</android.support.constraint.ConstraintLayout>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/dp_1"
android:background="@color/color_f4"
android:layout_marginLeft="@dimen/dp_24"
android:layout_marginRight="@dimen/dp_28"
android:layout_marginTop="@dimen/dp_49"/>
<android.support.v7.widget.AppCompatTextView
android:id="@+id/tv_create_write_tips"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="提示:请上传回答课后问题的图片,并确保图片清晰、
字迹易辨认,老师点评后会消息及时通知,请留意微信消息。"
android:textColor="#ffa3a3a3"
android:textSize="@dimen/dp_13"
android:layout_marginLeft="@dimen/dp_24"
android:layout_marginRight="@dimen/dp_24"
android:layout_marginTop="@dimen/dp_49"
android:layout_gravity="bottom"
android:layout_marginBottom="@dimen/dp_180" />
<android.support.v7.widget.RecyclerView
android:id="@+id/gl_picture_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/dp_33"
android:paddingRight="@dimen/dp_38"
android:layout_marginTop="@dimen/dp_19"
android:background="@color/trans"
/>
<RelativeLayout
android:id="@+id/rl_post_write_pitures"
android:layout_width="@dimen/dp_80"
android:layout_height="@dimen/dp_70"
android:layout_gravity="bottom|right"
android:layout_marginBottom="@dimen/dp_100"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_create_write_tips">
<android.support.v7.widget.AppCompatTextView
android:layout_width="@dimen/dp_52"
android:layout_height="@dimen/dp_29"
android:text="发表"
android:textColor="@color/white"
android:textSize="@dimen/dp_15"
android:gravity="center"
android:layout_alignParentRight="true"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginRight="@dimen/dp_19"
android:background="@drawable/bg_green_9c_solid_r0"
/>
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_layout_paying"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
android:orientation="vertical">
<ProgressBar
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/bg_loading_progress"
android:indeterminateBehavior="repeat"/>
<android.support.v7.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_5"
android:textSize="@dimen/sp_17"
android:textColor="@color/black"
android:layout_gravity="center"
android:text="正在上传..."/>
</LinearLayout>
</FrameLayout>
</LinearLayout>
这样我们的功能就可以实现了,但是也存在一些小问题,不如拖拽的界面可能会显示在底层,上层被有点击事件的其他控件遮挡,还有就是RecyclerView的边距无法拖拽显示出来。
解决办法就是动态代码设置一显示控件的位置。
下面就是开源项目的传送门链接: DragGridView-master