经常在遇到问题第一时间都会在网上搜索解决的方法,因此看到很多前辈们的比较精辟的技术文章,学习了很多东西,现在将自己平时工作中开发的一些小功能坐下总结,也写出来,既方便自己理清思路记忆功能块实现思路,又能与大家一起交流分享技术。
第一次写文章,哪里有不对的希望大家多多包涵!
通过ListView + PopupWindow的方式实现了仿微信的侧滑删除、取消关注功能。
实现的效果图如下:
下面贴出代码:
1、列表子项的“取消关注”和“删除”按钮的布局,文件名“layout_del_cancel_btn.xml”,代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<Button
android:id="@+id/id_item_cancel_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消关注"
android:background="@android:color/darker_gray"
android:textColor="#ffffff"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
/>
<Button
android:id="@+id/id_item_btn"
android:layout_width="60dp"
android:layout_height="wrap_content"
android:text="删除"
android:background="@android:color/holo_red_light"
android:textColor="#ffffff"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
/>
LinearLayout>
2、自定义的ListView,文件名“SlideDeleteCancelListView.java”,代码如下:
package com.record2text.vitospc.deletelistview;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;
/**
* 仿微信删除/取消关注列表
* @author 马文涛 技术群:317922608
*/
public class SlideDeleteCancelListView extends ListView {
private static final String TAG = "SlideDelListView";
private LayoutInflater mInflater = null;
/**
* 用户滑动的最小距离
*/
private int touchSlop;
/**
* 是否响应滑动
*/
private boolean isSliding;
/**
* 手指按下时的x坐标
*/
private int xDown;
/**
* 手指按下时的y坐标
*/
private int yDown;
/**
* 手指移动时的x坐标
*/
private int xMove;
/**
* 手指移动时的y坐标
*/
private int yMove;
/**
* 当前手指触摸的View
*/
private View mCurrentView;
/**
* 单签手指触摸的位置
*/
private int mCurrentViewPos;
/**
* 为删除按钮提供一个回调接口
*/
private DelButtonClickListener mDelListener = null;
private CancelButtonClickListener mCancelListener = null;
private PopupWindow mPopupWindow = null;
private Button mDelBtn = null,mCancelBtn = null;
private int mPopupWindowWidth, mPopupWindowHeight;
/** 自定义ListView的构造方法 在里面做一些必要的一些初始化
* @param context
* @param attrs
*/
public SlideDeleteCancelListView(Context context, AttributeSet attrs) {
super(context, attrs);
mInflater = LayoutInflater.from(context);
//用户手指移动的最小距离,用来判断是否响应触发移动事件
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
View view = mInflater.inflate(R.layout.layout_del_cancel_btn,null);
//删除按钮
mDelBtn = (Button) view.findViewById(R.id.id_item_btn);
//取消按钮
mCancelBtn = (Button) view.findViewById(R.id.id_item_cancel_btn);
mPopupWindow = new PopupWindow(view,
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
/**
* 先调用下measure,否则拿不到宽和高
*/
mPopupWindow.getContentView().measure(0,0);
mPopupWindowHeight = mPopupWindow.getContentView().getMeasuredHeight();
mPopupWindowWidth = mPopupWindow.getContentView().getMeasuredWidth();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (action){
case MotionEvent.ACTION_DOWN:
//手指按下时水平方向x的位置
xDown = x;
//手指按下时垂直方向y的位置
yDown = y;
/*
* 如果当前popupWindow显示,则直接隐藏,然后屏蔽ListView的Touch事件的下传
* */
if (mPopupWindow.isShowing()){
dismissPopWindow();
return false;
}
// 获得当前手指按下时的item的位置
mCurrentViewPos = pointToPosition(xDown,yDown);
// 获得当前手指按下时的ListView的item项
mCurrentView = getChildAt(mCurrentViewPos - getFirstVisiblePosition());
break;
case MotionEvent.ACTION_MOVE:
//手指移动时x的位置
xMove = x;
//手指一动时y的位置
yMove = y;
//水平滑动的距离(可能为负值)
int dx = xMove - xDown;
//垂直滑动的距离(可能为负值)
int dy = yMove - yDown;
/*
* 判断是否是从右到左的滑动
* */
if ( xMove < xDown && Math.abs(dx) > touchSlop && Math.abs(dy) < touchSlop ){
Log.e(TAG, "touchslop = " + touchSlop + " , dx = " + dx + " , dy = " + dy);
isSliding = true;
}
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
/*
* 如果是从右到左的滑动才响应,之前已在 dispatchTouchEvent 中获得了是否是从右向左滑动
* */
if ( isSliding ){
switch (action){
case MotionEvent.ACTION_MOVE:
int []location = new int[2];
//获得当前item的位置x与y
mCurrentView.getLocationOnScreen(location);
//设置PopupWindow的动画
mPopupWindow.setAnimationStyle(R.style.popwindow_delete_btn_anim_style);
mPopupWindow.update();
Log.e(TAG,"width location[0]: " + location[0]);
Log.e(TAG,"height location[1]: " + location[1]);
Log.e(TAG,"mCurrentView.getWidth(): " + mCurrentView.getWidth());
Log.e(TAG,"mCurrentView.getHeight(): " + mCurrentView.getHeight());
Log.e(TAG,"mPopupWindowHeight: " + mPopupWindowHeight);
//设置“取消关注”、“删除”按钮PopWindow的显示位置
//相对于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以设置偏移或无偏移
//相对某个控件的位置,有偏移;xoff表示x轴的偏移,正值表示向左,负值表示向右;yoff表示相对y轴的偏移,正值是向下,负值是向上;
mPopupWindow.showAtLocation(mCurrentView,
Gravity.LEFT | Gravity.TOP,
location[0] + mCurrentView.getWidth() ,
location[1] + mCurrentView.getHeight()/2 - mPopupWindowHeight /2);
//设置删除按钮的回调
mDelBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//通过接口对象调用当前Item上删除按钮的点击方法
mDelListener.onDelClick(mCurrentViewPos);
mPopupWindow.dismiss();
}
});
//设置取消按钮的回调
mCancelBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//通过接口对象调用当前Item上取消按钮的点击方法
mCancelListener.onCancelClick(mCurrentViewPos);
mPopupWindow.dismiss();
}
});
Log.e(TAG, "mPopupWindow.getHeight()=" + mPopupWindowHeight);
break;
case MotionEvent.ACTION_UP:
//设置侧滑关闭
isSliding = false;
break;
}
// 相应滑动期间屏幕itemClick事件,避免发生冲突
return true;
}
return super.onTouchEvent(ev);
}
/**
* 隐藏popupWindow
*/
private void dismissPopWindow()
{
if (mPopupWindow != null && mPopupWindow.isShowing())
{
mPopupWindow.dismiss();
}
}
/** 设置删除按钮点击事件监听
* @param listener DelButtonClickListener 删除按钮监听接口对象
*/
public void setDelButtonClickListener(DelButtonClickListener listener)
{
mDelListener = listener;
}
/** 设置取消按钮点击事件监听
* @param listener CancelButtonClickListener 按钮点击事件监听接口对象
*/
public void setCancelButtonClickListener(CancelButtonClickListener listener){
mCancelListener = listener;
}
/**
* 删除按钮监听接口
*/
interface DelButtonClickListener{
void onDelClick(int position);
}
/**
* 取消按钮监听接口
*/
interface CancelButtonClickListener{
void onCancelClick(int position);
}
}
3、滑动展示“删除”、“取消关注”时需要展示和隐藏的动画,在自定义的ListView类“SlideDeleteCancelListView”中用到了,分别如下:
a.展示动画,文件名“delete_btn_show.xml”,代码如下:
http://schemas.android.com/apk/res/android">
<scale android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="0.0"
android:toXScale="1.0"
android:fromYScale="1.0"
android:toYScale="1.0"
android:pivotX="100%"
android:pivotY="50%"
android:fillAfter="false"
android:duration="200" >
scale>
set>
b.隐藏动画,文件名“delete_btn_hide.xml”,代码如下:
http://schemas.android.com/apk/res/android">
<scale android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="1.0"
android:toXScale="0.0"
android:fromYScale="1.0"
android:toYScale="1.0"
android:pivotX="100%"
android:pivotY="50%"
android:fillAfter="false"
android:duration="200" >
scale>
set>
4、以上部分已经完成了自定义有删除和取消关注功能的ListView,紧接着我们看一下如何使用这个ListView吧,首先贴上布局文件中的调用代码,文件名“activity_main.xml”,代码如下:
"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.record2text.vitospc.deletelistview.MainActivity">
<com.record2text.vitospc.deletelistview.SlideDeleteCancelListView
android:id="@+id/id_listview"
android:layout_width="match_parent"
android:layout_height="match_parent">
com.record2text.vitospc.deletelistview.SlideDeleteCancelListView>
5、下来我们看一下主页面“MainActivity.java”中如何调用该段代码,并给响应的部分添加事件的,代码如下:
package com.record2text.vitospc.deletelistview;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 仿微信删除/取消关注列表
* @author 马文涛 技术群:317922608
*/
public class MainActivity extends AppCompatActivity {
private SlideDeleteCancelListView mListView = null;
private List mDatas = null;
private ArrayAdapter mAdapter = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (SlideDeleteCancelListView) findViewById(R.id.id_listview);
mDatas = new ArrayList<>(Arrays.asList("北京市", "天津市", "上海市", "重庆市", "安徽省", "福建省",
"甘肃省", "广东省", "贵州省", "海南省", "河北省","河南省","黑龙江省","湖北省","湖南省","吉林省"));
mAdapter = new ArrayAdapter(MainActivity.this,android.R.layout.simple_list_item_1, mDatas);
mListView.setAdapter(mAdapter);
//设置列表项Item删除按钮的点击监听事件
mListView.setDelButtonClickListener(new SlideDeleteCancelListView.DelButtonClickListener() {
@Override
public void onDelClick(int position) {
Toast.makeText(MainActivity.this, "删除:" + position + " : " + mAdapter.getItem(position), Toast.LENGTH_SHORT).show();
//从列表中移除当前项
mAdapter.remove(mAdapter.getItem(position));
}
});
//设置列表项Item的取消按钮点击监听事件
mListView.setCancelButtonClickListener(new SlideDeleteCancelListView.CancelButtonClickListener() {
@Override
public void onCancelClick(int position) {
Toast.makeText(MainActivity.this, "取消关注:" + position + " : " + mAdapter.getItem(position), Toast.LENGTH_SHORT).show();
}
});
//设置列表项Item点击监听事件
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id)
{
Toast.makeText(MainActivity.this, "您点击的是第 " + position + " 项: " + mAdapter.getItem(position), Toast.LENGTH_SHORT).show();
}
});
}
}
已经完成了一个自定义的具有侧滑“删除”、“取消关注”的自定义ListView控件,在使用过程中大家只需要结合自己的项目进行修改即可。
新人初次发文章,有不足之处希望大家多多海涵,有兴趣的朋友可以加QQ群317922608,大家一起多多交流,多多指教,相互学习!
源码地址:http://download.csdn.net/detail/laker10070/9735811