利用DragTopLayout实现上下两部分页面整体滑动,不影响下面部分页面的滚动效果

最近做了个个人中心的页面,上面部分显示头像昵称,标签,以及关注数和粉丝数,下面部分显示发表的帖子列表,下面部分是用H5做的,是带着下拉刷新上拉加载功能的列表页,要求向上滑动时,上面信息部分和下面的帖子列表部分要整体滑动,当信息部分滑动到不可见时,下面的帖子列表要也能上下滑动,并能上拉加载。

直接用scrollview的话,不管怎么自定义,要么是上下可以整体滑动,但上拉加载下拉刷新的功能不可用,要么就是滑动卡得要命。怎么都不好用。

在网上查了几天的资料,换了好几种方法终于搞定。

效果:


具体实现如下:

利用DragTopLayout这个开源控件可以轻松实现:

代码:

package com.h.fileinput.widget;

import android.content.Context;
import android.graphics.PointF;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.widget.AbsListView;
import android.widget.FrameLayout;
import android.widget.Scroller;

/**
 * Created by Administrator on 2017/6/6 0006.
 * 上下整体滑动的布局
 */

public class DragTopLayout extends FrameLayout {
    public DragTopLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

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

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

    private void init() {
        mScroller = new Scroller(getContext().getApplicationContext());
    }

    /**
     * 当前头部可见还是滚出屏幕,true为滚出屏幕
     */
    private boolean mCollapsed = false;
    /**
     * 头部高度
     */
    private int mHeadHeight;

    /**
     * 滚动辅助
     */
    private Scroller mScroller;

    /**
     * 速度计算,每次用完要recycle
     */
    private VelocityTracker velocityTracker;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);

        mHeadHeight = getChildAt(0).getMeasuredHeight();

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
                            int bottom) {
        View v1 = getChildAt(0);
        v1.layout(0, 0, v1.getMeasuredWidth(), v1.getMeasuredHeight());

        View v2 = getChildAt(1);
        v2.layout(0, v1.getMeasuredHeight(), getMeasuredWidth(),
                getMeasuredHeight() + mHeadHeight);
    }


    /**
     * 按下点,滑动过程中的上一个点
     */
    private PointF mDownPoint = new PointF();

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDownPoint.set(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                float y = event.getY();
                // Y方向需要scrollBy的距离,正值表示需要向上滚动
                float scrollByDelt = -y + mDownPoint.y;
                // 假如按照计算的距离偏移后的偏移量,即getScrollY()的值
                float realDelt = getScrollY() + scrollByDelt;
                Log.e("lzw", "------> " + scrollByDelt + "  " + realDelt);
                if (realDelt < 0) { // 表示按照实际的手指滑动距离向下移动的话太大,则直接计算出刚好头部显示出来的realDelt
                    scrollByDelt = 0 - getScrollY();
                } else if (realDelt > mHeadHeight) { // 同样表示实际距离太大,计算出合适的距离
                    scrollByDelt = mHeadHeight - getScrollY();
                }
                scrollBy(0, (int) scrollByDelt);
                mDownPoint.set(event.getX(), y);
                break;
            case MotionEvent.ACTION_UP:
                mDownPoint.set(0, 0);
                checkPosition();
                break;
        }
        return true;
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        Log.e("lzw", "onInterceptTouchEvent canChildScrollUp " + canChildScrollUp());
        if (canChildScrollUp()) { // 能向上滚动,一定是滚动view处理事件
            return false;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDownPoint.set(event.getX(), event.getY());
                return false;
            case MotionEvent.ACTION_MOVE:
                // 横向滚动大于纵向,也不响应
                if (Math.abs(event.getX() - mDownPoint.x) > Math.abs(event.getY()
                        - mDownPoint.y)) {
                    mDownPoint.set(event.getX(), event.getY());
                    return super.onInterceptTouchEvent(event);
                }
                // 在向下移动
                if (event.getY() > mDownPoint.y) {
                    mDownPoint.set(event.getX(), event.getY());
                    if (mCollapsed) { // 头部不可见了,向下滚动需要拦截
                        return true;
                    } else {
                        return super.onInterceptTouchEvent(event);
                    }
                }
                // 在向上移动
                if (event.getY() < mDownPoint.y) {
                    mDownPoint.set(event.getX(), event.getY());
                    if (mCollapsed) { // 头部滚出屏幕,不拦截
                        return super.onInterceptTouchEvent(event);
                    } else {
                        return true;
                    }
                }
                mDownPoint.set(event.getX(), event.getY());
            case MotionEvent.ACTION_UP:
                // 检查头部是否移除去
                mCollapsed = getScrollY() >= mHeadHeight;
                mDownPoint.set(event.getX(), event.getY());
                return super.onInterceptTouchEvent(event);
        }
        return true;
    }

    @Override
    public void requestDisallowInterceptTouchEvent(boolean b) {
        // if this is a List < L or another view that doesn't support nested
        // scrolling, ignore this request so that the vertical scroll event
        // isn't stolen
        if ((android.os.Build.VERSION.SDK_INT < 21 && mTarget instanceof AbsListView)
                || (mTarget != null && !ViewCompat.isNestedScrollingEnabled(mTarget))) {
            // Nope.
        } else {
            super.requestDisallowInterceptTouchEvent(b);
        }
    }

    /**
     * @return Whether it is possible for the child view of this layout to
     *         scroll up. Override this if the child view is a custom view.
     */
    public boolean canChildScrollUp() {
        if (android.os.Build.VERSION.SDK_INT < 14) {
            if (mTarget instanceof AbsListView) {
                final AbsListView absListView = (AbsListView) mTarget;
                return absListView.getChildCount() > 0
                        && (absListView.getFirstVisiblePosition() > 0 || absListView
                        .getChildAt(0).getTop() < absListView
                        .getPaddingTop());
            } else {
                return ViewCompat.canScrollVertically(mTarget, -1)
                        || mTarget.getScrollY() > 0;
            }
        } else {
            return ViewCompat.canScrollVertically(mTarget, -1);
        }
    }

    /**
     * 检查是否需要关闭或者打开
     */
    private void checkPosition() {
        // 移出去的大小,不能直接在if里面用,否则返回值不正确
        int opOffset = getScrollY();
        if (opOffset < (mHeadHeight / 2)) {
            open();
        } else {
            close();
        }
    }

    /**
     * 向上移动,隐藏头部
     */
    private void close() {
        mCollapsed = true;
        mScroller.startScroll(0, getScrollY(), 0, mHeadHeight - getScrollY());
        invalidate();
    }

    /**
     * 向下移动,头部出现
     */
    private void open() {
        mCollapsed = false;
        mScroller.startScroll(0, getScrollY(), 0, -getScrollY());
        invalidate();
    }

    @Override
    public void computeScroll() {
        // 返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。
        if (mScroller.computeScrollOffset()) {
            // 移动位置
            scrollTo(0, mScroller.getCurrY());
            invalidate();
        }
    }

    /**
     * 可滚动view
     */
    private View mTarget;

    /**
     * 设置可滚动view
     */
    public void setTargetView(View v) {
        mTarget = v;
    }
}


布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.h.fileinput.widget.DragTopLayout
        android:id="@+id/dragLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:id="@+id/top_view"
            android:layout_width="match_parent"
            android:layout_height="220dp"
            android:background="@color/cardview_dark_background"
            android:gravity="center"
            android:orientation="vertical">
            <RelativeLayout
                android:layout_marginTop="13dp"
                android:layout_above="@+id/rl_tagHeader"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                <Button
                    android:id="@+id/btn_otherLeft"
                    android:visibility="gone"
                    android:layout_width="22dp"
                    android:layout_height="22dp"
                    android:layout_centerVertical="true"
                    android:layout_marginLeft="15dp"
                    android:background="@drawable/icon_back" />
                <TextView
                    android:id="@+id/tv_userNick"
                    android:text="未命名"
                    android:textSize="16sp"
                    android:textColor="@color/text_white"
                    android:layout_centerHorizontal="true"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content" />
            </RelativeLayout>
            <RelativeLayout
                android:id="@+id/rl_tagHeader"
                android:layout_marginTop="10dp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                
                <com.h.fileinput.widget.CircleView
                    android:id="@+id/pUserHeader"
                    android:layout_centerHorizontal="true"
                    android:src="@drawable/zhongyuan"
                    android:layout_width="92dp"
                    android:layout_height="92dp" />

            </RelativeLayout>
            <ImageView
                android:id="@+id/tv_follow"
                android:layout_marginTop="5dp"
                android:src="@drawable/icon_add_follow"
                android:layout_gravity="center_horizontal"
                android:layout_width="42dp"
                android:layout_height="14dp" />
            <LinearLayout
                android:id="@+id/ll_summaryBottom"
                android:orientation="horizontal"
                android:layout_marginTop="10dp"
                android:gravity="center"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                <LinearLayout
                    android:orientation="vertical"
                    android:gravity="center_horizontal"
                    android:layout_width="100dp"
                    android:layout_height="wrap_content">
                    <TextView
                        android:id="@+id/tv_followNum"
                        android:text="0"
                        style="@style/person_num"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content" />
                    <TextView
                        android:text="关注"
                        style="@style/person_text1"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content" />
                </LinearLayout>
                <View
                    android:background="@color/text_white"
                    android:layout_marginBottom="5dp"
                    android:layout_marginTop="5dp"
                    android:layout_width="1dp"
                    android:layout_height="30dp"></View>
                <LinearLayout
                    android:orientation="vertical"
                    android:gravity="center_horizontal"
                    android:layout_width="100dp"
                    android:layout_height="wrap_content">
                    <TextView
                        android:id="@+id/tv_fansNum"
                        android:text="0"
                        style="@style/person_num"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content" />
                    <TextView
                        android:text="粉丝"
                        style="@style/person_text1"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content" />
                </LinearLayout>
            </LinearLayout>

        </LinearLayout>
        <WebView
            android:id="@+id/myWebview"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        </WebView>
    </com.h.fileinput.widget.DragTopLayout>
</RelativeLayout>

页面实现:

import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.LinearLayout;

import com.h.fileinput.R;
import com.h.fileinput.widget.DragTopLayout;
/*
* 类似于个人中心页,下方也有滑动,要求上下两部分整体滑动的例子
* */
public class DragTopDemoActivity extends Activity {
    private DragTopLayout dragTopLayout;
    private LinearLayout top_view;
    private WebView myWebView;
    String  path = "http://********/my.html?userId=201608251250230002&tuserId=26728010&phoneNumber=*******";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drag_top_demo);
        dragTopLayout = (DragTopLayout) findViewById(R.id.dragLayout);
        top_view = (LinearLayout) findViewById(R.id.top_view);
        myWebView = (WebView) findViewById(R.id.myWebview);
        dragTopLayout.setTargetView(myWebView);
        initWebView(path);
    }

    public boolean isWebViewAttach(WebView webView){
        if (webView != null) {
            if (webView.getScrollY() > 0) {
                return false;
            }
        }
        return true;
    }

    public void initWebView(String path) {
        WebSettings settings = myWebView.getSettings();
        settings.setJavaScriptEnabled(true);
        //设置可以访问文件
        settings.setAllowFileAccess(true);
        //设置支持缩放
        settings.setBuiltInZoomControls(true);
        //修改某些机型二维码显示不出来的问题
        //打开DOM储存API
        settings.setDomStorageEnabled(true);
        settings.setAllowFileAccess(true);
        settings.setAppCacheEnabled(true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }
        //修改WebView页面图片大小
        settings.setUseWideViewPort(true);//让webview读取网页设置的viewport,pc版网页
        settings.setLoadWithOverviewMode(true);
//        settings.setTextSize(WebSettings.TextSize.NORMAL);
        加载需要显示的网页
        myWebView.loadUrl(path);
        //设置Web视图
        myWebView.setWebViewClient(new MyWebViewClient());
    }

    //Web视图
    private class MyWebViewClient extends WebViewClient {
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }
}

注意:

1.个人信息部分一定要放在一个整体布局中,这样滑动时,DragTopLayout才能获取到个人信息的整体高度。同样,其余部分要放在另一个整体布局中。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值