自定义ScrollView实现图片下拉放大(弹性效果)+ 悬浮框
2017-01-16 17:44
489 查看
先上效果图:
1.自定义ScrollView:
/**
* 阻尼效果的scrollview
*/
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;
d881
}
}
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);
}
}
2.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<visahall.cn.mytest.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:background="@mipmap/ff"
android:layout_width="match_parent"
android:layout_height="300dp" />
<RelativeLayout
android:id="@+id/relativeLayout"
android:layout_width="match_parent"
android:background="@color/colorAccent"
android:layout_height="50dp">
<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"></ListView>
</LinearLayout>
</visahall.cn.mytest.MyScrollView>
<RelativeLayout
android:id="@+id/relativeLayout2"
android:layout_width="match_parent"
android:visibility="gone"
android:background="@color/colorAccent"
android:layout_height="50dp">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="固定在顶部"/>
</RelativeLayout>
</RelativeLayout>
3.MainActivity:
package visahall.cn.mytest;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
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<>();
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
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);
}
}
至此,就结束了,老样子,依然把解释都写在代码中。
Demo下载
1.自定义ScrollView:
/**
* 阻尼效果的scrollview
*/
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;
d881
}
}
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);
}
}
2.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<visahall.cn.mytest.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:background="@mipmap/ff"
android:layout_width="match_parent"
android:layout_height="300dp" />
<RelativeLayout
android:id="@+id/relativeLayout"
android:layout_width="match_parent"
android:background="@color/colorAccent"
android:layout_height="50dp">
<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"></ListView>
</LinearLayout>
</visahall.cn.mytest.MyScrollView>
<RelativeLayout
android:id="@+id/relativeLayout2"
android:layout_width="match_parent"
android:visibility="gone"
android:background="@color/colorAccent"
android:layout_height="50dp">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="固定在顶部"/>
</RelativeLayout>
</RelativeLayout>
3.MainActivity:
package visahall.cn.mytest;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
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<>();
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
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);
}
}
至此,就结束了,老样子,依然把解释都写在代码中。
Demo下载
相关文章推荐
- 自定义ScrollView实现图片下拉放大(弹性效果)+ 悬浮框
- 自定义scrollView实现顶部图片下拉放大
- Android : 自定义实现下拉放大图片,松手自动反弹效果
- 自定义scrollView实现顶部图片下拉放大
- Android自定义scrollView实现顶部图片下拉放大
- 自定义ScrollView实现下拉放大头部图片
- 安卓学习笔记---实现下拉图片放大,松开又自动回去效果 (ListView与ScrollView)
- iOS----实现scrollView或者scrollView的子类下拉图片放大的效果
- iOS----实现scrollView或者scrollView的子类下拉图片放大的效果
- android 自定义ScrollView实现背景图片伸缩(仿多米,PaPa个人页面特效也称为阻尼效果
- android 自定义ScrollView实现背景图片伸缩(阻尼效果)
- 弹性ScrollView,和下啦刷新的效果类似 实现下拉弹回和上拉弹回
- 经验之谈—实现图片下拉放大的效果
- android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- 自定义ScrollView实现弹性效果
- android自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果
- 弹性ScrollView,和下啦刷新的效果类似 实现下拉弹回和上拉弹回