[Android UI控件] AndroidSlidingUpPanel 分析

本文详细分析了 umano 的 SlidingUpPanelLayout 控件,这是一个开源的 Android 滑动面板布局,具有流畅的效果。文章介绍了控件的基本用法并提供了工程代码链接,接着深入解析了 SlidingUpPanelLayout 类的关键代码,包括滑动行为、事件处理、动画效果等。同时,还探讨了如何自定义设置面板高度、阴影、蒙层颜色等属性。
摘要由CSDN通过智能技术生成

大家好,先介绍下这个控件,是来之于umano的SlidingUpPanelLayout Open Source,效果非常赞,也很流畅。

开始前,先向大家展示下控件的效果,如下:



接下来我们分析这个控件的实现,主要是SlidingUpPanelLayout.java

public class SlidingUpPanelLayout extends ViewGroup {

    private static final String TAG = SlidingUpPanelLayout.class.getSimpleName();

    /**
     * 默认panel高度
     */
    private static final int DEFAULT_PANEL_HEIGHT = 68; // dp;

    /**
     * 默认阴影的高度
     */
    private static final int DEFAULT_SHADOW_HEIGHT = 4; // dp;

    /**
     * 默认蒙层颜色
     */
    private static final int DEFAULT_FADE_COLOR = 0x99000000;

    /**
     * 默认最低快速滑动的阀值
     */
    private static final int DEFAULT_MIN_FLING_VELOCITY = 400; // dips per second
    
    /**
     * 默认是否在mMainview上加一层蒙层
     */
    private static final boolean DEFAULT_OVERLAY_FLAG = false;
    
    /**
     * 默认定义要解析的属性
     */
    private static final int[] DEFAULT_ATTRS = new int[] {
        android.R.attr.gravity
    };

    /**
     * fling最低速度阀值
     */
    private int mMinFlingVelocity = DEFAULT_MIN_FLING_VELOCITY;

    /**
     * 蒙层颜色
     */
    private int mCoveredFadeColor = DEFAULT_FADE_COLOR;

    /**
     * 默认定义在滑动时,mMainView的偏移值
     */
    private static final int DEFAULT_PARALAX_OFFSET = 0;

    /**
     * 画蒙层的paint
     */
    private final Paint mCoveredFadePaint = new Paint();

    /**
     * 画阴影的drawable
     */
    private final Drawable mShadowDrawable;

    /**
     * slideable view折叠时的高度 单位像素
     */
    private int mPanelHeight = -1;

    /**
     * 阴影的高度
     */
    private int mShadowHeight = -1;

    /**
     * 定义mMainView的最大偏移值
     */
    private int mParalaxOffset = -1;

    /**
     * 若为true,定义slideable view向上滑动为展开
     */
    private boolean mIsSlidingUp;

    /**
     * 若为true,表示panel可以滑动
     */
    private boolean mCanSlide;

    /**
     * 若为false 表示会在mMainview上加上一层蒙层
     */
    private boolean mOverlayContent = DEFAULT_OVERLAY_FLAG;

    /**
     * 可用来拖动的view
     */
    private View mDragView;

    /**
     * 对应mDragView
     */
    private int mDragViewResId = -1;

    /**
     * 可被滑动的view
     */
    private View mSlideableView;

    /**
     * main view 一般是第一个索引的child view
     */
    private View mMainView;

    /**
     * 定义可滑动slideable view的状态
     */
    private enum SlideState {
        EXPANDED,
        COLLAPSED,
        ANCHORED,//类似锚点的功能
    }
    //记录当前slideable view的状态
    private SlideState mSlideState = SlideState.COLLAPSED;

    /**
     * 当前slideable view的滑动位置 是个比值 range[0,1] 0 = 展开, 1 = 收起
     */
    private float mSlideOffset;

    /**
     * slideable view能滑动的最大距离 单位像素
     */
    private int mSlideRange;

    /**
     * 若为true 表示不能够继续拖动
     */
    private boolean mIsUnableToDrag;

    /**
     * 一个flag 来标示是否激活滑动功能
     */
    private boolean mIsSlidingEnabled;

    /**
     * 若为true,此flag表示drag view想自己处理内部触摸事件,drag view可以水平滚动和处理点击事件
     * 默认这个值是false
     */
    private boolean mIsUsingDragViewTouchEvents;

    /**
     * 定义最低可滑动的距离 单位像素
     */
    private final int mScrollTouchSlop;

    //触摸事件down时,会记录point的x、y值
    private float mInitialMotionX;
    private float mInitialMotionY;
    
    /**
     * 锚点 有效值范围[0,1]
     */
    private float mAnchorPoint = 0.f;

    /**
     * Panel滑动动作监听
     */
    private PanelSlideListener mPanelSlideListener;

    /**
     * 辅助类 用于处理滑动的细节
     */
    private final ViewDragHelper mDragHelper;

    /**
     * 标示是否需要重新初始化
     */
    private boolean mFirstLayout = true;

    /**
     * 画main view和蒙层的区域大小
     */
    private final Rect mTmpRect = new Rect();

    /**
     * Panel滑动动作监听
     */
    public interface PanelSlideListener {
        
    	/**
    	 * 正在drag时,若有有效的滑动距离,会回调此函数
    	 * @param panel
    	 * @param slideOffset
    	 */
        public void onPanelSlide(View panel, float slideOffset);
        
        /**
         * Panel收起时回调
         * @param panel
         */
        public void onPanelCollapsed(View panel);

        /**
         * Panel展开时回调
         * @param panel
         */
        public void onPanelExpanded(View panel);

        /**
         * Panel滑到锚点时,会回调
         * @param panel
         */
        public void onPanelAnchored(View panel);
    }

    /**
     * 如果你不想实现PanelSlideListener的全部函数,可使用此
     */
    public static class SimplePanelSlideListener implements PanelSlideListener {
        @Override
        public void onPanelSlide(View panel, float slideOffset) {
        }
        @Override
        public void onPanelCollapsed(View panel) {
        }
        @Override
        public void onPanelExpanded(View panel) {
        }
        @Override
        public void onPanelAnchored(View panel) {
        }
    }

    //构造函数
    public SlidingUpPanelLayout(Context context) {
        this(context, null);
    }

    //构造函数
    public SlidingUpPanelLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    //构造函数
    public SlidingUpPanelLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        
        //兼容一些android提供的可视化工具做的处理
        if(isInEditMode()) {
            mShadowDrawable = null;
            mScrollTouchSlop = 0;
            mDragHelper = null;
            return;
        }
        
        //解析系统属性
        if (attrs != null) {
            TypedArray defAttrs = context.obtainStyledAttributes(attrs, DEFAULT_ATTRS);

            if (defAttrs != null) {
                int gravity = defAttrs.getInt(0, Gravity.NO_GRAVITY);
                if (gravity != Gravity.TOP && gravity != Gravity.BOTTOM) {
                    throw new IllegalArgumentException("gravity must be set to either top or bottom");
                }
                mIsSlidingUp = gravity == Gravity.BOTTOM;
            }

            defAttrs.recycle();

            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingUpPanelLayout);

            //解析自定义的属性
            if (ta != null) {
                mPanelHeight = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_panelHeight, -1);
                mShadowHeight = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_shadowHeight, -1);
                mParalaxOffset = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_paralaxOffset, -1);

                mMinFlingVelocity = ta.getInt(R.styleable.SlidingUpPanelLayout_flingVelocity, DEFAULT_MIN_FLING_VELOCITY);
                mCoveredFadeColor = ta.getColor(R.styleable.SlidingUpPanelLayout_fade
AndroidSlidingUpPanel 是一个上拉面板, 就是向上滑动的时候往上飞出一个显示面板控件, 该库效果在 Google Music, Google Maps and Rdio等 App 中用到。 效果图: 用法:使用com.sothree.slidinguppanel.SlidingUpPanelLayout作为您的活动布局的根元素。 布局必须设置为顶部或底部。请确保它有两个元素。 第一个元素是你的主要布局。第二个元素是你的向上滑动面板布局。 主要布局应当具有的宽度和高度设置为match_parent。 滑动的布局的宽度应设置为match_parent;高度应设置为match_parent,WRAP_CONTENT或最大desireable高度。 如果您想定义高度屏幕为percetange,可将其设置为match_parent,滑动视图定义为layout_weight属性。  默认情况下,整个面板将作为拖动区域和将截获的点击和拖动事件。可以通过使用setDragView方法或umanoDragView属性限制牵引区到特定的图。 想了解更多信息,请参考示例代码:<com.sothree.slidinguppanel.SlidingUpPanelLayout     xmlns:sothree="http://schemas.android.com/apk/res-auto"     android:id="@ id/sliding_layout"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:gravity="bottom"     sothree:umanoPanelHeight="68dp"     sothree:umanoShadowHeight="4dp">     <TextView         android:layout_width="match_parent"         android:layout_height="match_parent"         android:gravity="center"         android:text="Main Content"         android:textSize="16sp" />     <TextView         android:layout_width="match_parent"         android:layout_height="match_parent"         android:gravity="center|top"         android:text="The AwesomSliding Up Panel"         android:textSize="16sp" /> </com.sothree.slidinguppanel.SlidingUpPanelLayout>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值