您的位置:首页 > 移动开发 > Android开发

Android开发-自定义View-AndroidStudio(十六)侧滑删除

2016-12-29 16:23 495 查看
转载请注明出处:http://blog.csdn.net/iwanghang/article/details/53929510
觉得博文有用,请点赞,请评论,请关注,谢谢!~

项目源码下载:http://download.csdn.net/detail/iwanghang/9724693

老规矩,先上GIF动态图,看个效果,如果符合你的项目或者确定你要了解的内容,再往下看吧:
其实最近几篇博客写得不是很好,代码已经不太适合初学者来阅读,很多地方刚接触Android的同学可能还需要查资料,才能理解。
从这篇博文开始,博主把所有可能需要查资料的地方,都写在注释里,起码看了就明白意思,减少大家查资料的时间。
争取做到,复制代码就去用,不懂的地方几乎不用查资料,直接从注释里就能得到答案。让我们共同进步~





MainActivity.java:
package com.iwanghang.slidedemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

private ListView lv_main;
private ArrayList<MyBean> myBeans;
private MyAdapter myAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv_main = (ListView) findViewById(R.id.lv_main);

// 设置适配器
// 准备数据
myBeans = new ArrayList<>();
for(int i=0;i<100;i++){
myBeans.add(new MyBean("iwanghang~"+i));
}
myAdapter = new MyAdapter();
lv_main.setAdapter(myAdapter);
}

class MyAdapter extends BaseAdapter{

@Override
public int getCount() {
return myBeans.size();
}

@Override
public Object getItem(int position) {
return null;
}

@Override
public long getItemId(int position) {
return 0;
}

/**
* ViewHolder的解释:
* 1、只是一个静态类,不是Android的API方法。
* 2、它的作用就在于减少不必要的调用findViewById,然后把对底下的控件引用存在ViewHolder里面,再在
* View.setTag(holder)把它放在view里,下次就可以直接取了。
*/
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if(convertView == null){
convertView = View.inflate(MainActivity.this,R.layout.item_main,null);
viewHolder = new ViewHolder();
viewHolder.item_content = (TextView) convertView.findViewById(R.id.item_content);
viewHolder.item_menu = (TextView) convertView.findViewById(R.id.item_menu);
/**
* setTag
* 把查找的view缓存起来方便多次重用
* 相当于给View对象的一个标签。XX标签可以是任何内容,我们这里把他设置成了一个对象XX。
*
* Tag的作用就是设置标签,标签可以是任意玩意。
* 以及convertView是如何在程序中使代码运行变的效率的:利用缓存convertView尽可能少实例化
* 同样结构体的对象;
*/
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}

// 根据位置得到内容
final MyBean myBean = myBeans.get(position);
viewHolder.item_content.setText(myBean.getName());

viewHolder.item_content.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyBean myBean1 = myBeans.get(position);
Toast.makeText(MainActivity.this, myBean1.getName(), Toast.LENGTH_SHORT).show();
System.out.println("MainActivity---onClick");
}
});

viewHolder.item_menu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
/**
* getParent() 获取父组件
* 获取爷爷组件,可以使用getParent().getParent()
*/
SlideLayout slideLayout = (SlideLayout) view.getParent();
slideLayout.closeMenu();
myBeans.remove(myBean);
notifyDataSetChanged();
System.out.println("MainActivity---remove");
}
});

SlideLayout slideLayout = (SlideLayout) convertView;
slideLayout.setOnStateChangeListener(new MyOnStateChangeListener());
return convertView;
}
}

private SlideLayout slideLayout;

class MyOnStateChangeListener implements SlideLayout.OnStateChangeListener {

@Override
public void onClose(SlideLayout layout) {
if(slideLayout == layout){
slideLayout = null;
}
}

@Override
public void onDown(SlideLayout layout) {
if(slideLayout!=null && slideLayout!=layout){
slideLayout.closeMenu();
}
}

@Override
public void onOpen(SlideLayout layout) {
slideLayout = layout;
}

}

/**
* ViewHolder的解释:
* 1、只是一个静态类,不是Android的API方法。
* 2、它的作用就在于减少不必要的调用findViewById,然后把对底下的控件引用存在ViewHolder里面,再在
* View.setTag(holder)把它放在view里,下次就可以直接取了。
*/
static class ViewHolder{
TextView item_content;
TextView item_menu;
}
}
SlideLayout.java:
package com.iwanghang.slidedemo;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.Scroller;

public class SlideLayout extends FrameLayout {

private static final String TAG = SlideLayout.class.getSimpleName();
private View contentView;
private View menuView;

/**
* 滚动者
*/
private Scroller scroller;

/**
* Content的宽
*/
private int contentWidth;
private int menuWidth;
private int viewHeight; // 他们的高都是相同的

public SlideLayout(Context context, AttributeSet attrs) {
super(context, attrs);
scroller = new Scroller(context);
}

/**
* 当布局文件加载完成的时候回调这个方法
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
contentView = getChildAt(0);
menuView = getChildAt(1);
}

/**
* 在测量方法里,得到各个控件的高和宽
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
contentWidth = contentView.getMeasuredWidth();
menuWidth = menuView.getMeasuredWidth();
viewHeight = getMeasuredHeight();
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 指定菜单的位置
menuView.layout(contentWidth, 0, contentWidth + menuWidth, viewHeight);
}

private float startX;
private float startY;
private float downX; // 只赋值一次
private float downY;

@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 1.按下记录坐标
downX = startX = event.getX();
downY = startY = event.getY();
Log.e(TAG,"SlideLayout-onTouchEvent-ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"SlideLayout-onTouchEvent-ACTION_MOVE");
// 2.记录结束值
float endX = event.getX();
float endY = event.getY();
// 3.计算偏移量
float distanceX = endX - startX;

int toScrollX = (int) (getScrollX() - distanceX);
if (toScrollX < 0) {
toScrollX = 0;
} else if (toScrollX > menuWidth) {
toScrollX = menuWidth;
}

scrollTo(toScrollX, getScrollY());

startX = event.getX();
startY = event.getY();
// 在X轴和Y轴滑动的距离
float DX = Math.abs(endX-downX);
float DY = Math.abs(endY-downY);
if(DX>DY && DX>8){
// 水平方向滑动
// 响应侧滑
// 反拦截-事件给SlideLayout
getParent().requestDisallowInterceptTouchEvent(true);
}

break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"SlideLayout-onTouchEvent-ACTION_UP");
int totalScrollX = getScrollX();//偏移量
if(totalScrollX < menuWidth/2){
// 关闭Menu
closeMenu();
}else{
// 打开Menu
openMenu();
}
break;
}

return true;
}

/**
* true:拦截孩子的事件,但会执行当前控件的onTouchEvent()方法
* false:不拦截孩子的事件,事件继续传递
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercept = false;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 1、按下记录坐标
downX = startX = event.getX();
Log.e(TAG,"SlideLayout-onTouchEvent-ACTION_DOWN");
if(onStateChangeListener != null){
onStateChangeListener.onDown(this);
}
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"SlideLayout-onTouchEvent-ACTION_MOVE");
// 2、记录结束值
float endX = event.getX();
float endY = event.getY();
// 3、计算偏移量
float distanceX = endX - startX;

startX = event.getX();
// 在X轴和Y轴滑动的距离
float DX = Math.abs(endX-downX);
if(DX>8){
intercept = true;
}

break;
case MotionEvent.ACTION_UP:
break;
}

return intercept;
}

/**
* 打开menu
*/
public void openMenu() {
// --->menuWidth
int distanceX = menuWidth - getScrollX();
scroller.startScroll(getScrollX(), getScrollY(), distanceX, getScrollY());
invalidate(); // 强制刷新
System.out.println("SlideLayout---openMenu");
if(onStateChangeListener != null){
onStateChangeListener.onOpen(this);
}
}

/**
* 关闭menu
*/
public void closeMenu() {
// --->0
int distanceX = 0 - getScrollX();
scroller.startScroll(getScrollX(), getScrollY(), distanceX, getScrollY());
invalidate(); // 强制刷新
System.out.println("SlideLayout---closeMenu");
if(onStateChangeListener != null){
onStateChangeListener.onClose(this);
}
}

/**
* computeScroll:主要功能是计算拖动的位移量、更新背景、设置要显示的屏幕(setCurrentScreen(mCurrentScreen);)。
* 重写computeScroll()的原因:调用startScroll()是不会有滚动效果的,只有在computeScroll()获取滚动情况,做出滚动的响应
*/
@Override
public void computeScroll() {
super.computeScroll();
if(scroller.computeScrollOffset()){
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();
System.out.println("SlideLayout---computeScroll");
}
}

/**
* 接口回调
* 监听SlideLayout状态的改变
*/
public interface OnStateChangeListener{
void onClose(SlideLayout layout);
void onDown(SlideLayout layout);
void onOpen(SlideLayout layout);
}

private  OnStateChangeListener onStateChangeListener;

/**
* 设置SlideLayout状态的监听
*/
public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener) {
this.onStateChangeListener = onStateChangeListener;
}
}
MyBean.java:
package com.iwanghang.slidedemo;

public class MyBean {
private String name;

public MyBean(String name) {
this.name = name;
}

public String getName() {
return name;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context="com.iwanghang.slidedemo.MainActivity">

<ListView
android:id="@+id/lv_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
item_main.xml
<?xml version="1.0" encoding="utf-8"?>
<com.iwanghang.slidedemo.SlideLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp">

<include android:id="@+id/item_content" layout="@layout/item_content"/>
<include android:id="@+id/item_menu" layout="@layout/item_menu"/>

</com.iwanghang.slidedemo.SlideLayout>
item_content.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#44000000"
android:gravity="center"
android:text="Content"
android:textColor="#000000"
android:textSize="25sp">
</TextView>
item_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:background="#22000000"
android:gravity="center"
android:text="Delete"
android:textColor="#ff0000"
android:textSize="25sp">
</TextView>


转载请注明出处:http://blog.csdn.net/iwanghang/article/details/53929510

欢迎移动开发爱好者交流
沈阳或周边城市公司有意开发Android,请与我联系
联系方式



微信:iwanghang
QQ:413711276
邮箱:iwanghang@qq.com



项目源码下载:http://download.csdn.net/detail/iwanghang/9724693

觉得博文有用,请点赞,请评论,请关注,谢谢!~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: