先上圖
上代碼
package com.example.jzg.mvpdemo.view;
import android.content.Context;
import android.content.res.Resources;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.example.jzg.mvpdemo.Utils.DensityUtil;
/**
* author: guochen
* date: 2017/11/11 17:57
* email:
*/
public class SeekProductMenu extends ViewGroup {
private static final String TAG = "SeekProductMenu";
private ViewDragHelper viewDragHelper;
private FrameLayout twoMenuView;
private FrameLayout threeMenuView;
private int creenWidth;
private int creenHeight;
private FrameLayout oneMenuView;
private RecyclerView oneMenuList;
private RecyclerView twoMenuList;
private int twoMenuViewWidth;
private boolean twoMenuIsOpen = false;//給二級(jí)菜單的開(kāi)關(guān)標(biāo)志
private boolean threeMenuIsOpen = false;//給二級(jí)菜單的開(kāi)關(guān)標(biāo)志
private int threeMenuViewWidth;
private RecyclerView threeMenuList;
private int twoMenuViewLeft;//二級(jí)菜單距離屏幕左邊的距離
private int threeMenuViewLeft;//三級(jí)菜單距離屏幕左邊的距離
private int dx;//down事件時(shí)的坐標(biāo)
//二級(jí)和三級(jí)菜單的開(kāi)關(guān)狀態(tài)
private static final int ALL_CLOSE = 0;//二級(jí)菜單和三級(jí)菜單都處于關(guān)閉狀態(tài)
private static final int TWO_OPEN = 1;//只有二級(jí)菜單打開(kāi)
private static final int TWO_THREE_OPEN = 2;//二級(jí)菜單和三級(jí)菜單都打開(kāi)是的狀態(tài)
private int nowState = ALL_CLOSE;//當(dāng)前處于的狀態(tài) //3
private int threeMenuLeftAxis;
private int twoMenuLeftAxis;
private Context context;
private ViewDragHelper viewDragHelper2;
private int downY;
public SeekProductMenu(Context context) {
this(context, null);
}
public SeekProductMenu(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
// 獲取 viewDragHelper實(shí)例
viewDragHelper = ViewDragHelper.create(this, new MyCallBack());
viewDragHelper2 = ViewDragHelper.create(this, new MyCallBack());
//獲取屏幕寬高
int[] creenSize = getScreenSize();
//寬
creenWidth = creenSize[0];
//高
creenHeight = creenSize[1];
}
/**
* 該方法在布局文件加載完畢后被回調(diào)
*/
@Override
protected void onFinishInflate() {
//獲取一級(jí)菜單實(shí)例
oneMenuView = (FrameLayout) getChildAt(0);
oneMenuList = (RecyclerView) oneMenuView.getChildAt(0);
//獲取二級(jí)菜單實(shí)例
twoMenuView = (FrameLayout) getChildAt(1);
twoMenuList = (RecyclerView) twoMenuView.getChildAt(0);
//獲取三級(jí)菜單實(shí)例
threeMenuView = (FrameLayout) getChildAt(2);
threeMenuList = (RecyclerView) threeMenuView.getChildAt(0);
}
/**
* 測(cè)量子視圖
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//測(cè)量一級(jí)菜單
oneMenuView.measure(widthMeasureSpec, heightMeasureSpec);
//測(cè)量二級(jí)菜單
//設(shè)置二級(jí)菜單為屏幕的4/5寬
twoMenuViewWidth = (int) (creenWidth * 0.8 + 0.5) + 20;
int twoMenuViewWidthSpec = MeasureSpec.makeMeasureSpec(twoMenuViewWidth, MeasureSpec.EXACTLY);
twoMenuView.measure(twoMenuViewWidthSpec, heightMeasureSpec);
//測(cè)量三級(jí)菜單
//設(shè)置三級(jí)菜單為屏幕的3/5
threeMenuViewWidth = (int) (creenWidth * 0.55 + 0.5) + 30;
int threeMenuViewWidthSpec = MeasureSpec.makeMeasureSpec(threeMenuViewWidth, MeasureSpec.EXACTLY);
threeMenuView.measure(threeMenuViewWidthSpec, heightMeasureSpec);
//設(shè)置視圖本身
setMeasuredDimension(creenWidth, creenHeight);
}
/**
* 給子視圖布局
*
* @param b
* @param i
* @param i1
* @param i2
* @param i3
*/
@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
//給一級(jí)菜單布局
oneMenuView.layout(0, 0, creenWidth, creenHeight);
//給二級(jí)菜單布局
if (nowState != TWO_OPEN && nowState != TWO_THREE_OPEN) {
twoMenuView.layout(creenWidth, 0, creenWidth + twoMenuViewWidth, creenHeight);
} else {
twoMenuView.layout((int) (creenWidth * 0.2 + 0.5) - 20, 0, creenWidth, creenHeight);
}
if (nowState != TWO_THREE_OPEN) {
//給三級(jí)菜單布局
threeMenuView.layout(creenWidth, 0, creenWidth + threeMenuViewWidth, creenHeight);
} else {
threeMenuView.layout((int) (creenWidth * 0.45 + 0.5), 0, creenWidth, creenHeight);
}
}
/**
* 重寫(xiě)onInterceptTouchEvent自定義事件攔截規(guī)則
*
* @param ev
* @return
*/
int downX = 0;
/**
* 自定義事件分發(fā)
*
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = dx = (int) (ev.getX() + 0.5f);
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
//判斷當(dāng)用戶左右滑動(dòng)的時(shí)候攔截子視圖事件(也就是當(dāng)用戶左右滑動(dòng)的時(shí)候攔截ListView的事件走自己的事件)
//上下滑動(dòng)或者點(diǎn)擊的時(shí)候走ListView的事件
int moveY = (int) ev.getY();
int moveX = (int) (ev.getX() + 0.5f);
int moveDistanceX = (downX - moveX) > 0 ? (downX - moveX) : (moveX - downX);
int moveDistanceY = (downY - moveY) > 0 ? (downY - moveY) : (moveY - downY);
//當(dāng)上下滑動(dòng)時(shí)电湘,不攔截事件,走ListView的事件
if (moveDistanceY > 20) {
return false;
}
//當(dāng)左右滑動(dòng)的時(shí)候鹅经,攔截子控件事件寂呛,也就是攔截ListView的事件,走自己的左右滑動(dòng)事件
if (moveDistanceX > 10 && moveDistanceY < 20) {
downX = (int) (ev.getX() + 0.5f);
return true;
}
break;
}
return false;
}
/**
* 重寫(xiě)onTouchEvent自定義滑動(dòng)事件
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
View view = getTouchView(event, downX); //獲取被觸摸到的View
slideEvent(event, view); //處理被觸摸到的View的滑動(dòng)事件
break;
case MotionEvent.ACTION_UP:
switch (nowState) {
case TWO_THREE_OPEN:
/**
* 當(dāng)二級(jí)菜單和三級(jí)菜單都處于打開(kāi)狀態(tài)時(shí)的事件處理
*/
if (getTouchView(event, downX) == threeMenuView) {//當(dāng)二級(jí)菜單和三級(jí)菜單都處于打開(kāi)狀態(tài)瞬雹,并且手指觸摸到的是三級(jí)菜單時(shí)的事件處理
if (threeMenuViewLeft < creenWidth / 2 + DensityUtil.px2dip(context, 50)) {
viewDragHelper.smoothSlideViewTo(threeMenuView, (int) (creenWidth * 0.45 + 0.5), 0);
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
threeMenuViewLeft = (int) (creenWidth * 0.45 + 0.5);
threeMenuIsOpen = true;
nowState = TWO_THREE_OPEN;
} else {
viewDragHelper.smoothSlideViewTo(threeMenuView, creenWidth, 0);
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
threeMenuIsOpen = false;
nowState = TWO_OPEN;
threeMenuViewLeft = creenWidth;
//接口回調(diào)昧谊,監(jiān)聽(tīng)菜單被關(guān)閉時(shí),恢復(fù)菜單item默認(rèn)背景顏色
// //恢復(fù)二級(jí)菜單item默認(rèn)背景顏色
if (recoverListViewItemBackground != null) {
recoverListViewItemBackground.onRecoverTwoListViewItemBackgroundListener();
}
}
} else if (getTouchView(event, downX) == twoMenuView) {
//當(dāng)二級(jí)菜單和三級(jí)菜單都處于打開(kāi)狀態(tài)酗捌,并且手指觸摸到的是二級(jí)菜單時(shí)的事件處理
if (twoMenuViewLeft < creenWidth / 2) {
viewDragHelper.smoothSlideViewTo(twoMenuView, (int) (creenWidth * 0.2 + 0.5) - 20, 0);
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
viewDragHelper2.smoothSlideViewTo(threeMenuView, (int) (creenWidth * 0.45 + 0.5), 0);
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
twoMenuViewLeft = (int) (creenWidth * 0.2 + 0.5);
threeMenuViewLeft = (int) (creenWidth * 0.45 + 0.5);
threeMenuIsOpen = true;
twoMenuIsOpen = true;
nowState = TWO_THREE_OPEN;
} else {
viewDragHelper.smoothSlideViewTo(twoMenuView, creenWidth, 0);
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
viewDragHelper2.smoothSlideViewTo(threeMenuView, creenWidth + DensityUtil.px2dip(context, 300), 0);
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
twoMenuViewLeft = creenWidth;
threeMenuViewLeft = creenWidth;
threeMenuIsOpen = false;
twoMenuIsOpen = false;
nowState = ALL_CLOSE;
//接口回調(diào)呢诬,監(jiān)聽(tīng)菜單被關(guān)閉時(shí),恢復(fù)菜單item默認(rèn)背景顏色
//恢復(fù)一級(jí)菜單item默認(rèn)背景顏色
if (recoverListViewItemBackground != null) {
recoverListViewItemBackground.onRecoverOneListViewItemBackgroundListener();
}
}
}
break;
case TWO_OPEN:
/**
* 當(dāng)只有二級(jí)菜單處于打開(kāi)狀態(tài)并且三級(jí)菜單處于關(guān)閉狀態(tài)時(shí)的事件處理
*/
if (getTouchView(event, downX) == twoMenuView) { //當(dāng)手指觸摸到的是二級(jí)菜單時(shí)的事件處理
if (twoMenuViewLeft < creenWidth / 2) {
viewDragHelper.smoothSlideViewTo(twoMenuView, (int) (creenWidth * 0.2 + 0.5) - 20, 0);
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
twoMenuViewLeft = (int) (creenWidth * 0.2 + 0.5);
twoMenuIsOpen = true;
nowState = TWO_OPEN;
} else {
viewDragHelper.smoothSlideViewTo(twoMenuView, (int) creenWidth, 0);
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
viewDragHelper2.smoothSlideViewTo(threeMenuView, (int) creenWidth + DensityUtil.dip2px(context, 300), 0);
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
twoMenuViewLeft = creenWidth;
twoMenuIsOpen = false;
nowState = ALL_CLOSE;
//接口回調(diào)胖缤,監(jiān)聽(tīng)菜單被關(guān)閉時(shí)尚镰,恢復(fù)菜單item默認(rèn)背景顏色
//恢復(fù)一級(jí)菜單item默認(rèn)背景顏色
if (recoverListViewItemBackground != null) {
recoverListViewItemBackground.onRecoverOneListViewItemBackgroundListener();
}
}
}
}
}
return super.onTouchEvent(event);
}
/**
* 滑動(dòng)事件處理
*
* @param ev MotionEvent
* @param child 被觸摸到的View
* @return 返回被觸摸到的View距離屏幕左邊的距離
*/
public int slideEvent(MotionEvent ev, View child) {
int moveX = (int) (ev.getX() + 0.5);//滑動(dòng)后的X坐標(biāo)
int slideDistance = downX - moveX;//滑動(dòng)的距離
//如果被觸摸到的View是二級(jí)菜單并且只有二級(jí)菜單處于打開(kāi)狀態(tài)時(shí)
if (child == twoMenuView && nowState == TWO_OPEN) {
//計(jì)算二級(jí)菜單移動(dòng)的位置
twoMenuLeftAxis = twoMenuViewLeft - slideDistance;
//邊界限定
twoMenuLeftAxis = Math.max((int) (creenWidth * 0.2 + 0.5) - 20, twoMenuLeftAxis);
//重新布局
twoMenuView.layout(twoMenuLeftAxis, 0, creenWidth + twoMenuLeftAxis, creenHeight);
downX = (int) (ev.getX() + 0.5f);
twoMenuViewLeft = twoMenuLeftAxis;
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
return twoMenuViewLeft;
} else if (child == twoMenuView && nowState == TWO_THREE_OPEN) {
/**
* 這種情況是當(dāng)手指觸摸到二級(jí)菜單并且三級(jí)菜單也是打開(kāi)狀態(tài)時(shí)
*/
//計(jì)算二級(jí)菜單移動(dòng)的位置
int twoMenuLeftAxis = twoMenuViewLeft - slideDistance;
//計(jì)算三級(jí)菜單到屏幕左邊的距離
threeMenuLeftAxis = threeMenuViewLeft - slideDistance;
//二級(jí)菜單邊界限定
twoMenuLeftAxis = Math.max((int) (creenWidth * 0.2 + 0.5) - 20, twoMenuLeftAxis);
//三級(jí)菜單邊界限定
threeMenuLeftAxis = Math.max((int) (creenWidth * 0.45 + 0.5), threeMenuLeftAxis);
//重新布局
twoMenuView.layout(twoMenuLeftAxis, 0, creenWidth + twoMenuLeftAxis, creenHeight);
threeMenuView.layout(threeMenuLeftAxis, 0, creenWidth + threeMenuLeftAxis, creenHeight);
downX = (int) (ev.getX() + 0.5f);
twoMenuViewLeft = twoMenuLeftAxis;
threeMenuViewLeft = threeMenuLeftAxis;
} else if (child == threeMenuView) {
threeMenuLeftAxis = threeMenuViewLeft - slideDistance;
//三級(jí)菜單邊界限定
threeMenuLeftAxis = Math.max((int) (creenWidth * 0.45 + 0.5), threeMenuLeftAxis);
threeMenuView.layout(threeMenuViewLeft - slideDistance, 0, creenWidth + threeMenuLeftAxis, creenHeight);
downX = (int) (ev.getX() + 0.5f);
threeMenuViewLeft = threeMenuLeftAxis;
}
return 0;
}
/**
* 獲取當(dāng)手指按下時(shí)觸摸到的子視圖,用于用戶手指按下觸摸到的是那個(gè)菜單
* 當(dāng)在down事件時(shí)調(diào)用該方法
*
* @param ev
* @param dx
* @return
*/
public View getTouchView(MotionEvent ev, int dx) {
if (!twoMenuIsOpen && !threeMenuIsOpen) {
//當(dāng)二級(jí)菜單和三級(jí)菜單都處于關(guān)閉狀態(tài)時(shí)
nowState = ALL_CLOSE;
return oneMenuView;
} else if (twoMenuIsOpen && !threeMenuIsOpen) {
//當(dāng)二級(jí)菜單處于打開(kāi)并且三級(jí)菜單處于關(guān)閉時(shí)
nowState = TWO_OPEN;
return dx < twoMenuViewLeft ? oneMenuView : twoMenuView;
} else if (twoMenuIsOpen && threeMenuIsOpen) {
nowState = TWO_THREE_OPEN;
if (dx < twoMenuViewLeft) {
return oneMenuView;
} else if (dx > twoMenuViewLeft && threeMenuViewLeft > dx) {
return twoMenuView;
} else if (dx > threeMenuViewLeft) {
return threeMenuView;
}
}
return null;
}
/**
* 獲取手機(jī)屏幕寬高
*
* @return
*/
public int[] getScreenSize() {
Resources resources = this.getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
int width = dm.widthPixels;//獲得的是PX 需轉(zhuǎn)換為dp
int height = dm.heightPixels;
int[] ScreenSize = {width, height};
return ScreenSize;
}
@Override
public void computeScroll() {
//是否固定
if (viewDragHelper.continueSettling(true)) {
//該方法作用和invalidate()一樣,但是用invalidate()方法有的機(jī)型沒(méi)有效果哪廓,所以建議使用以下方法
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
}
if (viewDragHelper2.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
}
}
/**
* 當(dāng)二級(jí)菜單和三級(jí)菜單都關(guān)閉時(shí)狗唉,點(diǎn)擊listView item 相應(yīng)的事件
*/
public void OnClickOneMenu() {
if (nowState == TWO_THREE_OPEN) {
viewDragHelper.smoothSlideViewTo(threeMenuView, creenWidth + 10, 0);
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
threeMenuViewLeft = creenWidth + DensityUtil.dip2px(context, 10);
twoMenuIsOpen = true;
threeMenuIsOpen = false;
nowState = TWO_OPEN;
return;
}
twoMenuViewLeft = (int) (creenWidth * 0.2 + 0.5) - 20;//獲取屏幕的1/5
viewDragHelper.smoothSlideViewTo(twoMenuView, twoMenuViewLeft, 0);
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
twoMenuIsOpen = true;//當(dāng)前為二級(jí)菜單打開(kāi)狀態(tài),打上標(biāo)志
nowState = TWO_OPEN;
}
/**
* 點(diǎn)擊二級(jí)菜單是相應(yīng)的事件
*/
public void OnClickTwoMenu() {
threeMenuViewLeft = (int) (creenWidth * 0.45 + 0.5);
viewDragHelper.smoothSlideViewTo(threeMenuView, threeMenuViewLeft, 0);
ViewCompat.postInvalidateOnAnimation(SeekProductMenu.this);
threeMenuIsOpen = true;//標(biāo)注三級(jí)菜單為打開(kāi)狀態(tài)
nowState = TWO_THREE_OPEN;
}
class ViewHolder {
TextView textView;
}
class MyCallBack extends ViewDragHelper.Callback {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return true;
}
}
private RecoverListViewItemBackground recoverListViewItemBackground;
public void setOnRecoverListViewItemBackgroundListener(RecoverListViewItemBackground recoverListViewItemBackground) {
this.recoverListViewItemBackground = recoverListViewItemBackground;
}
/**
* 接口回調(diào)恢復(fù)listView item的背景顏色
*/
public interface RecoverListViewItemBackground {
void onRecoverOneListViewItemBackgroundListener();//恢復(fù)一級(jí)菜單item默認(rèn)背景回調(diào)
void onRecoverTwoListViewItemBackgroundListener();//恢復(fù)二級(jí)菜單item默認(rèn)背景回調(diào)
}
private ListViewChangeListener listViewChangeListener;
public void setOnListViewChangeListener(ListViewChangeListener listViewChangeListener) {
this.listViewChangeListener = listViewChangeListener;
}
public interface ListViewChangeListener {
void threeListViewChangeListener(boolean isOpen);
void twoListViewChangeListener(boolean isOpen);
}
}
上布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.jzg.mvpdemo.view.SeekProductMenu
android:id="@+id/seek"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/green_wathet_textcolor">
<android.support.v7.widget.RecyclerView
android:id="@+id/make_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/login_btn_clr">
<android.support.v7.widget.RecyclerView
android:id="@+id/model_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/zi_wathet_textcolor">
<android.support.v7.widget.RecyclerView
android:id="@+id/style_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
</FrameLayout>
</com.example.jzg.mvpdemo.view.SeekProductMenu>
<com.example.jzg.mvpdemo.view.LetterBarView
android:id="@+id/index_list"
android:layout_width="30dip"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:layout_marginBottom="2dip"
android:layout_marginTop="2dip"
android:background="#40000000"></com.example.jzg.mvpdemo.view.LetterBarView>
</RelativeLayout>