自定义ScrollView实现图片下拉放大(弹性效果)+ 悬浮框
效果图:
MyScrollView
package com.bwie.com.wangruixin1509c20171121; import android.content.Context; import android.graphics.Rect; import android.os.Handler; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.ImageView; import android.widget.ScrollView; import android.widget.Scroller; /** * Created by Wangrx on 2017/11/21. */ public class MyScrollView extends ScrollView{ private OnScrollListener onScrollListener; private int lastScrollY; private static final int LEN = 0xc8; private static final int DURATION = 500; private static final int MAX_DY = 200; private Scroller mScroller; TouchTool tool; int left, top; float startX, startY, currentX, currentY; int imageViewH; int rootW, rootH; ImageView imageView; boolean scrollerType; public MyScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public MyScrollView(Context context, AttributeSet attrs) { super(context, attrs); mScroller = new Scroller(context); } public MyScrollView(Context context) { super(context); } public void setImageView(ImageView imageView) { this.imageView = imageView; } @Override protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) { return 0; } private int[] li = new int[2]; private int[] li2 = new int[2]; private float lastLy; private boolean startIsTop = true; @Override public boolean dispatchTouchEvent(MotionEvent event) { super.dispatchTouchEvent(event); int action = event.getAction(); if (!mScroller.isFinished()) { return super.onTouchEvent(event); } currentX = event.getX(); currentY = event.getY(); imageView.getLocationInWindow(li); getLocationOnScreen(li2); imageView.getTop(); switch (action) { case MotionEvent.ACTION_DOWN: if (li[1] != li2[1]) {// 判断开始触摸时,imageview和窗口顶部对齐没 startIsTop = false; } left = imageView.getLeft(); top = imageView.getBottom(); rootW = getWidth(); rootH = getHeight(); imageViewH = imageView.getHeight(); startX = currentX; startY = currentY; tool = new TouchTool(imageView.getLeft(), imageView.getBottom(), imageView.getLeft(), imageView.getBottom() + LEN); break; case MotionEvent.ACTION_MOVE: if (!startIsTop && li[1] == li2[1]) { startY = currentY; startIsTop = true; } if (imageView.isShown() && imageView.getTop() >= 0) { if (tool != null) { int t = tool.getScrollY(currentY - startY); if (!scrollerType && currentY < lastLy && imageView.getHeight() > imageViewH) { scrollTo(0, 0); imageView.getLocationInWindow(li); getLocationOnScreen(li2); android.view.ViewGroup.LayoutParams params = imageView.getLayoutParams(); params.height = t; imageView.setLayoutParams(params); if (imageView.getHeight() == imageViewH && li[1] == li2[1]) { scrollerType = true; } if (startIsTop && li[1] != li2[1]) { startIsTop = false; } } if (t >= top && t <= imageView.getBottom() + LEN && li[1] == li2[1] && currentY > lastLy) { android.view.ViewGroup.LayoutParams params = imageView.getLayoutParams(); params.height = t; imageView.setLayoutParams(params); } } scrollerType = false; } lastLy = currentY; break; case MotionEvent.ACTION_UP: if (li[1] == li2[1]) { scrollerType = true; mScroller.startScroll(imageView.getLeft(), imageView.getBottom(), 0 - imageView.getLeft(), imageViewH - imageView.getBottom(), DURATION); invalidate(); } startIsTop = true; break; } return true; } @Override public void computeScroll() { super.computeScroll(); if (mScroller.computeScrollOffset()) { int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); imageView.layout(0, 0, x + imageView.getWidth(), y); invalidate(); if (!mScroller.isFinished() && scrollerType && y > MAX_DY) { android.view.ViewGroup.LayoutParams params = imageView.getLayoutParams(); params.height = y; imageView.setLayoutParams(params); } } } public class TouchTool { private int startX, startY; public TouchTool(int startX, int startY, int endX, int endY) { super(); this.startX = startX; this.startY = startY; } public int getScrollX(float dx) { int xx = (int) (startX + dx / 2.5F); return xx; } public int getScrollY(float dy) { int yy = (int) (startY + dy / 2.5F); return yy; } } /** * 设置滚动接口 * @param onScrollListener */ public void setOnScrollListener(OnScrollListener onScrollListener){ this.onScrollListener = onScrollListener; } /** * 用于用户手指离开MyScrollView的时候获取MyScrollView滚动的Y距离,然后回调给onScroll方法中 */ private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { int scrollY = MyScrollView.this.getScrollY(); //此时的距离和记录下的距离不相等,在隔5毫秒给handler发送消息 if(lastScrollY != scrollY){ lastScrollY = scrollY; handler.sendMessageDelayed(handler.obtainMessage(), 5); } if(onScrollListener != null){ onScrollListener.onScroll(scrollY); } } }; @Override public boolean onTouchEvent(MotionEvent ev) { if(onScrollListener != null){ onScrollListener.onScroll(lastScrollY = this.getScrollY()); } switch(ev.getAction()){ case MotionEvent.ACTION_UP: handler.sendMessageDelayed(handler.obtainMessage(), 20); break; } return super.onTouchEvent(ev); } /** * 滚动的回调接口 */ public interface OnScrollListener{ /** * 回调方法, 返回MyScrollView滑动的Y方向距离 */ public void onScroll(int scrollY); } }MainActivity
package com.bwie.com.wangruixin1509c20171121; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.RelativeLayout; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private ListView listView; private ImageView imageView; // private RelativeLayout relativeLayout; private RelativeLayout relativeLayout2; private MyScrollView dampView; private List<String> list = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); // initData(); //设置可拉伸的头部ImageView dampView.setImageView(imageView); // //setAdapter // listView.setAdapter(new ArrayAdapter<String>(this, // android.R.layout.simple_list_item_1, list)); //动态设置ListView单条的高度,解决与scollView的滑动冲突 setListViewHeightBasedOnChildren(listView); dampView.setOnScrollListener(new MyScrollView.OnScrollListener() { @Override public void onScroll(int scrollY) { if (scrollY >= imageView.getHeight()){ // relativeLayout.setVisibility(View.GONE); relativeLayout2.setVisibility(View.VISIBLE); }else { // relativeLayout.setVisibility(View.VISIBLE); relativeLayout2.setVisibility(View.GONE); } } }); } // //假数据 // private void initData() { // for (int i = 0; i < 100; i++) { // list.add(i, i + ""); // } // } //查找控件 private void initView() { dampView = (MyScrollView) findViewById(R.id.dampView); listView = (ListView) findViewById(R.id.listView); imageView = (ImageView) findViewById(R.id.imageView); // relativeLayout = (RelativeLayout) findViewById(R.id.relativeLayout); relativeLayout2 = (RelativeLayout) findViewById(R.id.relativeLayout2); } //动态设置ListView单条的高度,解决与scollView的滑动冲突 public void setListViewHeightBasedOnChildren(ListView listView) { // 获取ListView对应的Adapter ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { return; } int totalHeight = 0; for (int i = 0, len = listAdapter.getCount(); i < len; i++) { // listAdapter.getCount()返回数据项的数目 View listItem = listAdapter.getView(i, null, listView); // 计算子项View 的宽高 listItem.measure(0, 0); // 统计所有子项的总高度 totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight+ (listView.getDividerHeight() * (listAdapter.getCount() - 1)); // listView.getDividerHeight()获取子项间分隔符占用的高度 // params.height最后得到整个ListView完整显示需要的高度 listView.setLayoutParams(params); } }activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.bwie.com.wangruixin1509c20171121.MainActivity"> <com.bwie.com.wangruixin1509c20171121.MyScrollView android:id="@+id/dampView" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="300dp" android:background="@mipmap/i" /> <!--<RelativeLayout--> <!--android:id="@+id/relativeLayout"--> <!--android:layout_width="match_parent"--> <!--android:layout_height="50dp"--> <!--android:background="@color/colorAccent">--> <!--<TextView--> <!--android:layout_width="match_parent"--> <!--android:layout_height="match_parent"--> <!--android:gravity="center"--> <!--android:text="固定在顶部" />--> <!--</RelativeLayout>--> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent" android:entries="@array/entry"></ListView> </LinearLayout> </com.bwie.com.wangruixin1509c20171121.MyScrollView> <RelativeLayout android:id="@+id/relativeLayout2" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/colorAccent" android:visibility="gone"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="固定在顶部" /> </RelativeLayout> </RelativeLayout>