├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── ssyijiu │ │ └── swipelayout │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── ssyijiu │ │ │ └── swipelayout │ │ │ ├── MainActivity.java │ │ │ ├── SwipeLayout.java │ │ │ ├── SwipeLayoutManager.java │ │ │ └── baseadapter │ │ │ ├── CommonAdapter.java │ │ │ └── ViewHolder.java │ └── res │ │ ├── drawable-xhdpi │ │ └── head_1.png │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── item_listview.xml │ │ ├── layout_content.xml │ │ └── layout_delete.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── ssyijiu │ └── swipelayout │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── show.gif /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | SwipeLayout -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @Deprecated 2 | 年久失修,请使用:https://github.com/mcxtzhang/SwipeDelMenuLayout 3 | # SwipeLayout 4 | 侧滑删除,适用于任何 View。 5 | 6 | > Github 上有一个非常著名的侧滑删除 [daimajia/AndroidSwipeLayout](https://github.com/daimajia/AndroidSwipeLayout),但是我在使用的时候发现了一些 BUG。 7 | > 其他的侧滑删除大都又是与 ListView、RecyclerView 耦合在一起,不适用于目前的项目,于是有了这个小巧简洁的 SwipeLayout。 8 | 9 | ## 项目原理 10 | 使用 ViewDragHelper 和 ViewDragHelper.Callback 完成一系列的侧滑动作。 11 | 12 | ## 效果展示 13 | 14 | ![](./show.gif) 15 | ## 使用说明 16 | 17 | ### 布局 18 | 布局分内容区域和删除区域,内容区域为正常展示数据的区域,删除区域是侧滑出来的区域。 19 | ```html 20 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ``` 33 | 34 | ### 代码 35 | 36 | ``` 37 | // 在进入 Activity 或者 Fragmen t时候初始化 SwipeLayout 38 | SwipeLayoutManager.getInstance().closeOpenInstance(); 39 | 40 | // 设置点击事件 41 | swipelayou.setOnSwipeLayoutClickListener(new SwipeLayout.OnSwipeLayoutClickListener() { 42 | @Override 43 | public void onClick() { 44 | Toast.makeText(MainActivity.this, "BUTTON", Toast.LENGTH_SHORT).show(); 45 | } 46 | }); 47 | 48 | // 获取内容区域并设置点击事件 49 | swipelayou.getContentView().setOnClickListener(new View.OnClickListener() { 50 | @Override 51 | public void onClick(View v) { 52 | Toast.makeText(MainActivity.this, "BUTTON", Toast.LENGTH_SHORT).show(); 53 | } 54 | }); 55 | 56 | // 获取删除区域并设置点击事件(因为这里删除区域是LinearLayout,包括一个callView和deleteView,需要自己获取子View来设置点击事件) 57 | ((LinearLayout)swipelayou.getDeleteView()).getChildAt(1).setOnClickListener(new View.OnClickListener() { 58 | @Override 59 | public void onClick(View v) { 60 | Toast.makeText(MainActivity.this, "DELETE", Toast.LENGTH_SHORT).show(); 61 | } 62 | }); 63 | 64 | // ListView侧滑打开的时候,通过监听滑动来关闭打开的侧滑。 65 | // 这里没有想到其他的办法,如果您有思路,希望告知我。 66 | listview.setOnScrollListener(new AbsListView.OnScrollListener() { 67 | @Override 68 | public void onScrollStateChanged(AbsListView view, int scrollState) { 69 | if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 70 | // 如果listView跟随手机拖动,关闭已经打开的SwipeLayout 71 | SwipeLayoutManager.getInstance().closeOpenInstance(); 72 | } 73 | } 74 | 75 | @Override 76 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 77 | } 78 | }); 79 | ``` 80 | ## 联系作者 81 | - Github: [ssyijiu](https://github.com/ssyijiu) 82 | - E-mail: lxmyijiu@163.com 83 | - WeChat: ssyijiu11 84 | 85 | ## License 86 | 87 | ``` 88 | Copyright 2016 ssyijiu 89 | 90 | Licensed under the Apache License, Version 2.0 (the "License"); 91 | you may not use this file except in compliance with the License. 92 | You may obtain a copy of the License at 93 | 94 | http://www.apache.org/licenses/LICENSE-2.0 95 | 96 | Unless required by applicable law or agreed to in writing, software 97 | distributed under the License is distributed on an "AS IS" BASIS, 98 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 99 | See the License for the specific language governing permissions and 100 | limitations under the License. 101 | ``` 102 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.ssyijiu.swipelayout" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.2.0' 26 | } 27 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in E:\eclipse-adt\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/ssyijiu/swipelayout/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.ssyijiu.swipelayout; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/ssyijiu/swipelayout/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.ssyijiu.swipelayout; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | import android.widget.AbsListView; 8 | import android.widget.Button; 9 | import android.widget.LinearLayout; 10 | import android.widget.ListView; 11 | import android.widget.Toast; 12 | 13 | import com.ssyijiu.swipelayout.baseadapter.CommonAdapter; 14 | import com.ssyijiu.swipelayout.baseadapter.ViewHolder; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | 20 | public class MainActivity extends AppCompatActivity { 21 | 22 | 23 | SwipeLayout swipelayout_button; 24 | ListView listview; 25 | private Adapter adapter; 26 | 27 | private ArrayList datas = new ArrayList<>(); 28 | 29 | 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_main); 35 | 36 | initView(); 37 | 38 | //-------------------Button----------------------- 39 | swipelayout_button.setOnSwipeLayoutClickListener(new SwipeLayout.OnSwipeLayoutClickListener() { 40 | @Override 41 | public void onClick() { 42 | Toast.makeText(MainActivity.this, "BUTTON", Toast.LENGTH_SHORT).show(); 43 | } 44 | }); 45 | 46 | swipelayout_button.getContentView().setOnClickListener(new View.OnClickListener() { 47 | @Override 48 | public void onClick(View v) { 49 | Toast.makeText(MainActivity.this, "BUTTON", Toast.LENGTH_SHORT).show(); 50 | } 51 | }); 52 | 53 | ((LinearLayout)swipelayout_button.getDeleteView()).getChildAt(1).setOnClickListener(new View.OnClickListener() { 54 | @Override 55 | public void onClick(View v) { 56 | Toast.makeText(MainActivity.this, "DELETE", Toast.LENGTH_SHORT).show(); 57 | } 58 | }); 59 | 60 | 61 | 62 | //-------------------ListView---------------------- 63 | initData(); 64 | adapter = new Adapter(this,datas,R.layout.item_listview); 65 | listview.setAdapter(adapter); 66 | 67 | 68 | // 侧滑打来的时候滑动没有想到什么好的办法解决,只能这样了。 69 | listview.setOnScrollListener(new AbsListView.OnScrollListener() { 70 | @Override 71 | public void onScrollStateChanged(AbsListView view, int scrollState) { 72 | if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 73 | // 如果listView跟随手机拖动,关闭已经打开的SwipeLayout 74 | SwipeLayoutManager.getInstance().closeOpenInstance(); 75 | } 76 | } 77 | 78 | @Override 79 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 80 | } 81 | }); 82 | 83 | 84 | 85 | } 86 | 87 | private void initView() { 88 | listview = (ListView) findViewById(R.id.listview); 89 | swipelayout_button = (SwipeLayout) findViewById(R.id.swipelayout_button); 90 | // 初始化SwipeLayout 91 | SwipeLayoutManager.getInstance().closeOpenInstance(); 92 | } 93 | 94 | 95 | class Adapter extends CommonAdapter { 96 | 97 | public Adapter(Context context, List datas, int layoutId) { 98 | super(context, datas, layoutId); 99 | } 100 | 101 | @Override 102 | public void convert(ViewHolder holder, final String s) { 103 | holder.setText(R.id.tv_name,s); 104 | 105 | final SwipeLayout swipeLayout = holder.getView(R.id.swipelayout); 106 | 107 | swipeLayout.setOnSwipeLayoutClickListener(new SwipeLayout.OnSwipeLayoutClickListener() { 108 | @Override 109 | public void onClick() { 110 | Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show(); 111 | } 112 | }); 113 | 114 | ((LinearLayout)swipeLayout.getDeleteView()).getChildAt(0).setOnClickListener(new View.OnClickListener() { 115 | @Override 116 | public void onClick(View v) { 117 | Toast.makeText(MainActivity.this, "call", Toast.LENGTH_SHORT).show(); 118 | } 119 | }); 120 | 121 | 122 | 123 | ((LinearLayout)swipeLayout.getDeleteView()).getChildAt(1).setOnClickListener(new View.OnClickListener() { 124 | @Override 125 | public void onClick(View v) { 126 | SwipeLayoutManager.getInstance().closeOpenInstance(); 127 | datas.remove(s); 128 | adapter.notifyDataSetChanged(); 129 | Toast.makeText(mContext, "datas.size():" + datas.size(), Toast.LENGTH_SHORT).show(); 130 | } 131 | }); 132 | 133 | } 134 | } 135 | 136 | 137 | 138 | private void initData() { 139 | for (int i=0;i<20;i++) { 140 | datas.add(i + "壶浊酒喜相逢"); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /app/src/main/java/com/ssyijiu/swipelayout/SwipeLayout.java: -------------------------------------------------------------------------------- 1 | package com.ssyijiu.swipelayout; 2 | 3 | import android.content.Context; 4 | import android.graphics.PointF; 5 | import android.support.v4.view.ViewCompat; 6 | import android.support.v4.widget.ViewDragHelper; 7 | import android.util.AttributeSet; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.view.ViewConfiguration; 11 | import android.widget.FrameLayout; 12 | 13 | /** 14 | * Created by ssyijiu on 2016/8/16. 15 | * Github: ssyijiu 16 | * E-mail: lxmyijiu@163.com 17 | */ 18 | public class SwipeLayout extends FrameLayout { 19 | 20 | private View contentView; 21 | private View deleteView; 22 | private int contentWidth; 23 | private int deleteWidth; 24 | private ViewDragHelper dragHelper; 25 | private int dragWidth; 26 | 27 | private int STATE_OPEN = 0; 28 | private int STATE_CLOSE = 1; 29 | private int mState = STATE_CLOSE; 30 | float touchSlop; 31 | 32 | public SwipeLayout(Context context, AttributeSet attrs) { 33 | super(context, attrs); 34 | init(); 35 | } 36 | 37 | 38 | private void init() { 39 | 40 | dragHelper = ViewDragHelper.create(this,callback); 41 | // 获取系统认为的滑动的临界值 42 | touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); 43 | } 44 | 45 | /** 将拦截事件交给ViewDragHelper处理 */ 46 | @Override 47 | public boolean onInterceptTouchEvent(MotionEvent ev) { 48 | // 这里只是为了保证onTouchEvent可以执行 49 | if(!SwipeLayoutManager.getInstance().isCouldSwipe(SwipeLayout.this)) { 50 | return true; 51 | } 52 | return dragHelper.shouldInterceptTouchEvent(ev); 53 | } 54 | 55 | 56 | float downX, downY; 57 | long downTime; 58 | /** 将触摸事件交给ViewDragHelper处理 */ 59 | @Override 60 | public boolean onTouchEvent(MotionEvent event) { 61 | // SwipeLayout不可以侧滑时,关闭已经打开的SwipeLayout 62 | if(!SwipeLayoutManager.getInstance().isCouldSwipe(SwipeLayout.this)) { 63 | SwipeLayoutManager.getInstance().closeOpenInstance(); 64 | return false; // 这里返回true崩溃什么鬼 。 65 | } 66 | 67 | switch (event.getAction()) { 68 | 69 | case MotionEvent.ACTION_DOWN: 70 | downX = event.getX(); 71 | downY = event.getY(); 72 | // 记录按下的时间 73 | downTime = System.currentTimeMillis(); 74 | break; 75 | case MotionEvent.ACTION_MOVE: 76 | 77 | float moveX = event.getX(); 78 | float moveY = event.getY(); 79 | 80 | // 水平滑动,不让listView拦截事件 81 | if(Math.abs(moveY-downY) < Math.abs(moveX-downX)) { 82 | // 请求父View不拦截事件 83 | requestDisallowInterceptTouchEvent(true); 84 | } 85 | 86 | break; 87 | case MotionEvent.ACTION_UP: 88 | // 记录抬起的时间点 89 | long upTime = System.currentTimeMillis(); 90 | // 计算抬起的坐标 91 | float upX = event.getX(); 92 | float upY = event.getY(); 93 | // 计算按下和抬起的时间差 94 | long touchDuration = upTime-downTime; 95 | // 计算按下点和抬起点的距离 96 | float touchD = getDistanceBetween2Points(new PointF(downX, downY), new PointF(upX, upY)); 97 | 98 | // 模拟点击事件 99 | if(touchDuration < 400 && touchD < touchSlop){ 100 | // 打开状态则关闭,否则执行点击事件 101 | if(SwipeLayoutManager.getInstance().isOpenInstance(SwipeLayout.this)) { 102 | SwipeLayoutManager.getInstance().closeOpenInstance(); 103 | } else { 104 | if(listener!=null){ 105 | listener.onClick(); 106 | } 107 | } 108 | 109 | } 110 | break; 111 | } 112 | 113 | dragHelper.processTouchEvent(event); 114 | return true; 115 | } 116 | 117 | ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { 118 | 119 | /** 确定需要触摸的View */ 120 | @Override 121 | public boolean tryCaptureView(View child, int pointerId) { 122 | //Toast.makeText(getContext(), "事件捕获", Toast.LENGTH_SHORT).show(); 123 | return child == contentView || child == deleteView; 124 | } 125 | 126 | /** View在水平方向的拖拽范围,不要返回0 */ 127 | @Override 128 | public int getViewHorizontalDragRange(View child) { 129 | return dragWidth; 130 | } 131 | 132 | /** 133 | * 控制子View在水平方向移动 134 | * @param child 拖拽的View 135 | * @param left 手指滑动之后子ViewDragHelper认为的View的left 136 | * @param dx 手指在水平方向移动的距离 137 | * @return 子View最终的left 138 | */ 139 | @Override 140 | public int clampViewPositionHorizontal(View child, int left, int dx) { 141 | if(child == contentView) { 142 | left = left > 0 ? 0 : left; 143 | left = left < -dragWidth ? -dragWidth : left; 144 | } else if(child == deleteView) { 145 | left = left > contentWidth ? contentWidth : left; 146 | left = left < contentWidth - deleteWidth ? contentWidth - deleteWidth 147 | : left; 148 | } 149 | return left; 150 | } 151 | 152 | /** 153 | * View位置改变时调用,一般用来做伴随移动和判断状态执行相应的操作 154 | * @param changedView 155 | * @param left View当前的left 156 | * @param top View当前的top 157 | * @param dx View的水平移动距离 158 | * @param dy View的竖直移动距离 159 | */ 160 | @Override 161 | public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { 162 | if(changedView == contentView) { 163 | 164 | int newLeft = deleteView.getLeft() + dx; 165 | deleteView.layout(newLeft,getTop(), newLeft+deleteWidth,getBottom()); 166 | 167 | } else if(changedView == deleteView) { 168 | contentView.layout(left - contentWidth,contentView.getTop(), 169 | left, contentView.getBottom()); 170 | } 171 | 172 | // 处理打开与关闭的逻辑 173 | if(contentView.getLeft() == -deleteWidth && mState == STATE_CLOSE) { 174 | mState = STATE_OPEN; 175 | 176 | // 记录打开的SwipeLayout 177 | SwipeLayoutManager.getInstance().setOpenInstance(SwipeLayout.this); 178 | 179 | } else if(contentView.getLeft() == 0 && mState == STATE_OPEN) { 180 | mState = STATE_CLOSE; 181 | SwipeLayoutManager.getInstance().closeOpenInstance(); 182 | } 183 | } 184 | 185 | /** 手指抬起的时候执行 */ 186 | @Override 187 | public void onViewReleased(View releasedChild, float xvel, float yvel) { 188 | 189 | int width = contentWidth - dragWidth/2; 190 | if(contentView.getRight() < width) { 191 | openDeleteMenu(); 192 | } else { 193 | closeDeleteMenu(); 194 | } 195 | } 196 | }; 197 | 198 | public void closeDeleteMenu() { 199 | dragHelper.smoothSlideViewTo(contentView,0,contentView.getTop()); 200 | ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); 201 | } 202 | 203 | public void openDeleteMenu() { 204 | dragHelper.smoothSlideViewTo(contentView,-dragWidth,contentView.getTop()); 205 | ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); 206 | } 207 | 208 | @Override 209 | public void computeScroll() { 210 | if(dragHelper.continueSettling(true)) { 211 | ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); 212 | } 213 | } 214 | 215 | /** 对contentView和deleteView重新排版 */ 216 | @Override 217 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 218 | contentView.layout(left, top, right, bottom); 219 | deleteView.layout(right, top, right + deleteWidth, bottom); 220 | } 221 | 222 | /** 获取contentView和deleteView */ 223 | @Override 224 | protected void onFinishInflate() { 225 | super.onFinishInflate(); 226 | // 做简单的异常处理 227 | if(getChildCount() != 2) { 228 | throw new IllegalArgumentException("the swipelayout only have 2 children!"); 229 | } 230 | contentView = getChildAt(0); 231 | deleteView = getChildAt(1); 232 | } 233 | 234 | /** 获取contentView和deleteView的测量大小 */ 235 | @Override 236 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 237 | contentWidth = contentView.getMeasuredWidth(); 238 | deleteWidth = deleteView.getMeasuredWidth(); 239 | 240 | dragWidth = deleteWidth; 241 | } 242 | 243 | /** 获取删除区域 */ 244 | public View getDeleteView() { 245 | return deleteView; 246 | } 247 | 248 | /** 获取内容区域 */ 249 | public View getContentView() { 250 | return contentView; 251 | } 252 | 253 | 254 | private OnSwipeLayoutClickListener listener; 255 | public void setOnSwipeLayoutClickListener(OnSwipeLayoutClickListener listener){ 256 | this.listener = listener; 257 | } 258 | 259 | /** 点击事件回调接口 */ 260 | public interface OnSwipeLayoutClickListener{ 261 | void onClick(); 262 | } 263 | 264 | /** 265 | * 获得两点之间的距离 266 | * @param p0 267 | * @param p1 268 | * @return 269 | */ 270 | public static float getDistanceBetween2Points(PointF p0, PointF p1) { 271 | return (float) Math.sqrt(Math.pow(p0.y - p1.y, 2) + Math.pow(p0.x - p1.x, 2)); 272 | } 273 | } 274 | 275 | 276 | -------------------------------------------------------------------------------- /app/src/main/java/com/ssyijiu/swipelayout/SwipeLayoutManager.java: -------------------------------------------------------------------------------- 1 | package com.ssyijiu.swipelayout; 2 | 3 | /** 4 | * 使用单例模式来管理listView条目的打开与关闭 5 | * Created by ssyijiu on 2016/8/16. 6 | * Github: ssyijiu 7 | * E-mail: lxmyijiu@163.com 8 | */ 9 | public class SwipeLayoutManager { 10 | 11 | private SwipeLayoutManager(){} 12 | 13 | // 静态内部类模式单例 14 | private static class LazyHolder { 15 | private static final SwipeLayoutManager INSTANCE = new SwipeLayoutManager(); 16 | } 17 | 18 | public static SwipeLayoutManager getInstance() { 19 | return LazyHolder.INSTANCE; 20 | } 21 | 22 | /** 记录当前打开的SwipeLayout */ 23 | private SwipeLayout openInstance; 24 | 25 | /** 设置当前打开的SwipeLayout */ 26 | public void setOpenInstance(SwipeLayout swipeLayout) { 27 | openInstance = swipeLayout; 28 | } 29 | 30 | /** 31 | * 判断一个条目能否侧滑 32 | */ 33 | public boolean isCouldSwipe(SwipeLayout swipeLayout) { 34 | 35 | // 已经打开。可以侧滑 36 | if(isOpenInstance(swipeLayout)) { 37 | return true; 38 | } 39 | 40 | // 都没有打开也可以侧滑 41 | return openInstance == null; 42 | } 43 | 44 | /** 45 | * 判断是不是打开的条目 46 | */ 47 | public boolean isOpenInstance(SwipeLayout swipeLayout) { 48 | 49 | return swipeLayout == openInstance; 50 | } 51 | 52 | /** 关闭打开的条目 */ 53 | public void closeOpenInstance() { 54 | if(openInstance != null) { 55 | openInstance.closeDeleteMenu(); 56 | openInstance = null; 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/ssyijiu/swipelayout/baseadapter/CommonAdapter.java: -------------------------------------------------------------------------------- 1 | package com.ssyijiu.swipelayout.baseadapter; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | 9 | import java.util.List; 10 | 11 | public abstract class CommonAdapter extends BaseAdapter { 12 | protected Context mContext; 13 | protected List mDatas; 14 | protected LayoutInflater mInflater; 15 | private int layoutId; 16 | 17 | public CommonAdapter(Context context, List datas, int layoutId) { 18 | this.mContext = context; 19 | mInflater = LayoutInflater.from(context); 20 | this.mDatas = datas; 21 | this.layoutId = layoutId; 22 | } 23 | 24 | @Override 25 | public int getCount() { 26 | return mDatas.size(); 27 | } 28 | 29 | @Override 30 | public T getItem(int position) { 31 | return mDatas.get(position); 32 | } 33 | 34 | @Override 35 | public long getItemId(int position) { 36 | return position; 37 | } 38 | 39 | @Override 40 | public View getView(int position, View convertView, ViewGroup parent) { 41 | ViewHolder holder = ViewHolder.get(mContext, convertView, parent, 42 | layoutId, position); 43 | convert(holder, getItem(position)); 44 | return holder.getConvertView(); 45 | } 46 | 47 | public abstract void convert(ViewHolder holder, T t); 48 | 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/ssyijiu/swipelayout/baseadapter/ViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.ssyijiu.swipelayout.baseadapter; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Paint; 7 | import android.graphics.Typeface; 8 | import android.graphics.drawable.Drawable; 9 | import android.os.Build; 10 | import android.text.util.Linkify; 11 | import android.util.SparseArray; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.view.animation.AlphaAnimation; 16 | import android.widget.Checkable; 17 | import android.widget.ImageView; 18 | import android.widget.ProgressBar; 19 | import android.widget.RatingBar; 20 | import android.widget.TextView; 21 | 22 | public class ViewHolder { 23 | private SparseArray mViews; 24 | private int mPosition; 25 | private View mConvertView; 26 | private Context mContext; 27 | private int mLayoutId; 28 | 29 | public ViewHolder(Context context, ViewGroup parent, int layoutId, 30 | int position) { 31 | mContext = context; 32 | mLayoutId = layoutId; 33 | this.mPosition = position; 34 | this.mViews = new SparseArray(); 35 | mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, 36 | false); 37 | mConvertView.setTag(this); 38 | } 39 | 40 | public static ViewHolder get(Context context, View convertView, 41 | ViewGroup parent, int layoutId, int position) { 42 | if (convertView == null) 43 | { 44 | return new ViewHolder(context, parent, layoutId, position); 45 | } else 46 | { 47 | ViewHolder holder = (ViewHolder) convertView.getTag(); 48 | holder.mPosition = position; 49 | return holder; 50 | } 51 | } 52 | 53 | public int getPosition() { 54 | return mPosition; 55 | } 56 | 57 | public int getLayoutId(){ 58 | return mLayoutId; 59 | } 60 | 61 | /** 62 | * 通过viewId获取控件 63 | * 64 | * @param viewId 65 | * @return 66 | */ 67 | public T getView(int viewId) { 68 | View view = mViews.get(viewId); 69 | if (view == null) 70 | { 71 | view = mConvertView.findViewById(viewId); 72 | mViews.put(viewId, view); 73 | } 74 | return (T) view; 75 | } 76 | 77 | public View getConvertView() 78 | { 79 | return mConvertView; 80 | } 81 | 82 | /** 83 | * 设置TextView的值 84 | * 85 | * @param viewId 86 | * @param text 87 | * @return 88 | */ 89 | public ViewHolder setText(int viewId, String text) { 90 | TextView tv = getView(viewId); 91 | tv.setText(text); 92 | return this; 93 | } 94 | 95 | public ViewHolder setImageResource(int viewId, int resId) { 96 | ImageView view = getView(viewId); 97 | view.setImageResource(resId); 98 | return this; 99 | } 100 | 101 | public ViewHolder setImageBitmap(int viewId, Bitmap bitmap) { 102 | ImageView view = getView(viewId); 103 | view.setImageBitmap(bitmap); 104 | return this; 105 | } 106 | 107 | public ViewHolder setImageDrawable(int viewId, Drawable drawable) { 108 | ImageView view = getView(viewId); 109 | view.setImageDrawable(drawable); 110 | return this; 111 | } 112 | 113 | public ViewHolder setBackgroundColor(int viewId, int color) { 114 | View view = getView(viewId); 115 | view.setBackgroundColor(color); 116 | return this; 117 | } 118 | 119 | public ViewHolder setBackgroundRes(int viewId, int backgroundRes) { 120 | View view = getView(viewId); 121 | view.setBackgroundResource(backgroundRes); 122 | return this; 123 | } 124 | 125 | public ViewHolder setTextColor(int viewId, int textColor) { 126 | TextView view = getView(viewId); 127 | view.setTextColor(textColor); 128 | return this; 129 | } 130 | 131 | public ViewHolder setTextColorRes(int viewId, int textColorRes) { 132 | TextView view = getView(viewId); 133 | view.setTextColor(mContext.getResources().getColor(textColorRes)); 134 | return this; 135 | } 136 | 137 | @SuppressLint("NewApi") 138 | public ViewHolder setAlpha(int viewId, float value) { 139 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 140 | getView(viewId).setAlpha(value); 141 | } else { 142 | // Pre-honeycomb hack to set Alpha value 143 | AlphaAnimation alpha = new AlphaAnimation(value, value); 144 | alpha.setDuration(0); 145 | alpha.setFillAfter(true); 146 | getView(viewId).startAnimation(alpha); 147 | } 148 | return this; 149 | } 150 | 151 | public ViewHolder setVisible(int viewId, boolean visible) { 152 | View view = getView(viewId); 153 | view.setVisibility(visible ? View.VISIBLE : View.GONE); 154 | return this; 155 | } 156 | 157 | public ViewHolder linkify(int viewId) { 158 | TextView view = getView(viewId); 159 | Linkify.addLinks(view, Linkify.ALL); 160 | return this; 161 | } 162 | 163 | public ViewHolder setTypeface(Typeface typeface, int... viewIds) { 164 | for (int viewId : viewIds) { 165 | TextView view = getView(viewId); 166 | view.setTypeface(typeface); 167 | view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); 168 | } 169 | return this; 170 | } 171 | 172 | public ViewHolder setProgress(int viewId, int progress) { 173 | ProgressBar view = getView(viewId); 174 | view.setProgress(progress); 175 | return this; 176 | } 177 | 178 | public ViewHolder setProgress(int viewId, int progress, int max) { 179 | ProgressBar view = getView(viewId); 180 | view.setMax(max); 181 | view.setProgress(progress); 182 | return this; 183 | } 184 | 185 | public ViewHolder setMax(int viewId, int max) { 186 | ProgressBar view = getView(viewId); 187 | view.setMax(max); 188 | return this; 189 | } 190 | 191 | public ViewHolder setRating(int viewId, float rating) { 192 | RatingBar view = getView(viewId); 193 | view.setRating(rating); 194 | return this; 195 | } 196 | 197 | public ViewHolder setRating(int viewId, float rating, int max) { 198 | RatingBar view = getView(viewId); 199 | view.setMax(max); 200 | view.setRating(rating); 201 | return this; 202 | } 203 | 204 | public ViewHolder setTag(int viewId, Object tag) { 205 | View view = getView(viewId); 206 | view.setTag(tag); 207 | return this; 208 | } 209 | 210 | public ViewHolder setTag(int viewId, int key, Object tag) { 211 | View view = getView(viewId); 212 | view.setTag(key, tag); 213 | return this; 214 | } 215 | 216 | public ViewHolder setChecked(int viewId, boolean checked) { 217 | Checkable view = (Checkable) getView(viewId); 218 | view.setChecked(checked); 219 | return this; 220 | } 221 | 222 | /** 223 | * 关于事件的 224 | */ 225 | public ViewHolder setOnClickListener(int viewId, 226 | View.OnClickListener listener) { 227 | View view = getView(viewId); 228 | view.setOnClickListener(listener); 229 | return this; 230 | } 231 | 232 | public ViewHolder setOnTouchListener(int viewId, 233 | View.OnTouchListener listener) { 234 | View view = getView(viewId); 235 | view.setOnTouchListener(listener); 236 | return this; 237 | } 238 | 239 | public ViewHolder setOnLongClickListener(int viewId, 240 | View.OnLongClickListener listener) { 241 | View view = getView(viewId); 242 | view.setOnLongClickListener(listener); 243 | return this; 244 | } 245 | 246 | } 247 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/head_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssyijiu/SwipeLayout/4ff1492a27f7da8dcff7ac205b5e4b1eb3fab0c1/app/src/main/res/drawable-xhdpi/head_1.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 14 | 15 |