京东淘宝有那么一种效果就是,上拉可以查看宝贝的详情,这里我也实现了一个类似的效果,也可以移植到商业项目上:先看看简单的效果图
实现原理其实是利用了ScrollView的滚动和view的touch事件监听完成的:图片层(也可以是其他布局)和详情页层其实是从上到下布局到ScrollView中的,首先要屏蔽ScrollView的touch事件,然后初始化的时候给上层设置为屏幕的高度,详情页设置高度为屏幕高度 - 状态栏高度 - 上层灰色提示信息的高度。再给图片层添加touch事件,获取手指移动的距离,当达到一定的距离就上滑或下滑,否则就回弹回去。就是这么简单 哈哈
一:自定义ScrollView屏蔽touch事件(不然,图片层不能监听到touch事件)
package com.ywl5320.scrollanima;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView;
public class MyScrollView extends ScrollView {
private OnScrollChangedListeneer onScrollChangedListeneer;// 滚动监听接口
public MyScrollView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}
@Override
public boolean onTouchEvent(MotionEvent ev) { // 屏蔽touch事件,才能在监听其子控件的touch事件
// TODO Auto-generated method stub
super.onTouchEvent(ev);
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event)// 屏蔽touch事件传递,才能在监听其子控件的touch事件
{
super.onInterceptTouchEvent(event);
return false;
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
// TODO Auto-generated method stub
super.onScrollChanged(l, t, oldl, oldt);
if(onScrollChangedListeneer != null)
{
onScrollChangedListeneer.onScrollChanged(l, t, oldl, oldt);
}
}
// 滚动事件监听,获取滚动的距离,用户处理一些其他事
public interface OnScrollChangedListeneer
{
public void onScrollChanged(int l, int t, int oldl, int oldt);
}
public void setOnScrollChangedListeneer(OnScrollChangedListeneer onScrollChangedListeneer)
{
this.onScrollChangedListeneer = onScrollChangedListeneer;
}
}
这里屏蔽touch事件的同时,还为滚动事件添加了一个回调接口,方便在使用的时候获取滚动的状态,以实现其他需要的效果。
二:动态设置图片层和详情页的高度
// 设置滑动层为屏幕高度
LayoutParams lp = (LayoutParams) lyView.getLayoutParams();
screenHeight = measureHeight();
lp.height = screenHeight;
lyView.setLayoutParams(lp);
// 设置详细层的高度:等于屏幕高度-状态栏高度-阴影提示高度
LayoutParams lp2 = (LayoutParams) swipeRefreshLayout.getLayoutParams();
lp2.height = screenHeight - dip2px(MainActivity.this, 150)
- getStatusBarHeight();
swipeRefreshLayout.setLayoutParams(lp2);
用到的工具方法:
/**
* 获取屏幕高度
*
* @return
*/
public int measureHeight() {
WindowManager wManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wManager.getDefaultDisplay().getMetrics(dm);
return dm.heightPixels;
}
/**
* dip转换为px
*
* @param context
* @param dipValue
* @return
*/
public int dip2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
/**
* 获取状态栏高度
*
* @return
*/
private int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height",
"dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
初始化工作就完成了
三:为图片层添加touch事件
// 为上层添加touch事件,控制详情页显示隐藏
lyView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getAction();
int offsety = 0;
int y = 0;
switch (action) {
case MotionEvent.ACTION_DOWN:
point.y = (int) event.getRawY();
offsetsum = 0;
// System.out.println(event.getX() + "----------" + event.getY());
break;
case MotionEvent.ACTION_MOVE:
y = (int) event.getRawY();
offsety = y - point.y;
offsetsum += offsety;
point.y = (int) event.getRawY();
sv.scrollBy(0, -offsety);
// System.out.println("offsetnum:" + offsetsum);
break;
case MotionEvent.ACTION_UP:
if (offsetsum > 0) {// offsetsum大于0时是往下拉,只有当显示详情页是下拉才有效果,所以这里先判断isOpen的值。
if (isOpen) {
if (offsetsum > 300) {
sv.smoothScrollTo(0, 0);
isOpen = false;
} else {
sv.smoothScrollTo(0, screenHeight);
isOpen = true;
}
}
else
{
sv.smoothScrollTo(0, 0);
isOpen = false;
}
} else {// offsetsum小于0时是往上拉,只有当隐藏详情页是下拉才有效果,所以这里先判断isOpen的值。
if(!isOpen)
{
if (offsetsum < -300) {
sv.smoothScrollTo(
0,
screenHeight
- dip2px(MainActivity.this, 150));
isOpen = true;
} else {
sv.smoothScrollTo(0, 0);
isOpen = false;
}
}
else
{
sv.smoothScrollTo(
0,
screenHeight
- dip2px(MainActivity.this, 150));
isOpen = true;
}
}
break;
}
return true;
}
});
首先判断当前是否显示详情页,然后根据手指移动距离是否大于0,判断是向上(小于0)还是向下(大于0)滑动,当滑动了一定的距离后就执行滑动操作,利用ScrollView的
smoothScrollTo方法动态的滑动到指定位置,注意:touch-move滑动时不要用smoothScrollTo这个方法,会导致Up时smoothScrollTo没有效果(我想应该是move时的动画监听还没有完成,up是就没有添加成功动画的监听,导致up是smoothScrollTo没有效果,而是直接到了某一点)。
这就实现了上拉查看详情和下拉隐藏详情页的效果。
效果图中用到了一个下拉刷新的组件是v4包里的SwipeRefreshLayout控件,这个很好用的,大家可以试试哦。好了就到这里了:Demo下载地址