SlidingMenuVertical
Android 自定义控件之SlidingMenuVertical顶部悬浮(垂直折叠抽屉,有滑动渐变回调,可自行添加渐变动画)
Install / Use
/learn @AnJiaoDe/SlidingMenuVerticalREADME
使用方法
将libray模块复制到项目中,或者直接在build.gradle中依赖:
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
dependencies {
api 'com.github.AnJiaoDe:SlidingMenuVertical:V1.1.5'
}
注意:如果sync报错,是因为和com.android.tools.build:gradle 3.0有关, 可以改将compile改为implementation 或者api

注意:布局一定是SlidingMenuVertical包含2个直接子View
<?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.cy.translucentparent.StatusBarView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff3F51B5"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#ff3F51B5">
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="10dp"
android:scaleType="centerInside"
android:src="@drawable/back" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="抽屉"
android:textColor="#ffffff" />
<TextView
android:id="@+id/tv_switch"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:gravity="center"
android:padding="10dp"
android:text="开关"
android:textColor="#ffffff" />
</RelativeLayout>
<com.cy.slidemenuvertical.SlidingMenuVertical
android:id="@+id/slidingMenu"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#33454545"
android:text="上面面\n上面面\n上面面\n上面面\n上面面\n上面面\n上面面\n上面面\n上面面\n上面面\n上面面\n上面面\n上面面\n上面面\n上面面\n" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_middle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:text="悬浮"
android:textColor="#454545" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#e6e6e6"
android:overScrollMode="never"
android:scrollbars="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="下面\n下面\n下面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n下面\n菜逼" />
</ScrollView>
</LinearLayout>
</com.cy.slidemenuvertical.SlidingMenuVertical>
</LinearLayout>
public abstract class BaseActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StatusNavUtils.setStatusBarColor(this,0x00000000);
}
public void startAppcompatActivity(Class<?> cls) {
startActivity(new Intent(this, cls));
}
}
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv_middle = (TextView) findViewById(R.id.tv_middle);
final SlidingMenuVertical slidingMenuVertical = ((SlidingMenuVertical) findViewById(R.id.slidingMenu));
slidingMenuVertical.setDuration_max(300);//设置 设置松手后 开闭最长过渡时间
slidingMenuVertical.setAmbit_scroll(100);//修改滑动界限 值,值越大 开闭越难 单位ms
slidingMenuVertical.setOnSwitchListener(new SlidingMenuVertical.OnSwitchListener() {
/*
滑动中
y_now:实时view_bottom的top y, y_opened:抽屉打开时view_bootom的top y,y_closed:抽屉关闭时view_bottom的top y top y:在屏幕中的top y坐标
*/
@Override
public void onSwitching(boolean isToOpen, int y_now, int y_opened, int y_closed) {
tv_middle.setBackgroundColor(Color.argb((int) (1.0f * (y_opened - y_now) / (y_opened - y_closed) * 255),
Color.red(0xff3F51B5), Color.green(0xff3F51B5), Color.blue(0xff3F51B5)));
tv_middle.setTextColor(Color.argb((int) (1.0f * (y_opened - y_now) / (y_opened - y_closed) * 255),
Color.red(0xffffffff), Color.green(0xffffffff), Color.blue(0xffffffff)));
}
@Override
public void onSwitched(boolean opened) {
if (opened) {
tv_middle.setBackgroundColor(0xffffffff);
tv_middle.setTextColor(0xff454545);
}
}
});
findViewById(R.id.tv_switch).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
slidingMenuVertical.open(!slidingMenuVertical.isOpened());
}
});
}
@Override
public void onClick(View v) {
}
}
源码
SlidingMenuVertical
public class SlidingMenuVertical extends LinearLayout {
private Scroller mScroller;
private View view_top;
private View view_bottom;
private float downX;
private float downY;
private boolean opened = true;//状态是否开闭
private OnSwitchListener onSwitchListener;
private int duration_max = 300;//最长过度时间
private int ambit_scroll = 100;//滑动界限,开闭
private int y_opened = -1; // * y_opened:抽屉打开时view_bootom的top y
public SlidingMenuVertical(Context context) {
this(context, null);
}
public SlidingMenuVertical(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
setOrientation(VERTICAL);
}
@Override
protected void onFinishInflate() {
// 当xml解析完成时的回调
view_top = getChildAt(0);
view_bottom = getChildAt(1);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
view_top.measure(widthMeasureSpec, ViewMeasureUtils.getChildHeightMeasureSpec(view_top, heightMeasureSpec));
// view_middle.measure(widthMeasureSpec,ViewMeasureUtils.getChildHeightMeasureSpec(view_middle,heightMeasureSpec));
view_bottom.measure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
setY_opened();
// 拦截
// 竖直滑动时,去拦截
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
float moveX = event.getX();
float moveY = event.getY();
// 竖直滑动
if (Math.abs(moveY - downY) > Math.abs(moveX - downX)) {
//上面隐藏
if (opened == false) {
return false;
}
//上面显示并且下滑
if (opened == true && (moveY - downY) > 0) {
return false;
}
return true;
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
float moveX = event.getX();
float moveY = event.getY();
int dy = (int) (downY - moveY + 0.5f);// 四舍五入 20.9 + 0.5-->20
// Log.e("dy","++++++++++++++++++++++++++++"+dy);
int scrollY = getScrollY();
//mDownY - moveY>0上滑
if (scrollY + dy > 0) {
scrollBy(0, dy);
if (scrollY + dy > getHeight_top()) {
scrollTo(0, getHeight_top());
}
}
downX = moveX;
down
