ScrollView嵌套SwipeMenuListView的一些改进

概述

dome
dome

这种侧滑菜单大家都不会陌生,自从qq使用了了这种方式之后,网上有很多实现方法。公司有一个业务需要这种模式,本想在github上找个现成的直接使用。于是找到了这个

https://github.com/baoyongzhang/SwipeMenuListView

问题

尽管这个项目实现了大多数功能,但是这个项目存在几个问题

  1. 当其放置于scrollView中,上下滑动和左右滑动有时候会出现冲突,导致菜单收不回来,并且时而滑动艰难

  2. 与部分下拉刷新组件会产生冲突

  3. 每次都只能拉开一个抽屉(业务需要同时打开多个)

解决问题

解决问题1、2

既然是滑动冲突,就按照一般的滑动冲突的解决方法来解决。

为SwipeMenuListView 添加onTouch监听器。根据滑动水平方向与竖直方向的距离来处理。核心是下面的方法

requestDisallowInterceptTouchEvent

这个方法可以让父控件不去拦截这次滑动事件。我们只需设置计算出手指水平方向的偏移量。设置一个阈值即可。


if (Math.abs(localWigth - sx) > 30) {

scrollView.requestDisallowInterceptTouchEvent(true);

}

else{

scrollView.requestDisallowInterceptTouchEvent(false);

}

对于第二个问题,一般出现于那种原理是嵌套于ScrollView或者ListView 并在dispatchTouchEvent进行了流程控制的一些下拉刷新组件。如果你遇到到这种问题用上面的方式是无效的。当然以仿照这种方式在下拉刷新组件的dispatchTouchEvent函数中添加标志位,与scrollView 进行同样的控制

refreshScrollParentViewBase 是下拉刷新组件


@Override

public boolean onTouch(View v, MotionEvent motionEvent) {

if (scrollView == null || refreshScrollParentViewBase == null) {

GetView();

}

switch (motionEvent.getAction()) {

case MotionEvent.ACTION_DOWN:

localWigth = (int) motionEvent.getX();

localHeigth = (int) motionEvent.getY();

break;

case MotionEvent.ACTION_MOVE:

int sx = (int) motionEvent.getX();

if (Math.abs(localWigth - sx) > 30) {

scrollView.requestDisallowInterceptTouchEvent(true);

refreshScrollParentViewBase.setDispath(false);

} else {

scrollView.requestDisallowInterceptTouchEvent(false);

refreshScrollParentViewBase.setDispath(true);

}

break;

case MotionEvent.ACTION_UP:

scrollView.requestDisallowInterceptTouchEvent(false);

refreshScrollParentViewBase.setDispath(true);

localWigth = 0;

localHeigth = 0;

break;

}

return false;

}

别忘了scrollView 与listview 嵌套需要


@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);

super.onMeasure(widthMeasureSpec, expandSpec);

}

解决问题3

其实解决前两个问题并不需要,对SwipeMenuListView的实现方式进行很深的了解。然而如果想要SwipeMenuListView同时展开多个,便需要大致了解一下SwipeMenuListView的实现原理。

SwipeMenuListView 侧滑本身是由 SwipeMenuLayout 类中 onSwipe()的方式来进行侧滑,onSwipe()里面的实现方式是用onlayout方法进行偏移。但是我在再使用SwipeMenuListView的时候传入的是我们自己的View,它是什么时候讲我们的普通View转变成可以支持侧滑的SwipeMenuLayout的呢?

他提供了SwipeMenuAdapter ,但是我们并不直接使用,那么他的功能是什么呢。让我们看看在适配器中做了什么。


@Override

public View getView(int position, View convertView, ViewGroup parent) {

SwipeMenuLayout layout = null;

if (convertView == null) {

View contentView = mAdapter.getView(position, convertView, parent);

SwipeMenu menu = new SwipeMenu(mContext);

menu.setViewType(mAdapter.getItemViewType(position));

createMenu(menu);

SwipeMenuView menuView = new SwipeMenuView(menu,

(SwipeMenuListView) parent);

menuView.setOnSwipeItemClickListener(this);

SwipeMenuListView listView = (SwipeMenuListView) parent;

layout = new SwipeMenuLayout(contentView, menuView,

listView.getCloseInterpolator(),

listView.getOpenInterpolator());

layout.setPosition(position);

} else {

layout = (SwipeMenuLayout) convertView;

layout.closeMenu();

layout.setPosition(position);

View view = mAdapter.getView(position, layout.getContentView(),

parent);

}

if(SwipeMenuListView.is_edit)

{

layout.setSwipeDirection(1);

layout.smoothOpenMenu();

}

return layout;

}

public void createMenu(SwipeMenu menu) {

// Test Code

SwipeMenuItem item = new SwipeMenuItem(mContext);

item.setTitle("Item 1");

item.setBackground(new ColorDrawable(Color.GRAY));

item.setWidth(300);

menu.addMenuItem(item);

item = new SwipeMenuItem(mContext);

item.setTitle("Item 2");

item.setBackground(new ColorDrawable(Color.RED));

item.setWidth(300);

menu.addMenuItem(item);

}

这是一个很巧妙方式,对我们传入的adapter进行了装饰。在getview 中将我们传入的adapter.getView()得到的View 拼装出SwipeMenuLayout。并将其返回给listview.

粗略的了解了侧滑菜单的实现方式,那我们来解决我们的问题吧,到底是哪里限制了SwipeMenuListView每次只能弹出一个菜单?

在SwipeMenuListView 中声明了如下变量

private SwipeMenuLayout mTouchView;

观测其中的onTouchEvent方法,可知,这个变量便存储当前正在操作的滑动视图

打开某一个菜单有这样一种方法


public void smoothOpenMenu(int position) {

if (position >= getFirstVisiblePosition()

&& position <= getLastVisiblePosition()) {

View view = getChildAt(position - getFirstVisiblePosition());

if (view instanceof SwipeMenuLayout) {

mTouchPosition = position;

if (mTouchView != null && mTouchView.isOpen()) {

mTouchView.smoothCloseMenu();

}

mTouchView = (SwipeMenuLayout) view;

mTouchView.setSwipeDirection(mDirection);

mTouchView.smoothOpenMenu();

}

}

}

由代码可知,每次打开一个菜单,会先调用mTouchView.smoothCloseMenu这样就导致每次只能打开一个菜单。

如果我们希望能够同时打开所有菜单,可以当前listview当中所有的SwipeMenuLayout的smoothOpenMenu即可。

添加打开和关闭所有菜单的方法


public void ShowAllMenu() {

is_edit = true;

for (int i = 0; i < getChildCount(); i++) {

View view=getChildAt(i);

if (view instanceof SwipeMenuLayout) {

SwipeMenuLayout menuView = (SwipeMenuLayout) view;

if(!menuView.isOpen())

{

menuView.setSwipeDirection(mDirection);

menuView.smoothOpenMenu();

}

}

}

}

public void HideAllMenu() {

is_edit = false;

for (int i = 0; i < getChildCount(); i++) {

View view=getChildAt(i);

if (view instanceof SwipeMenuLayout) {

SwipeMenuLayout menuView = (SwipeMenuLayout) view;

if(menuView.isOpen())

{

menuView.setSwipeDirection(mDirection);

menuView.smoothCloseMenu();

}

}

}

}

is_edit变量,我说一下,由于listview中视图的复用机制。当前视图不可见时,会被回收,之后通过adapter.getView方法重新创建。因此我们要根据position去保存每个item的状态。然后在getview之后根据状态进行恢复。


if(SwipeMenuListView.is_edit)

{

layout.setSwipeDirection(1);

layout.smoothOpenMenu();

}

我的业务是要求一起开,一起关,所以一个变量即可记录,想要支持记录每个状态,可以对应存储。

最后来看一眼效果图

效果图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,454评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,553评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,921评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,648评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,770评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,950评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,090评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,817评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,275评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,592评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,724评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,409评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,052评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,815评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,043评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,503评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,627评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,845评论 25 707
  • 因为要参加P1的爱喜藕,所以买入了人生第一种token---伊藕丝,开始开启入门区块链世界之旅,虽然自己的行走速度...
    翻滚吧橘子阅读 287评论 0 0
  • 从小我都是一个内向的人,为别人着想很多,说话时都要向想好了再说出口,怕说出的话会被别人误解产生误会,也怕万一说有歧...
    一凡常心阅读 326评论 0 0
  • 一、一个概念:组合式工作。分别为连续全职,故效率会非常高。 仅仅是工作,无法填满一个人的人生。人生多样的可能性需要...
    佩芸说阅读 92评论 0 0
  • 星星铺在水面上 海鸥还在飞翔 我躺在深海里 像一条鱼 没有翅膀 下一个转弯 洞口像天坑一样 在这阳光灿烂的日子 我...
    原朔阅读 135评论 0 0