個人習慣,先上圖

同事是個妹子(這點很重要),寫滑動刪除動能的時候用到了SwipeLayout,然后悲催的是,滑動時間被攔截了,解決方法先不提,在(一)中先講解SwipeLayout下載listview並實現滑動刪除效果,當然加載listview有很多種方式,后面都會講到,
首先你需要了解ViewDragHelper,ViewDragHelper重寫觸摸事件參數從而可以拖動改變子view的位置,具體魅力見:
需要看源碼的關聯一下http://www.tuicool.com/articles/JZbEvya
2013年谷歌i/o大會上介紹了兩個新的layout: SlidingPaneLayout和DrawerLayout都用到viewdragHelper處理拖動事件,好了話不多費能力有限精力不充足不研究太深,會用就ok,具體見滑動刪除例子代碼:
》》》創建SwipeLayout
package com.one.swipe;
import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
/**
* 相當於繼承viewGroup
*/
public class SwipeLayout extends FrameLayout {
/**
* 用到枚舉三種狀態,代碼模式
*/
public static enum Status {
Close, Open, Swiping
}
public interface OnSwipeListener{
void onClose(SwipeLayout layout);
void onOpen(SwipeLayout layout);
void onStartOpen(SwipeLayout layout);
void onStartClose(SwipeLayout layout);
}
private Status status = Status.Close;
private OnSwipeListener onSwipeListener;
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public OnSwipeListener getOnSwipeListener() {
return onSwipeListener;
}
public void setOnSwipeListener(OnSwipeListener onSwipeListener) {
this.onSwipeListener = onSwipeListener;
}
//--------------------------上面和我們常用設置adapter差不多綁定偵聽和布局設置參數
private ViewDragHelper mHelper;
public SwipeLayout(Context context) {
this(context, null);
}
public SwipeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SwipeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 1. 創建ViewDragHelper 第二個參數默認值
mHelper = ViewDragHelper.create(this,1.0f, callback);
}
// 3. 重寫一系列回調的方法
ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return true;
}
/**
* 水平方向移動的處理 限制范圍
*/
public int getViewHorizontalDragRange(View child) {
return mRange;
};
/**
* 豎直方向的處理
*/
public int clampViewPositionHorizontal(View child, int left, int dx) {
// 返回的值決定了將要移動到的位置.
if(child == mFrontView){
if(left < - mRange){
// 限定左范圍
return - mRange;
}else if (left > 0) {
// 限定右范圍
return 0;
}
}else if (child == mBackView) {
if(left < mWidth - mRange){
// 限定左范圍
return mWidth - mRange;
}else if (left > mWidth) {
// 限定右范圍
return mWidth;
}
}
return left;
};
// 位置發生改變的時候, 把水平方向的偏移量傳遞給另一個布局
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
if(changedView == mFrontView){
// 拖拽的是前布局, 把剛剛發生的 偏移量dx 傳遞給 后布局
mBackView.offsetLeftAndRight(dx);
} else if (changedView == mBackView) {
// 拖拽的是后布局, 把剛剛發生的 偏移量dx 傳遞給 前布局
mFrontView.offsetLeftAndRight(dx);
}
dispatchDragEvent();
invalidate();
};
/**
* Released svn上貌似有這個設置,回滾
*/
public void onViewReleased(View releasedChild, float xvel, float yvel) {
// 松手時候會被調用
// xvel 向右+, 向左-
if(xvel == 0 && mFrontView.getLeft() < - mRange * 0.5f){
open();
}else if(xvel < 0){
open();
}else {
close();
}
};
};
private View mBackView;
private View mFrontView;
private int mRange;
private int mWidth;
private int mHeight;
/**
* 更新當前的狀態
*/
protected void dispatchDragEvent() {
Status lastStatus = status;
// 獲取最新的狀態
status = updateStatus();
// 狀態改變的時候, 調用監聽里的方法
if(lastStatus != status && onSwipeListener != null){
if(status == Status.Open){
onSwipeListener.onOpen(this);
}else if (status == Status.Close) {
onSwipeListener.onClose(this);
}else if (status == Status.Swiping) {
if(lastStatus == Status.Close){
onSwipeListener.onStartOpen(this);
}else if (lastStatus == Status.Open) {
onSwipeListener.onStartClose(this);
}
}
}
}
private Status updateStatus() {
int left = mFrontView.getLeft();
if(left == 0){
return Status.Close;
}else if (left == -mRange) {
return Status.Open;
}
return Status.Swiping;
}
@Override
public void computeScroll() {
super.computeScroll();
// 維持平滑動畫繼續
if(mHelper.continueSettling(true)){
ViewCompat.postInvalidateOnAnimation(this);
}
}
/**
* 關閉
*/
protected void close() {
close(true);
}
public void close(boolean isSmooth){
int finalLeft = 0;
if(isSmooth){
// 觸發平滑動畫
if(mHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)){
ViewCompat.postInvalidateOnAnimation(this);
}
}else {
layoutContent(false);
}
}
/**
* 打開
*/
protected void open() {
open(true);
}
public void open(boolean isSmooth){
int finalLeft = -mRange;
if(isSmooth){
// 觸發平滑動畫
if(mHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)){
ViewCompat.postInvalidateOnAnimation(this);
}
}else {
layoutContent(false);
}
}
// 2. 轉交觸摸事件攔截判斷, 處理觸摸事件
public boolean onInterceptTouchEvent(android.view.MotionEvent ev) {
if (mHelper.shouldInterceptTouchEvent(ev)) {
return true;
}
return super.onInterceptTouchEvent(ev);
};
/**
* 時間交由mHelper處理,默認返回true
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
try {
mHelper.processTouchEvent(event);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 默認是關閉狀態
layoutContent(false);
}
/**
* 根據當前的開啟狀態擺放內容
* @param isOpen
*/
private void layoutContent(boolean isOpen) {
// 設置前布局位置
Rect rect = computeFrontRect(isOpen);
mFrontView.layout(rect.left, rect.top, rect.right, rect.bottom);
// 根據前布局位置設置后布局位置
Rect backRect = computeBackRectViaFront(rect);
mBackView.layout(backRect.left, backRect.top, backRect.right, backRect.bottom);
// 把任意布局順序調整到最上
bringChildToFront(mFrontView);
}
/**
* 計算后布局的矩形區域
* @param rect
* @return
*/
private Rect computeBackRectViaFront(Rect rect) {
int left = rect.right;
return new Rect(left, 0, left + mRange , 0 + mHeight);
}
/**
* 計算前布局的矩形區域
* @param isOpen
* @return
*/
private Rect computeFrontRect(boolean isOpen) {
int left = 0;
if(isOpen){
left = -mRange;
}
return new Rect(left, 0, left + mWidth, 0 + mHeight);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRange = mBackView.getMeasuredWidth();
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
}
/**
* 賦值等一些操作
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mBackView = getChildAt(0);
mFrontView = getChildAt(1);
}
/**
* 這個方法可以用來設置拖動距離等操作
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
============================================================
package com.one.swipe;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.one.swipe.SwipeLayout.OnSwipeListener;
public class MyAdapter extends BaseAdapter {
private Context context;
private List<String> list;
private ArrayList<SwipeLayout> openedItems;
public MyAdapter(Context context, List<String> list) {
super();
this.context=context;
this.list=list;
openedItems = new ArrayList<SwipeLayout>();
}
@Override
public int getCount() {
return list==null?0:list.size();
}
@Override
public Object getItem(int position) {
return list == null ? 0 : position;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView==null){
holder = new ViewHolder();
convertView=View.inflate(context, R.layout.public_type_item, null);
holder.tv_type=(TextView) convertView.findViewById(R.id.tv_type);
holder.tv_date=(TextView) convertView.findViewById(R.id.tv_date);
holder.tv_price=(TextView) convertView.findViewById(R.id.tv_price);
convertView.setTag(holder);
}else{
holder=(ViewHolder) convertView.getTag();
}
SwipeLayout sl = (SwipeLayout)convertView;
sl.setOnSwipeListener(new OnSwipeListener() {
@Override
public void onClose(SwipeLayout layout) {
openedItems.remove(layout);
}
@Override
public void onOpen(SwipeLayout layout) {
openedItems.add(layout);
}
@Override
public void onStartOpen(SwipeLayout layout) {
// 關閉所有已經打開的條目
for (int i = 0; i < openedItems.size(); i++) {
openedItems.get(i).close(true);
}
openedItems.clear();
}
@Override
public void onStartClose(SwipeLayout layout) {
}
});
String tv_type=holder.tv_type.getText().toString().trim();
List<String> list = new ArrayList<String>();
list.add(tv_type);
return convertView;
}
class ViewHolder{
public TextView tv_type;
public TextView tv_date;
public TextView tv_price;
}
}
====================================
MainActivity
package com.one.swipe;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
public class MainActivity extends Activity implements OnClickListener {
private Button btn;
private ListView view;
private List<String> list;
private MyAdapter adapter;
private EditText et;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(this);
view = (ListView) findViewById(R.id.listview);
et = (EditText) findViewById(R.id.et);
initData();
}
private void initData() {
list = new ArrayList();
for (int i = 0; i < 3; i++) {
list.add(i + "");
}
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.btn:
adapter = new MyAdapter(getApplicationContext(), list);
view.setAdapter(adapter);
adapter.notifyDataSetChanged();
break;
default:
break;
}
}
}
================================
main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<EditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:text="寫點啥呢"
/>
<Button
android:layout_marginTop="20dp"
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="看效果"
android:layout_centerInParent="true"
android:layout_gravity="center"
/>
<ListView
android:id="@+id/listview"
android:layout_width="fill_parent"
android:layout_height="120dp"
android:layout_marginTop="20dp"
/>
</LinearLayout>
</ScrollView>
============================
item.xml
<?xml version="1.0" encoding="utf-8"?>
<com.one.swipe.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sl"
android:layout_width="match_parent"
android:layout_height="@dimen/item_height" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="@dimen/item_height"
android:orientation="horizontal" >
<TextView
android:layout_width="60dp"
android:layout_height="@dimen/item_height"
android:background="#666666"
android:gravity="center"
android:text="cancel"
android:textColor="#FFFFFF" />
<TextView
android:layout_width="60dp"
android:layout_height="@dimen/item_height"
android:background="#FF0000"
android:gravity="center"
android:text="Delete"
android:textColor="#FFFFFF" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/item_height"
android:background="@drawable/bg_detail_item"
android:orientation="horizontal"
>
<TextView
android:id="@+id/tv_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:hint="做平凡一個"
android:textColor="@color/txt_date"
android:textSize="@dimen/text_size" />
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:hint="用十倍苦心"
android:textColor="@color/txt_date"
android:textSize="@dimen/text_size" />
<TextView
android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:hint="一座城池2012"
android:textColor="@color/txt_date"
android:textSize="@dimen/text_size" />
</LinearLayout>
</com.one.swipe.SwipeLayout>
ok,就是這些了 還有5個關於ViewDragHelper有簡單到難的demo整理完了,明天在一塊上傳吧,
hosts 文件配置c:\windows\system32\drivers\etc 復制完后enter一下,叫我雷鋒就好了,Google,github正常使用啦不要忘記加群哦:Android&Go,Let's go! 521039620
hosts下載地址:http://download.csdn.net/detail/onebelowzero2012/9359679
