在日常的开发中,大家很熟悉并常见的一种侧滑删除大概就是listview的侧滑删除了,对于listview的侧滑删除很好实现,但是如果是一个linearlayout的布局呢?在最近的项目中就遇到了这样的问题,整体的页面并不是一个列表只有一条数据,那样我们就不必再用listview了,为了节约内存资源,相信很多小伙们很少遇到这样的问题,所以准备撸一波代码,分享一下。
首先感谢Android-->实现可滑动删除的Layout 这篇博客,很多东西都是在这篇博客的基础上改善的
Android有比较成熟的开源项项目SwipeListview来实现列表的滑动删除功能
接着来看看SwipeLayout的具体用法。
1.SwipeLayout所需布局container_swipelayout.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/hh_fi_wr"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/view_content"
style="@style/hh_fi_wr"
android:orientation="horizontal" >
</LinearLayout>
<RelativeLayout
android:id="@+id/view_right"
android:layout_width="80dp"
android:layout_height="match_parent"
android:clickable="true" >
</RelativeLayout>
</merge>
主要的思想就是把SwipeLayout的布局分为两个部分,view_content用于加载正常的内容区域有,view_right用于加载右边侧滑的布局。其他的布局也还是类似的想法
下面我们来看SwipeLayout的代码实现,逻辑也不复杂
package com.huahansoft.medicaldoctor.view.SwipeLayout;
import android.content.Context;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Scroller;
import com.huahansoft.medicaldoctor.R;
/**
*
* 类描述:
* 类传参:
* Creat byLyb on 2018/5/29 11:16
*/
public class SwipeLayout extends LinearLayout {
private static final String TAG = "SwipeLayout";
private Context mContext;
private LinearLayout mContentView;
private RelativeLayout mRightView;
private Scroller mScroller;
private OnSlideListener mOnSlideListener;
private int mHolderWidth = 80;//此处是右边布局的宽度
private int mLastX = 0;
private int mLastY = 0;
private static final int TAN = 2;
private int mSlideState = 0;
public interface OnSlideListener {
int SLIDE_STATUS_OFF = 0;
int SLIDE_STATUS_START_SCROLL = 1;
int SLIDE_STATUS_ON = 2;
void onSlide(View view, int status);
}
public SwipeLayout(Context context) {
super(context);
initView();
}
public SwipeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
private void initView() {
mContext = getContext();
mScroller = new Scroller(mContext);
setOrientation(LinearLayout.HORIZONTAL);
View.inflate(mContext, R.layout.container_swipelayout, this);
mContentView = (LinearLayout) findViewById(R.id.view_content);
mRightView = (RelativeLayout)findViewById(R.id.view_right);
mHolderWidth = Math.round(TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, mHolderWidth, getResources()
.getDisplayMetrics()));
}
//将View加入到mContentView中
public void setContentView(View view) {
mContentView.addView(view);
}
//将View加入到mRightView中
public void setRightView(View v) {
mRightView.addView(v);
}
public void setOnSlideListener(OnSlideListener onSlideListener) {
mOnSlideListener = onSlideListener;
}
//将当前状态设置为关闭
public void shrink() {
if (getScrollX() != 0) {
this.smoothScrollTo(0, 0);
}
}
//如果其子View存在消耗点击事件的View,那么SwipeLayout的onTouchEvent不会被执行,
// 因为在ACTION_MOVE的时候返回true,执行其onTouchEvent方法
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
if (mOnSlideListener != null) {
mOnSlideListener.onSlide(this,
OnSlideListener.SLIDE_STATUS_START_SCROLL);
mSlideState = OnSlideListener.SLIDE_STATUS_START_SCROLL;
}
//这里需要记录mLastX,mLastY的值,不然当SwipeLayout已经处于开启状态时,
// 用于再次滑动SwipeLayout时,会先立即复原到关闭状态,用户体验不太好
mLastX = (int)ev.getX();
mLastY = (int)ev.getY();
return false;
case MotionEvent.ACTION_MOVE:
//返回值为true表示本次触摸事件由自己执行,即执行SwipeLayout的onTouchEvent方法
int deltaX = x - mLastX;
int deltaY = y - mLastY;
//这里作用是来比较X、Y轴的滑动距离,如果X轴的滑动距离小于两倍的Y轴滑动距离,则不执行SwipeLayout的滑动事件
if (Math.abs(deltaX) < Math.abs(deltaY) * TAN) {
return false;
}
//如果返回true,则子控件的事件几乎不会被触发
return false;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
int scrollX = getScrollX();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastX;
//如果SwipeLayout是在譬如ScrollView、ListView这种可以上下滑动的View中
//那么当用户的手指滑出SwipeLayout的边界,那么将会触发器ACTION_CANCEL事件
//如果此情形发生,那么SwipeLayout将会处于停止状态,无法复原。
//增加下面这句代码,就是告诉父控件,不要cancel我的事件,我的事件我继续处理。
getParent().requestDisallowInterceptTouchEvent(true);
int newScrollX = scrollX - deltaX;
if (deltaX != 0) {
if (newScrollX < 0) {
//最小的滑动距离为0
newScrollX = 0;
} else if (newScrollX > mHolderWidth) {
//最大的滑动距离就是mRightView的宽度
newScrollX = mHolderWidth;
}
this.scrollTo(newScrollX, 0);
}
break;
}
case MotionEvent.ACTION_UP: {
int newScrollX = 0;
//如果已滑动的距离满足下面条件,则SwipeLayout直接滑动到最大距离,不然滑动到最小距离0
if (scrollX - mHolderWidth * 0.75 > 0) {
newScrollX = mHolderWidth;
}
this.smoothScrollTo(newScrollX, 0);
if (mOnSlideListener != null) {
if (newScrollX == 0){
mOnSlideListener.onSlide(this, OnSlideListener.SLIDE_STATUS_OFF);
mSlideState = OnSlideListener.SLIDE_STATUS_OFF;
}
else {
mOnSlideListener.onSlide(this, OnSlideListener.SLIDE_STATUS_ON);
mSlideState = OnSlideListener.SLIDE_STATUS_ON;
}
}
getParent().requestDisallowInterceptTouchEvent(false);
}
default:
break;
}
mLastX = x;
mLastY = y;
return true;
}
//获取当前SwipeLayout的滑动状态
public int getSideState(){
return mSlideState;
}
private void smoothScrollTo(int destX, int destY) {
// 缓慢滚动到指定位置
int scrollX = getScrollX();
int delta = destX - scrollX;
mScroller.startScroll(scrollX, 0, delta, 0, Math.abs(delta) * 3);
invalidate();
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
}
一切准备就绪,最后来看看具体怎么用SwipeLayout
在布局中直接引用这个SwipeLayout,然后在主函数中
View contentView = LayoutInflater.from(this).inflate(R.layout.view_outpatient_stop_show, null);
showContentTextView = (TextView) contentView.findViewById(R.id.tv_tip_content);
showTimeTextView = (TextView) contentView.findViewById(R.id.tv_tip_time);
View right = LayoutInflater.from(this).inflate(R.layout.right_swipe, null);
deleteTextView = (TextView) right.findViewById(R.id.tv_right_dele);
swipeLayout.setContentView(contentView);
swipeLayout.setRightView(right);
好啦!一个完美的侧滑删除就实现了....