当前位置:   article > 正文

实现一个底部上滑出的ViewGroup_widget.drawerlayout 底部划出

widget.drawerlayout 底部划出

在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);
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193

测试布局

<?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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

结论

主要使用了ObjectAnimator进行滑动,采用Id进行绑定滑动区域。使用起来便捷爽快。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/279762
推荐阅读
相关标签
  

闽ICP备14008679号