自定义下拉能露出背景的RelativeLayout(FrameLayout)之想朋友圈那样下拉能露出背景的功能

自定义下拉能露出背景的RelativeLayout(FrameLayout)之想朋友圈那样下拉能露出背景的功能,

只要是能滚动的view,用该自定义view包裹着都能实现下拉露出背景功能(上拉按照同一套路是实现即可);

就是不太明白对于原来就不能滚动的View不起作用,希望路过知道的大神,能提醒一下要点;


废话不多说,直接上代码:效果图不上了;


package demo.com.customviewdemo.customview;

import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.ListView;
import android.widget.RelativeLayout;

import java.util.ArrayList;

/**
 * Created by Alv_chi.
 */
public class MyDraggableRelativeLayout extends RelativeLayout {


    private static final String TAG = "Test";
    private int childCount;
    private float downY;
    private float moveY;

    private View firstContentView;

    private boolean isMoved;
    private View visibleContentView;
    private ArrayList<Rect> rects;
    private ArrayList<View> views;
    private boolean isListlView;
    private boolean isNeedMoved;


    public MyDraggableRelativeLayout(Context context) {
        this(context, null);
    }

    public MyDraggableRelativeLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyDraggableRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public MyDraggableRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();//当系统加载完Xml就会调用此方法;

        childCount = getChildCount();
        Log.e(TAG, "onFinishInflate: childCount=" + childCount);
        if (childCount > 0) {
            firstContentView = getChildAt(0);//获取子view:
            if (childCount == 1) {
//                当只有一个子view时(没有背景View),该子View就是可被拉拽的子View;
                visibleContentView = this.firstContentView;
            } else {
//                当有多个子View时,默认第二个子view可拉拽子View,
//                其实当被拉拽时,除了第一个子view(背景子View)不会移动,其他所有子view都会移动;
//                因为我这里继承的是relativeLayout所以我取第一个,要是继承FrameLAyout的话,
//                  应该是取最后一个子View;
                visibleContentView = getChildAt(1);
            }

//            此处做法的原因是LIstVIew的getScrollView()方法获取到的值一直是0,
//            所以要计算出当前listView是否到达顶端,就要另辟蹊径;
            if (visibleContentView instanceof ListView) {
                isListlView = true;
            } else {
                isListlView = false;
            }

        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (visibleContentView == null) {
            return;
        }
        rects = new ArrayList<>();
        views = new ArrayList<>();

        for (int i = 0; i < childCount; i++) {
//        将原来每个view对应的位置纪录下来,用于下面view恢复原来位置用的;
            View childView = getChildAt(i);
            views.add(childView);
            rects.add(new Rect(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom()));
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downY = ev.getY();//纪录按下位置
                break;
            case MotionEvent.ACTION_MOVE:

                if (visibleContentView != null) {
                    moveY = ev.getY();//纪录移动位置
                    float deltaY = moveY - downY;//计算Y变化值;

                    int offset = (int) (deltaY * 0.7);//变化Y值乘以阻尼系数为偏移量;

                    if (isListlView) {
                        ListView listView = (ListView) this.visibleContentView;
                        int childCount = listView.getChildCount();
                        if (childCount > 0) {
//                            判断当前的listView是否滑动到顶部;
                            isNeedMoved = listView.getFirstVisiblePosition() == 0 && deltaY > 0;
                        }
                    } else {
                        isNeedMoved = visibleContentView.getScrollY() == 0 && deltaY > 0;
                    }

                    if (isNeedMoved) {
//                       当子View数量大于1时,背景子view(第一个子View)不移动,移动其他所有子view;
                        for (int i = 0; i < childCount; i++) {
                            if (childCount > 1 && i == 0) continue;//当子View数为1时,该子view也动;

                            View childView = views.get(i);
                            Rect rect = rects.get(i);
//                            移动所要移动的子View;
                            childView.layout(rect.left, rect.top + offset, rect.right, rect.bottom + offset);
                        }

                        isMoved = true;//标记一下,移动了;
                    }
                }


                break;
            case MotionEvent.ACTION_UP:
                if (isMoved) {

                    for (int i = 0; i < childCount; i++) {
                        if (childCount > 1 && i == 0) continue;
                        final Rect rectII = rects.get(i);
                        final View childView = views.get(i);

//                        此处开线程的目的是,让动画与移动同步不延迟;
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                new Handler(Looper.getMainLooper()).post(new Runnable() {
                                    @Override
                                    public void run() {
                                        // 定义动画,准备动画;
                                        TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, childView.getTop(), rectII.top);
                                        translateAnimation.setDuration(500);
                                        translateAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
                                        translateAnimation.start();

                                        childView.setAnimation(translateAnimation);
//                                        contentView回复原位置;
                                        childView.layout(rectII.left, rectII.top, rectII.right, rectII.bottom);

                                    }
                                });
                            }
                        }).start();


                    }

                    isMoved = false;//标记一下恢复原来的位置了;
                }
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
}





//源码下载: 点击打开链接下载源码


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值