高仿微信实现左滑显示删除button功能
在实际项目中删除列表中的某一项是很常见的功能。传统的做法能够使用长按监听器等,而如今流行的做法是左滑弹出删除button,微信,QQ等都是这么做的,以下做一个演示样例,代码例如以下:
主页面MainActivity:代码比較简单常规
package com.home.testslideview; import java.util.ArrayList;
import java.util.List; import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView; import com.home.textslideview.R; public class MainActivity extends Activity { private ListView listView; private List<NewInfoBean> list = new ArrayList<NewInfoBean>(); // 适配器
private SlideAdapter adapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initView();
initData();
setAdapter();
} /**
* 初始化页面控件
*/
private void initView() {
listView = (ListView) findViewById(R.id.main_lv);
} /**
* 初始化数据
*/
private void initData() {
list.add(new NewInfoBean("这是測试内容1"));
list.add(new NewInfoBean("这是測试内容2"));
list.add(new NewInfoBean("这是測试内容3"));
list.add(new NewInfoBean("这是測试内容4"));
list.add(new NewInfoBean("这是測试内容5"));
list.add(new NewInfoBean("这是測试内容6"));
list.add(new NewInfoBean("这是測试内容7"));
list.add(new NewInfoBean("这是測试内容8"));
list.add(new NewInfoBean("这是測试内容9"));
list.add(new NewInfoBean("这是測试内容10"));
} /**
* 设置适配器
*/
private void setAdapter() {
if (adapter == null) {
adapter = new SlideAdapter(this, list);
listView.setAdapter(adapter);
} else {
adapter.setList(list);
adapter.notifyDataSetChanged();
}
} }
实体类NewInfoBean:详细项目中由自定义:
package com.home.testslideview;
public class NewInfoBean {
public SlideView slideView;
private String content;
public SlideView getSlideView() {
return slideView;
}
public void setSlideView(SlideView slideView) {
this.slideView = slideView;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public NewInfoBean() {
super();
}
public NewInfoBean(String content) {
super();
this.content = content;
}
}
适配器SlideAdapter:也比較简单
package com.home.testslideview; import java.util.List; import android.content.Context;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView; import com.home.testslideview.SlideView.OnSlideListener;
import com.home.textslideview.R; public class SlideAdapter extends BaseAdapter implements OnSlideListener,
OnClickListener { private LayoutInflater inflater; private List<NewInfoBean> list; private Context context; public SlideAdapter(Context context, List<NewInfoBean> list) {
if (inflater == null) {
inflater = LayoutInflater.from(context);
}
this.list = list;
this.context = context;
} @Override
public int getCount() {
return list.size();
} @Override
public Object getItem(int position) {
return list.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup arg2) { SlideView slideView = (SlideView) convertView;
NewInfoBean bean = list.get(position);
if (slideView == null) {
slideView = new SlideView(context);
slideView.setOnSlideListener(this);
} // 设置内容
TextView contentText = getAdapterView(slideView,
R.id.slideview_tv_content, position);
contentText.setText(bean.getContent()); // 删除button
TextView delText = getAdapterView(slideView, R.id.slideview_tv_del,
position);
delText.setOnClickListener(this); bean.slideView = slideView;
bean.slideView.shrink(); return slideView;
} @SuppressWarnings("unchecked")
public <T extends View> T getAdapterView(View convertView, int id,
Object tag) {
SparseArray<View> viewHolder = null;
try {
if (convertView.getTag(R.id.view_holder) instanceof SparseArray<?>) {
viewHolder = (SparseArray<View>) convertView
.getTag(R.id.view_holder);
}
} catch (ClassCastException e) {
}
if (viewHolder == null) {
viewHolder = new SparseArray<View>();
convertView.setTag(R.id.view_holder, viewHolder);
convertView.setTag(R.id.order_id, tag);
}
View childView = viewHolder.get(id);
if (childView == null) {
childView = convertView.findViewById(id);
childView.setTag(tag);
viewHolder.put(id, childView);
}
return (T) childView;
} public List<NewInfoBean> getList() {
return list;
} public void setList(List<NewInfoBean> list) {
this.list = list;
} @Override
public void onSlide(View view, int status) {
} @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.slideview_tv_del:
int position = (Integer) v.getTag();
list.remove(position);
notifyDataSetChanged();
break; default:
break;
}
} }
比較关键的两个类:
自己定义的ListView:SlideListView
package com.home.testslideview; import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ListView; public class SlideListView extends ListView { private SlideView itemView; public SlideListView(Context context) {
super(context);
} public SlideListView(Context context, AttributeSet attrs) {
super(context, attrs);
} public void shrinkListItem(int position) {
View item = getChildAt(position);
if (item != null) {
try {
((SlideView) item).shrink();
} catch (ClassCastException e) {
e.printStackTrace();
}
}
} @Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
int x = (int) event.getX();
int y = (int) event.getY();
int position = pointToPosition(x, y);
if (position != INVALID_POSITION) {
NewInfoBean data = (NewInfoBean) getItemAtPosition(position);
itemView = data.slideView;
}
}
default:
break;
} if (itemView != null) {
itemView.onRequireTouchEvent(event);
} return super.onTouchEvent(event);
} }
自己定义的ListView中的每一行控件:SlideView(借鉴网上的一个演示样例):
package com.home.testslideview; import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Scroller; import com.home.textslideview.R; public class SlideView extends LinearLayout { private static final String TAG = SlideView.class.getSimpleName(); private Context mContext;
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 LayoutInflater inflater; public interface OnSlideListener {
public static final int SLIDE_STATUS_OFF = 0;
public static final int SLIDE_STATUS_START_SCROLL = 1;
public static final int SLIDE_STATUS_ON = 2; /**
* @param view
* current SlideView
* @param status
* SLIDE_STATUS_ON or SLIDE_STATUS_OFF
*/
public void onSlide(View view, int status);
} public SlideView(Context context) {
super(context);
initView();
} public SlideView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
} private void initView() {
mContext = getContext();
if (inflater == null) {
inflater = LayoutInflater.from(mContext);
}
mScroller = new Scroller(mContext); setOrientation(LinearLayout.HORIZONTAL);
View.inflate(mContext, R.layout.slide_view_merge, this);
mHolderWidth = Math.round(TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, mHolderWidth, getResources()
.getDisplayMetrics()));
} public void setOnSlideListener(OnSlideListener onSlideListener) {
mOnSlideListener = onSlideListener;
} public void shrink() {
if (getScrollX() != 0) {
this.smoothScrollTo(0, 0);
}
} public void onRequireTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
int scrollX = getScrollX();
Log.d(TAG, "x=" + x + " y=" + y); switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
if (mOnSlideListener != null) {
mOnSlideListener.onSlide(this,
OnSlideListener.SLIDE_STATUS_START_SCROLL);
}
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastX;
int deltaY = y - mLastY;
if (Math.abs(deltaX) < Math.abs(deltaY) * TAN) {
break;
} int newScrollX = scrollX - deltaX;
if (deltaX != 0) {
if (newScrollX < 0) {
newScrollX = 0;
} else if (newScrollX > mHolderWidth) {
newScrollX = mHolderWidth;
}
this.scrollTo(newScrollX, 0);
}
break;
}
case MotionEvent.ACTION_UP: {
int newScrollX = 0;
if (scrollX - mHolderWidth * 0.75 > 0) {
newScrollX = mHolderWidth;
}
this.smoothScrollTo(newScrollX, 0);
if (mOnSlideListener != null) {
mOnSlideListener.onSlide(this,
newScrollX == 0 ? OnSlideListener.SLIDE_STATUS_OFF
: OnSlideListener.SLIDE_STATUS_ON);
}
break;
}
default:
break;
} mLastX = x;
mLastY = y;
} 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();
}
} }
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <com.home.testslideview.SlideListView
android:id="@+id/main_lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="#00000000"
android:fadingEdge="none"
android:listSelector="#00000000"
android:scrollbars="none" /> </LinearLayout>
slide_view_merge.xml:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" > <LinearLayout
android:id="@+id/slideview_layout_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:orientation="horizontal" > <TextView
android:id="@+id/slideview_tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="内容部分"/> </LinearLayout> <LinearLayout
android:id="@+id/view_layout_del"
android:layout_width="80dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_toRightOf="@id/slideview_layout_content"
android:clickable="true"
android:gravity="center_vertical"
android:orientation="horizontal" > <TextView
android:id="@+id/slideview_tv_del"
android:layout_width="80dp"
android:layout_height="match_parent"
android:layout_marginBottom="2dp"
android:gravity="center"
android:padding="15dp"
android:text="删除"/> </LinearLayout> </merge>
高仿微信实现左滑显示删除button功能的更多相关文章
- Android 高仿微信 获取最近刚刚拍照的缩略图 功能实现
原理其实挺简单的,android 中文件 修改 增加 删除等等 都会在数据库里的某个表里记录下来,你需要的时候 只要迅速的去查找这个表里的值 即可得到你想要的所有信息. 实际上 如果真正理解这个表结构 ...
- Flutter高仿微信项目开源-具即时通讯IM功能
项目地址:https://github.com/fluttercandies/wechat_flutter wechat_flutter Flutter版本微信 效果图: 下载体验(Android) ...
- android高仿微信拍照、多选、预览、删除(去除相片)相冊功能
先声明授人与鱼不如授人与渔,仅仅能提供一个思路,当然须要源代码的同学能够私下有偿问我要源代码:QQ:508181017 工作了将近三年时间了,一直没正儿八经的研究系统自带的相冊和拍照,这回来个高仿微信 ...
- 高仿QQ6.0側滑菜单之滑动优化(二)
好了,昨天已经实现了高仿QQ6.0的側滑大致框架.如有兴趣.能够去看下仿QQ6.0側滑之ViewDragHelper的使用(一) 可是之前的实现.仅仅是简单的能够显示和隐藏左側的菜单,可是特别生硬,并 ...
- iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码
iOS精选源码 iOS高仿微信完整项目源码 Khala: Swift 编写的iOS/macOS 路由框架 微信左滑删除效果的实现与TableViewCell的常用样式介绍 实现阴影圆角并存,渐变色背景 ...
- 安卓开发笔记——Fragment+ViewPager组件(高仿微信界面)
什么是ViewPager? 关于ViewPager的介绍和使用,在之前我写过一篇相关的文章<安卓开发复习笔记——ViewPager组件(仿微信引导界面)>,不清楚的朋友可以看看,这里就不再 ...
- 转-Fragment+ViewPager组件(高仿微信界面)
http://www.cnblogs.com/lichenwei/p/3982302.html 什么是ViewPager? 关于ViewPager的介绍和使用,在之前我写过一篇相关的文章<安卓开 ...
- Android 高仿微信实时聊天 基于百度云推送
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天终于有幸利用百 ...
- Android 高仿微信即时聊天 百度云为基础的推
转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天最终有幸利用百 ...
随机推荐
- python安装numpy模块
1.打开网址https://pypi.python.org/pypi/numpy,找到安装的python版本对应的numpy版本. 我的python版本是 下载的对应numpy版本是 2.将numpy ...
- 常用模块之configpaser与shutil
configparser模块 定义:configparser翻译为配置解析,即它是用来解析配置文件的 配置文件:用于编写程序的配置信息的文件 配置文件编写格式 配置文件中只允许出现两种类型的数据 se ...
- 守护进程,互斥锁,IPC,生产者与消费者模型
守护进程: b 进程守护 a进程,当a进程执行完毕时,b进程会跟着立马结束 守护进程用途: 如果父进程结束了,子进程无需运行了,就可以将子进程设置为父进程的守护进程 例如我们qq视频聊天时,当我们退出 ...
- Day05基本运算符,if判断和while循环
day05 1.常量 变量名全大写 2.基本运算符 ①算术运算 10/3除法 10//3取整 10*3乘法 10**3幂 ②赋值运算 增量赋值 age += 1#age = age + 1 age * ...
- python 四——线程、进程、协程
内容概要 1.进程与线程优.缺点的比较 2.适用情况 3.线程 线程的创建 setDaemon join event RLock 队列 4.进程 创建进程 setDaemon join 线程与进程,数 ...
- Centos6虚拟主机的实现
centos6上虚拟主机的实现 实现虚拟主机有三种方式:基于IP的实现.基于端口的实现.基于FQDN的实现 一.基于IP的实现 1.先创建三个站点: mkdir /app/site1 mkdir ...
- Android DialogFragment全屏
在onCreate里面写入代码: @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(saved ...
- 九度oj 题目1025:最大报销额
题目描述: 现有一笔经费可以报销一定额度的发票.允许报销的发票类型包括买图书(A类).文具(B类).差旅(C类),要求每张发票的总额不得超过1000元,每张发票上,单项物品的价值不得超过600 ...
- php5.3.3版本前后变化中php-v和sbin/php-fpm -v
重装php-fpm试试,遂去http://php-fpm.org/download/想下载个新版本的php-fpm, 结果发现版本大于5.3.3的PHP内部已经集成了php-fpm,不用再另行安装了. ...
- 【Luogu】P1231教辅的组成(拆点+Dinic+当前弧优化)
题目链接 妈耶 我的图建反了两次 准确的说是有两个地方建反了,然后反上加反改了一个小时…… 知道为什么要拆点吗? 假设这是你的图 左边到右边依次是超级源点 练习册 书 答案 ...