Android自定义View之上拉、下拉列表 头部元素跟随 缩放、平移效果的实现

  滑动ListView列表然后 listView上边的视图 跟随着上拉或者下拉的距离 自动放大或者缩小  视图里边元素自动平移的效果

思路很简单

根据listView 的滑动距离去计算图片和文字应该平移的距离

例如顶部视图本来高度为500px  我们定义视图收缩到200px为最小高度,那么视图向上滑动的最大距离就为300px

当我们将列表向上滑动300px的时候试图就应该滑到最小高度了   继续上滑,不继续缩小视图高度即可

同理 下拉的时候 下拉300px 此时视图应该从200px高度变为500px高度  继续下拉 不增加试图高度即可

简单来说就是对 触摸事件的处理  根据   (上拉或者下拉的距离)/300px = 视图应该缩小或者放大的比例

上代码:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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:background="#fff"
    >

    <RelativeLayout
        android:id="@+id/rl_head"
        android:layout_width="match_parent"
        android:layout_height="300px"
        android:text="Hello World!"
        android:background="#9F79EE">

        <ImageView
            android:id="@+id/iv_head"
            android:layout_marginTop="60px"
            android:layout_marginLeft="50px"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@mipmap/ic_launcher_round"
            />

        <TextView
            android:id="@+id/tv_name"
            android:layout_marginTop="80px"
            android:layout_marginLeft="180px"
            android:text="一个名称"
            android:textColor="#fff"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/tv_other"
            android:text="其他字段"
            android:textColor="#fff"
            android:layout_marginTop="200px"
            android:layout_marginLeft="50px"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        </RelativeLayout>


    <ListView
        android:id="@+id/lv"
        android:layout_below="@id/rl_head"
        android:listSelector="@android:color/transparent"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

MainActivity.java

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.Arrays;
import java.util.List;

public class MainActivity extends Activity {

    private ListView listView;
    private RelativeLayout rl_head;
    private ImageView iv_head;
    private TextView tv_name,tv_other;

    private MyAdapter adapter;

    //*******************************
    private int mLastY = 0;  //最后的点
    private static int mNeedDistance;   // 需要滑动的距离
    private static int mMinHight; //最小高度
    private static int mOrignHight; //原始的高度

    private int mCurrentDistance = 0;  //当前的距离
    private float mRate = 0;  //距离与目标距离的变化率 mRate=mCurrentDistance/mNeedDistance
    private int mPhotoOriginHeight; //图片的原始高度
    private int mPhotoOriginWidth; //图片的原始宽度
    private int mPhotoLeft;  //图片距左边的距离
    private int mPhotoTop;  //图片距离上边的距离
    private int mPhotoNeedMoveDistanceX;  // 图片需要移动的X距离
    private int mPhotoNeedMoveDistanceY;  // 图片需要移动的Y距离
    //需要移动的文字
    private int mTextLeft;  //文字距左边的距离
    private int mTextTop;  //文字距离上边的距离
    private int mTextNeedMoveDistanceX;  // 文字需要移动的X距离
    private int mTextNeedMoveDistanceY;  //文字需要移动的Y距离
    //*********************************************

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        initView();
        initDistance();
    }

    private void initView() {
        listView= (ListView) findViewById(R.id.lv);
        rl_head= (RelativeLayout) findViewById(R.id.rl_head);
        iv_head= (ImageView) findViewById(R.id.iv_head);
        tv_name= (TextView) findViewById(R.id.tv_name);
        tv_other= (TextView) findViewById(R.id.tv_other);

        String []strs={"北京","上海","天津","北京","上海","天津","北京","上海","天津","北京","上海","天津","北京","上海","天津","北京","上海","天津","北京","上海","天津"};
        List<String> data= Arrays.asList(strs);

        adapter=new MyAdapter(this,data);
        listView.setAdapter(adapter);
    }

    /**
     * 初始化需要滚动的距离
     */
    private void initDistance() {
        mOrignHight = rl_head.getLayoutParams().height;
        mMinHight =100;  //设置最小的高度为这么多
        mNeedDistance = mOrignHight - mMinHight;
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) iv_head.getLayoutParams();
        mPhotoOriginHeight = params.height;
        mPhotoOriginWidth = params.width;
        mPhotoLeft = params.leftMargin;
        mPhotoTop = params.topMargin;
        mPhotoNeedMoveDistanceX = getWindowManager().getDefaultDisplay().getWidth() / 2 - mPhotoLeft - mMinHight;
        mPhotoNeedMoveDistanceY = mPhotoTop - 20;
        /*******************移动的文字初始化***************************/
        RelativeLayout.LayoutParams textParams = (RelativeLayout.LayoutParams) tv_name.getLayoutParams();
        mTextLeft = textParams.leftMargin;
        mTextTop = textParams.topMargin;
        mTextNeedMoveDistanceX = getWindowManager().getDefaultDisplay().getWidth() / 2 - mTextLeft + 10;
        mTextNeedMoveDistanceY = mTextTop - 20;  //这里计算有点误差,正确的应该是剪去获取textview高度的一半
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastY = (int) ev.getY();
              //  LogUtils.d(TAG, "ACTION_MOVE==mCurrentDistance" + mCurrentDistance);
                return super.dispatchTouchEvent(ev); //传递事件 例如可以用来子view的点击事件等
            case MotionEvent.ACTION_MOVE:
                int y = (int) ev.getY();
                int dy = mLastY - y;
            //    LogUtils.d(TAG, "ACTION_MOVE==mCurrentDistance" + mCurrentDistance);
                if (mCurrentDistance >= mNeedDistance && dy > 0) {
                    return super.dispatchTouchEvent(ev);  //传递事件
                }
                if (mCurrentDistance <= 0 && dy < 0) {
                    return super.dispatchTouchEvent(ev); //把事件传递进去
                }
                //改变布局
                changeTheLayout(dy);
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
                checkTheHeight();
         //       LogUtils.d(TAG, "ACTION_MOVE==mCurrentDistance" + mCurrentDistance);
                return super.dispatchTouchEvent(ev);
        }

        return false;
    }


    /**
     * 通过滑动的偏移量
     *
     * @param dy
     */
    private void changeTheLayout(int dy) {
        final ViewGroup.LayoutParams layoutParams = rl_head.getLayoutParams();
        layoutParams.height = layoutParams.height - dy;
        rl_head.setLayoutParams(layoutParams);
        checkTheHeight();
        rl_head.requestLayout();
        //计算当前移动了多少距离
        mCurrentDistance = mOrignHight - rl_head.getLayoutParams().height;
        mRate = (float) (mCurrentDistance * 1.0 / mNeedDistance);
        changeTheAlphaAndPostion(mRate);  //获取偏移率然后改变某些控件的透明度,和位置
    }


    /**
     * 根据变化率来改变这些这些控件的变化率位置
     *
     * @param rate
     */
    private void changeTheAlphaAndPostion(float rate) {
        //先改变一些控件的透明度
        if (rate >= 1) {
            tv_other.setVisibility(View.GONE);
        } else {
            tv_other.setVisibility(View.VISIBLE);
            tv_other.setAlpha(1 - rate);
            tv_other.setScaleY(1 - rate);
            tv_other.setScaleX(1 - rate);
        }
        //接下来是改变控件的大小和位置了  (这就是关键了)
        RelativeLayout.LayoutParams photoParams = (RelativeLayout.LayoutParams) iv_head.getLayoutParams();
      //  photoParams.width = (int) (mPhotoOriginWidth - (rate * (mPhotoOriginWidth - mMinHight - 10)));
     //   photoParams.height = (int) (mPhotoOriginWidth - (rate * (mPhotoOriginWidth - mMinHight - 10)));
        photoParams.leftMargin = (int) (mPhotoLeft + mPhotoNeedMoveDistanceX * rate);
        photoParams.topMargin = (int) (mPhotoTop - mPhotoNeedMoveDistanceY * rate);
        iv_head.setLayoutParams(photoParams);
        //针对文字
        RelativeLayout.LayoutParams textParams = (RelativeLayout.LayoutParams) tv_name.getLayoutParams();
        textParams.leftMargin = (int) (mTextLeft + mTextNeedMoveDistanceX * rate);
        textParams.topMargin = (int) (mTextTop - mTextNeedMoveDistanceY * rate);
        tv_name.setLayoutParams(textParams);
    }


    /**
     * 检查上边界和下边界
     */
    private void checkTheHeight() {
        final ViewGroup.LayoutParams layoutParams = rl_head.getLayoutParams();
        if (layoutParams.height < mMinHight) {
            layoutParams.height = mMinHight;
            rl_head.setLayoutParams(layoutParams);
            rl_head.requestLayout();
        }
        if (layoutParams.height > mOrignHight) {
            layoutParams.height = mOrignHight;
            rl_head.setLayoutParams(layoutParams);
            rl_head.requestLayout();
        }

    }


}

根据这个思路  即可实现网上大多数 上拉下拉,收缩放大视图的效果

严禁盗版    

转载请注明出处:https://www.cnblogs.com/bimingcong/p/9029491.html

原文地址:https://www.cnblogs.com/bimingcong/p/9029491.html