赞
踩
在supportV4中有一个侧滑的View叫做DrawerLayout,支持左右滑动。最近项目中刚好有一个下向上滑动的组件需求,所以参考了一个改实现,打造了一个上下滑动的组件,发现代码简易,值得分享出来供大家参考。
需求简述:实现一个滑动底部滑块,展开的容器控件,滑块自身内容自行定制。上滑动展开,下滑动关闭,点击开关进行对应的展开关闭。关键点:
根据需求,我们可以简易列出实现过程中的几个关键点(辅助如图)
1、ViewGroup内部进行测量子控件;
2、外部提供一个关闭后的展开高度
3、提供开启关闭的回调
4、提供绑定滑动的区域
package com.owant.space.view; import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.TypedArray; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import com.owant.space.R; /** * created by Kyle.Zhong on 2020-04-07 */ public class DrawerVerticalLayout extends FrameLayout { public interface LayoutOpenCloseListener { void onClosed(); void onOpened(); } private View shadowView; private ViewGroup slipBoxView; private View touchBar; private int closeHeight; private float slipBoxViewTransY = 0; public int height; public int minTop; public int maxTop; private boolean isClose = true; private LayoutOpenCloseListener layoutOpenCloseListener; public DrawerVerticalLayout(Context context) { this(context, null); } public DrawerVerticalLayout(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public DrawerVerticalLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray = context .obtainStyledAttributes(attrs, R.styleable.DrawerVerticalLayout); closeHeight = typedArray .getDimensionPixelSize(R.styleable.DrawerVerticalLayout_closeHeight, 200); typedArray.recycle(); } public void setLayoutOpenCloseListener( LayoutOpenCloseListener layoutOpenCloseListener) { this.layoutOpenCloseListener = layoutOpenCloseListener; } @Override protected void onFinishInflate() { super.onFinishInflate(); int childCount = getChildCount(); if (childCount != 2) { throw new IllegalStateException("DrawerVerticalLayout必须添加两个子View"); } shadowView = getChildAt(0); shadowView.setVisibility(INVISIBLE); slipBoxView = (ViewGroup) getChildAt(1); touchBar = findViewById(R.id.drawer_touch_bar); if (touchBar == null) { throw new IllegalStateException( "DrawerVerticalLayout必须添加一个为R.id.drawer_touch_bar的拖动View"); } touchBar.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return onTouchBar(v, event); } }); } float currentY; float startTouchY; public boolean isClose() { return isClose; } public void setClose(boolean close) { if (close == isClose) { return; } if (close) { boxClose(); } else { boxOpen(); } isClose = close; } private boolean onTouchBar(View v, MotionEvent event) { int action = event.getAction(); float rawY = event.getRawY(); switch (action) { case MotionEvent.ACTION_DOWN: currentY = rawY; slipBoxViewTransY = slipBoxView.getTranslationY(); startTouchY = rawY; break; case MotionEvent.ACTION_MOVE: shadowView.setVisibility(VISIBLE); float dY = rawY - currentY; float resultY = slipBoxViewTransY + dY; if (resultY <= minTop) { resultY = minTop; } if (resultY >= maxTop) { resultY = maxTop; } slipBoxView.setTranslationY(resultY); break; case MotionEvent.ACTION_UP: currentY = rawY; if (currentY > startTouchY) { isClose = true; boxClose(); } else { isClose = false; boxOpen(); } break; default: break; } return true; } public void boxOpen() { ObjectAnimator openAnimator = ObjectAnimator .ofFloat(slipBoxView, "translationY", slipBoxViewTransY, minTop); long time = (long) ((slipBoxViewTransY - minTop) / ((maxTop - minTop) * 1.0) * 400L); openAnimator.setDuration(time); openAnimator.start(); shadowView.setVisibility(VISIBLE); if (layoutOpenCloseListener != null) { layoutOpenCloseListener.onOpened(); } } public void boxClose() { ObjectAnimator closeAnimator = ObjectAnimator .ofFloat(slipBoxView, "translationY", slipBoxViewTransY, maxTop); long time = (long) ((maxTop - slipBoxViewTransY) / ((maxTop - minTop) * 1.0) * 400L); closeAnimator.setDuration(time); closeAnimator.start(); shadowView.setVisibility(INVISIBLE); if (layoutOpenCloseListener != null) { layoutOpenCloseListener.onClosed(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int boxViewHeight = slipBoxView.getMeasuredHeight(); height = getMeasuredHeight(); slipBoxViewTransY = 0; minTop = 0; maxTop = boxViewHeight - closeHeight; FrameLayout.LayoutParams layoutParams = (LayoutParams) slipBoxView.getLayoutParams(); layoutParams.gravity = Gravity.BOTTOM; slipBoxView.setLayoutParams(layoutParams); if (isClose) { slipBoxView.setTranslationY(maxTop); } else { shadowView.setVisibility(VISIBLE); } } }
测试布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" > <com.owant.space.view.DrawerVerticalLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" android:orientation="vertical" app:closeHeight="200dp" app:openMarginTop="20dp" > <View android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="#ff0f0f" /> <LinearLayout android:layout_width="match_parent" android:layout_height="600dp" android:orientation="vertical" > <Button android:id="@+id/drawer_touch_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="hallo" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="hallo" /> </LinearLayout> </com.owant.space.view.DrawerVerticalLayout> </LinearLayout>
主要使用了ObjectAnimator进行滑动,采用Id进行绑定滑动区域。使用起来便捷爽快。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。