package com.zft.tygj.view; import android.animation.ValueAnimator; import android.content.Context; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewTreeObserver; import android.widget.LinearLayout; import android.widget.ScrollView; import com.zft.tygj.R; public class MyPullHeaderView extends LinearLayout { private View headerView; private ScrollView scrollView; private int mTouchSlop; private float lastY; private int headerHeight; private float offsetRadio = 2.0f; public boolean isDispatchEvent; private boolean headScrollEnable = true; public MyPullHeaderView(Context context) { super(context); } public MyPullHeaderView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyPullHeaderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void setHeadScrollEnable(boolean headScrollEnable) { this.headScrollEnable = headScrollEnable; } @Override protected void onFinishInflate() { super.onFinishInflate(); headerView = findViewById(R.id.headerView); scrollView = (ScrollView) findViewById(R.id.myScrollView); init(); } /** * 初始化 */ private void init() { mTouchSlop = (int) (ViewConfiguration.get(getContext()).getScaledTouchSlop() * 1.5); // 得到Header的高度,这个高度需要用这种方式得到,在onLayout方法里面得到的高度始终是0 getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { refreshLoadingViewsSize(); getViewTreeObserver().removeOnGlobalLayoutListener(this); } }); } /** * 初始化padding,我们根据header的高度来设置top padding和bottom padding */ public void refreshLoadingViewsSize() { // 得到header的内容高度,它将会作为拖动刷新的一个临界值,如果拖动距离大于这个高度 headerHeight = (headerView != null) ? headerView.getHeight() : 0; int pLeft = getPaddingLeft(); int pTop = -headerHeight; int pRight = getPaddingRight(); int pBottom = 0; setPadding(pLeft, pTop, pRight, pBottom); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: lastY = ev.getY(); break; case MotionEvent.ACTION_MOVE: float deltaY = ev.getY() - lastY; if (headScrollEnable && isInterceptMoveEvent(deltaY)) { onTouchEvent(ev); return false; } else { lastY = ev.getY(); } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: int mScrollY = getScrollY(); boolean flag = true; //解决滑动事件触发点击事件 if (mScrollY < 0 && mScrollY > -headerHeight// || headerView.getLayoutParams().height > headerHeight) { //当头布局处于滑动状态,屏蔽下层的点击事件 flag = false; } //触摸事件消失,设置头布局位置,要么全显示,要么全隐藏 onTouchEvent(ev); if (!flag) { return false; } break; } return super.dispatchTouchEvent(ev); } /** * TODO touch */ @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_MOVE: float deltaY = event.getY() - lastY; lastY = event.getY(); handlerSelfMoveEvent(deltaY); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: handlerSelfUpEvent(); break; } return super.onTouchEvent(event); } /** * 处理自身的up事件 */ private void handlerSelfUpEvent() { int mScrollY = getScrollY(); if (isHeaderViewShowing()) { if (Math.abs(mScrollY) < headerHeight / 2) {//回退回去 setAnimator(Math.abs(mScrollY)); } else {//直接显示 setAnimator(-(headerHeight - Math.abs(mScrollY))); } } if (headerView.getLayoutParams().height > headerHeight) { setViewHeight(headerView, headerHeight); } } /** * 处理自身的move事件 此方法不好,不推荐 */ private void handlerSelfMoveEvent1(float deltaY) { int mScrollY = getScrollY(); //向下滑动 deltaY>0 向上滑动 deltaY<0 //mScrollY=0完全隐藏,mScrollY==-headerHeight全部显示 if (deltaY > 0) {// 向下滑动布局 if (mScrollY > -headerHeight) {//还没有显示完全 if (Math.abs(mScrollY) + Math.abs(deltaY) > headerHeight) {//移动超标了 deltaY = headerHeight - Math.abs(mScrollY); } float mOffsetRadio = getOffsetRadio(mScrollY); scrollBy(0, (int) (-deltaY / mOffsetRadio)); } } else if (deltaY < 0) {//向上滑动 deltaY<0 if (mScrollY < 0 //还没有隐藏完全 && headerView.getLayoutParams().height <= headerHeight) {//头布局在放大的时候,不处理 if (Math.abs(mScrollY) - Math.abs(deltaY) < 0) {//移动超标了 deltaY = 0 - Math.abs(mScrollY); } scrollBy(0, (int) -deltaY); } } //头布局拉伸效果 if (mScrollY <= -headerHeight) { //改变头布局的高度 getOffsetRadio1(); int afterViewHeight = getAfterViewHeight(headerView, (int) (deltaY / getOffsetRadio1())); setViewHeight(headerView, afterViewHeight); } } /** * 处理自身的move事件 */ private void handlerSelfMoveEvent(float deltaY) { int mScrollY = getScrollY(); //向下滑动 deltaY>0 向上滑动 deltaY<0 //mScrollY=0完全隐藏,mScrollY==-headerHeight全部显示 if (deltaY > 0) {// 向下滑动布局 if (mScrollY > -headerHeight) { float mOffsetRadio = getOffsetRadio(mScrollY); float myY = deltaY / mOffsetRadio; if (Math.abs(mScrollY) + myY > headerHeight) {//移动超标了 scrollTo(0, -headerHeight); } else { scrollTo(0, (int) (mScrollY - myY)); } } else if (mScrollY < -headerHeight) { scrollTo(0, -headerHeight); } } else if (deltaY < 0) {//向上滑动 deltaY<0 if (mScrollY < 0) { if (headerView.getLayoutParams().height <= headerHeight) {//头布局 不 处于弹簧状态 if (Math.abs(mScrollY) - Math.abs(deltaY) < 0) {//移动超标了 scrollTo(0, 0); } else { scrollTo(0, (int) (mScrollY - deltaY)); } } } else if (mScrollY > 0) { scrollTo(0, 0); } } //头布局拉伸效果==头布局弹簧效果 if (mScrollY <= -headerHeight) { //改变头布局的高度 float offsetRadio = getOffsetRadio1(); int afterViewHeight = getAfterViewHeight(headerView, (int) (deltaY / offsetRadio)); setViewHeight(headerView, afterViewHeight); } } /** * 是否拦截事件 */ private boolean isInterceptMoveEvent(float deltaY) { boolean intercept = false; //向下滑动 deltaY>0 向上滑动 deltaY<0 if (deltaY > 0 && scrollView.getScrollY() == 0) { intercept = true; } else if (deltaY < 0) { int mScrollY = getScrollY(); if (mScrollY < 0 && mScrollY >= -headerHeight) { intercept = true; } } return intercept; } /** * 头布局拉伸的阻尼系数 */ private float getOffsetRadio1() { int nowHeight = headerView.getLayoutParams().height; return nowHeight * 1.0f * 2 / headerHeight; } /** * 改变 布局的高度 */ public int getAfterViewHeight(View view, int upDateHeight) { int nowHeight = view.getLayoutParams().height; return nowHeight + upDateHeight; } /** * 设置高度 */ public void setViewHeight(View view, int afterHeight) { if (afterHeight <= headerHeight) { afterHeight = headerHeight; } else if (afterHeight >= headerHeight * 2) { afterHeight = headerHeight * 2; } view.getLayoutParams().height = afterHeight; view.setLayoutParams(view.getLayoutParams()); } private float getOffsetRadio(int mScrollY) { float ratio = Math.abs(mScrollY) * 2f / headerHeight; float offsetRadio = 5.0f - ratio * 4; if (offsetRadio <= 1.0) { offsetRadio = 1.0f; } return offsetRadio; } /** * headerView 是否正在展示 */ private boolean isHeaderViewShowing() { int mScrollY = getScrollY(); if (mScrollY < 0) { return true; } return false; } private void setAnimator(int endY) { ValueAnimator valueAnimator = ValueAnimator.ofInt(0, endY); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { private int lastValue; @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int value = (int) valueAnimator.getAnimatedValue(); int y = value - lastValue; lastValue = value; Log.i("TAG", "===y" + getScrollY()); scrollBy(0, y); } }); valueAnimator.setDuration(200).start(); } public void backInitialState() { int scrollY = getScrollY(); if (scrollY != 0) { setAnimator(Math.abs(scrollY)); } } }
package com.zhangfan.myheadscroll; import android.graphics.Color; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private TextView tv1; private TextView tv2; private TextView tv3; private LinearLayout headView; private LinearLayout ll_addView; private ScrollView scrollView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); initView(); } private void initView() { tv1 = (TextView) findViewById(R.id.tv1); tv2 = (TextView) findViewById(R.id.tv2); tv3 = (TextView) findViewById(R.id.tv3); headView = (LinearLayout) findViewById(R.id.headView); ll_addView = (LinearLayout) findViewById(R.id.ll_addView); scrollView = (ScrollView) findViewById(R.id.scrollView); tv1.setOnClickListener(this); tv2.setOnClickListener(this); tv3.setOnClickListener(this); headView.setOnClickListener(this); for (int i = 0; i < 20; i++) { TextView textView = new TextView(this); textView.setText("测试" + i); textView.setTextColor(Color.BLACK); textView.setTextSize(50); LinearLayout.LayoutParams layoutParams = new LinearLayout.// LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 300); textView.setLayoutParams(layoutParams); textView.setGravity(Gravity.CENTER); ll_addView.addView(textView); final int finalI = i; textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { TextView textView = (TextView) view; textView.setText("点击测试" + finalI); } }); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.tv1: ((TextView) v).setText("1111"); break; case R.id.tv2: ((TextView) v).setText("222"); break; case R.id.tv3: ((TextView) v).setText("222"); break; case R.id.headView: break; } } } //==========================XML==============
<?xml version="1.0" encoding="utf-8"?> <com.zhangfan.myheadscroll.myview.MyPullView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.zhangfan.myheadscroll.MainActivity"> <LinearLayout android:id="@+id/headView" android:layout_width="match_parent" android:layout_height="400px" android:background="#FFFFCCCC" android:clickable="true" android:orientation="horizontal"> <TextView android:id="@+id/tv1" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:clickable="true" android:gravity="center" android:text="Title1" android:textColor="#000000" android:textSize="50px"/> <TextView android:id="@+id/tv2" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:clickable="true" android:gravity="center" android:text="Title2" android:textColor="#000000" android:textSize="50px"/> <TextView android:id="@+id/tv3" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:clickable="true" android:gravity="center" android:text="Title3" android:textColor="#000000" android:textSize="50px"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="200px" android:clickable="true"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:clickable="true" android:gravity="center" android:text="固定的布局" android:textColor="#000000" android:textSize="50px"/> </LinearLayout> <com.zhangfan.myheadscroll.myview.MyScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/ll_addView" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="vertical"> </LinearLayout> </com.zhangfan.myheadscroll.myview.MyScrollView> </com.zhangfan.myheadscroll.myview.MyPullView>