版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】怎么在Android中通过自定义ViewGroup实现淘宝商品详情页
这篇文章给大家介绍怎么在Android中通过自定义ViewGroup实现淘宝商品详情页,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。package
com.mcoy.snapscrollview;
import
android.content.Context;
import
android.util.AttributeSet;
import
android.util.Log;
import
android.view.MotionEvent;
import
android.view.VelocityTracker;
import
android.view.View;
import
android.view.ViewConfiguration;
import
android.view.ViewGroup;
import
android.widget.Scroller;
public
class
McoySnapPageLayout
extends
ViewGroup
{
。。。。
public
interface
McoySnapPage
{
/**
*
返回page根节点
*
*
@return
*/
View
getRootView();
/**
*
是否滑动到最顶端
*
第二页必须自己实现此方法,来判断是否已经滑动到第二页的顶部
*
并决定是否要继续滑动到第一页
*/
boolean
isAtTop();
/**
*
是否滑动到最底部
*
第一页必须自己实现此方法,来判断是否已经滑动到第二页的底部
*
并决定是否要继续滑动到第二页
*/
boolean
isAtBottom();
}
public
interface
PageSnapedListener
{
/**
*
@mcoy
*
当从某一页滑动到另一页完成时的回调函数
*/
void
onSnapedCompleted(int
derection);
}
。。。。。。
/**
*
设置上下页面
*
@param
pageTop
*
@param
pageBottom
*/
public
void
setSnapPages(McoySnapPage
pageTop,
McoySnapPage
pageBottom)
{
mPageTop
=
pageTop;
mPageBottom
=
pageBottom;
addPagesAndRefresh();
}
private
void
addPagesAndRefresh()
{
//
设置页面id
mPageTop.getRootView().setId(0);
mPageBottom.getRootView().setId(1);
addView(mPageTop.getRootView());
addView(mPageBottom.getRootView());
postInvalidate();
}
/**
*
@mcoy
add
*
computeScroll方法会调用postInvalidate()方法,
而postInvalidate()方法中系统
*
又会调用computeScroll方法,
因此会一直在循环互相调用,
循环的终结点是在computeScrollOffset()
*
当computeScrollOffset这个方法返回false时,说明已经结束滚动。
*
*
重要:真正的实现此view的滚动是调用scrollTo(mScroller.getCurrX(),
mScroller.getCurrY());
*/
@Override
public
void
computeScroll()
{
//先判断mScroller滚动是否完成
if
(mSputeScrollOffset())
{
if
(mScroller.getCurrY()
==
(mScroller.getFinalY()))
{
if
(mNextDataIndex
>
mDataIndex)
{
mFlipDrection
=
FLIP_DIRECTION_DOWN;
makePageToNext(mNextDataIndex);
}
else
if
(mNextDataIndex
<
mDataIndex)
{
mFlipDrection
=
FLIP_DIRECTION_UP;
makePageToPrev(mNextDataIndex);
}else{
mFlipDrection
=
FLIP_DIRECTION_CUR;
}
if(mPageSnapedListener
!=
null){
mPageSnapedListener.onSnapedCompleted(mFlipDrection);
}
}
//这里调用View的scrollTo()完成实际的滚动
scrollTo(mScroller.getCurrX(),
mScroller.getCurrY());
//必须调用该方法,否则不一定能看到滚动效果
postInvalidate();
}
}
private
void
makePageToNext(int
dataIndex)
{
mDataIndex
=
dataIndex;
mCurrentScreen
=
getCurrentScreen();
}
private
void
makePageToPrev(int
dataIndex)
{
mDataIndex
=
dataIndex;
mCurrentScreen
=
getCurrentScreen();
}
public
int
getCurrentScreen()
{
for
(int
i
=
0;
i
<
getChildCount();
i++)
{
if
(getChildAt(i).getId()
==
mDataIndex)
{
return
i;
}
}
return
mCurrentScreen;
}
public
View
getCurrentView()
{
for
(int
i
=
0;
i
<
getChildCount();
i++)
{
if
(getChildAt(i).getId()
==
mDataIndex)
{
return
getChildAt(i);
}
}
return
null;
}
/*
*
(non-Javadoc)
*
*
@see
*
android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)
*
重写了父类的onInterceptTouchEvent(),主要功能是在onTouchEvent()方法之前处理
*
touch事件。包括:down、up、move事件。
*
当onInterceptTouchEvent()返回true时进入onTouchEvent()。
*/
@Override
public
boolean
onInterceptTouchEvent(MotionEvent
ev)
{
final
int
action
=
ev.getAction();
if
((action
==
MotionEvent.ACTION_MOVE)
&&
(mTouchState
!=
TOUCH_STATE_REST))
{
return
true;
}
final
float
x
=
ev.getX();
final
float
y
=
ev.getY();
switch
(action)
{
case
MotionEvent.ACTION_MOVE:
//
记录y与mLastMotionY差值的绝对值。
//
yDiff大于gapBetweenTopAndBottom时就认为界面拖动了足够大的距离,屏幕就可以移动了。
final
int
yDiff
=
(int)(y
-
mLastMotionY);
boolean
yMoved
=
Math.abs(yDiff)
>
gapBetweenTopAndBottom;
if
(yMoved)
{
if(MCOY_DEBUG)
{
Log.e(TAG,
"yDiff
is
"
+
yDiff);
Log.e(TAG,
"mPageTop.isFlipToBottom()
is
"
+
mPageTop.isAtBottom());
Log.e(TAG,
"mCurrentScreen
is
"
+
mCurrentScreen);
Log.e(TAG,
"mPageBottom.isFlipToTop()
is
"
+
mPageBottom.isAtTop());
}
if(yDiff
<
0
&&
mPageTop.isAtBottom()
&&
mCurrentScreen
==
0
||
yDiff
>
0
&&
mPageBottom.isAtTop()
&&
mCurrentScreen
==
1){
Log.e("mcoy",
"121212121212121212121212");
mTouchState
=
TOUCH_STATE_SCROLLING;
}
}
break;
case
MotionEvent.ACTION_DOWN:
//
Remember
location
of
down
touch
mLastMotionY
=
y;
Log.e("mcoy",
"mScroller.isFinished()
is
"
+
mScroller.isFinished());
mTouchState
=
mScroller.isFinished()
?
TOUCH_STATE_REST
:
TOUCH_STATE_SCROLLING;
break;
case
MotionEvent.ACTION_CANCEL:
case
MotionEvent.ACTION_UP:
//
Release
the
drag
mTouchState
=
TOUCH_STATE_REST;
break;
}
boolean
intercept
=
mTouchState
!=
TOUCH_STATE_REST;
Log.e("mcoy",
"McoySnapPageLayoutonInterceptTouchEvent
return
"
+
intercept);
return
intercept;
}
/*
*
(non-Javadoc)
*
*
@see
android.view.View#onTouchEvent(android.view.MotionEvent)
*
主要功能是处理onInterceptTouchEvent()返回值为true时传递过来的touch事件
*/
@Override
public
boolean
onTouchEvent(MotionEvent
ev)
{
Log.e("mcoy",
"onTouchEvent--"
+
System.currentTimeMillis());
if
(mVelocityTracker
==
null)
{
mVelocityTracker
=
VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
final
int
action
=
ev.getAction();
final
float
x
=
ev.getX();
final
float
y
=
ev.getY();
switch
(action)
{
case
MotionEvent.ACTION_DOWN:
if
(!mScroller.isFinished())
{
mScroller.abortAnimation();
}
break;
case
MotionEvent.ACTION_MOVE:
if(mTouchState
!=
TOUCH_STATE_SCROLLING){
//
记录y与mLastMotionY差值的绝对值。
//
yDiff大于gapBetweenTopAndBottom时就认为界面拖动了足够大的距离,屏幕就可以移动了。
final
int
yDiff
=
(int)
Math.abs(y
-
mLastMotionY);
boolean
yMoved
=
yDiff
>
gapBetweenTopAndBottom;
if
(yMoved)
{
mTouchState
=
TOUCH_STATE_SCROLLING;
}
}
//
手指拖动屏幕的处理
if
((mTouchState
==
TOUCH_STATE_SCROLLING))
{
//
Scroll
to
follow
the
motion
event
final
int
deltaY
=
(int)
(mLastMotionY
-
y);
mLastMotionY
=
y;
final
int
scrollY
=
getScrollY();
if(mCurrentScreen
==
0){//显示第一页,只能上拉时使用
if(mPageTop
!=
null
&&
mPageTop.isAtBottom()){
scrollBy(0,
Math.max(-1
*
scrollY,
deltaY));
}
}else{
if(mPageBottom
!=
null
&&
mPageBottom.isAtTop()){
scrollBy(0,
deltaY);
}
}
}
break;
case
MotionEvent.ACTION_CANCEL:
case
MotionEvent.ACTION_UP:
//
弹起手指后,切换屏幕的处理
if
(mTouchState
==
TOUCH_STATE_SCROLLING)
{
final
VelocityTracker
velocityTracker
=
mVelocityTracker;
velocityTputeCurrentVelocity(1000,
mMaximumVelocity);
int
velocityY
=
(int)
velocityTracker.getYVelocity();
if
(Math.abs(velocityY)
>
SNAP_VELOCITY)
{
if(
velocityY
>
0
&&
mCurrentScreen
==
1
&&
mPageBottom.isAtTop()){
snapToScreen(mDataIndex-1);
}else
if(velocityY
<
0
&&
mCurrentScreen
==
0){
snapToScreen(mDataIndex+1);
}else{
snapToScreen(mDataIndex);
}
}
else
{
snapToDestination();
}
if
(mVelocityTracker
!=
null)
{
mVelocityTracker.recycle();
mVelocityTracker
=
null;
}
}else{
}
mTouchState
=
TOUCH_STATE_REST;
break;
default:
break;
}
return
true;
}
private
void
clearOnTouchEvents(){
mTouchState
=
TOUCH_STATE_REST;
if
(mVelocityTracker
!=
null)
{
mVelocityTracker.recycle();
mVelocityTracker
=
null;
}
}
private
void
snapToDestination()
{
//
计算应该去哪个屏
final
int
flipHeight
=
getHeight()
/
8;
int
whichScreen
=
-1;
final
int
topEdge
=
getCurrentView().getTop();
if(topEdge
<
getScrollY()
&&
(getScrollY()-topEdge)
>=
flipHeight
&&
mCurrentScreen
==
0){
//向下滑动
whichScreen
=
mDataIndex
+
1;
}else
if(topEdge
>
getScrollY()
&&
(topEdge
-
getScrollY())
>=
flipHeight
&&
mCurrentScreen
==
1){
//向上滑动
whichScreen
=
mDataIndex
-
1;
}else{
whichScreen
=
mDataIndex;
}
Log.e(TAG,
"snapToDestination
mDataIndex
=
"
+
mDataIndex);
Log.e(TAG,
"snapToDestination
whichScreen
=
"
+
whichScreen);
snapToScreen(whichScreen);
}
private
void
snapToScreen(int
dataIndex)
{
if
(!mScroller.isFinished())
return;
final
int
direction
=
dataIndex
-
mDataIndex;
mNextDataIndex
=
dataIndex;
boolean
changingScreens
=
dataIndex
!=
mDataIndex;
View
focusedChild
=
getFocusedChild();
if
(focusedChild
!=
null
&&
changingScreens)
{
focusedChild.clearFocus();
}
//在这里判断是否已到目标位置~
int
newY
=
0;
switch
(direction)
{
case
1:
//需要滑动到第二页
Log.e(TAG,
"the
direction
is
1");
newY
=
getCurrentView().getBottom();
//
最终停留的位置
break;
case
-1:
//需要滑动到第一页
Log.e(TAG,
"the
direction
is
-1");
Log.e(TAG,
"getCurrentView().getTop()
is
"
+
getCurrentView().getTop()
+
"
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 【地理】广西防城港市防城区2023-2024学年七年级下学期第一次月考(解析版)
- 意向金合同范本7篇
- 二级动火作业安全管理规定 26E
- 民族园区建设计划
- 《桂花病虫害防治技术》课程标准
- 物流中标通知书
- 改善早泄的草药配方
- 建筑工地:工人传染病风险评估
- 2024年西式快餐行业现状及发展趋势研究
- 烟草园丁:病虫害诊断与治疗策略
- 流体流动阻力的测定课件
- 篮球英语2完整版教育课件
- 小学语文作业分层布置实施方案
- DB50-T 1284-2022 爆炸危险场所雷电防护指南
- 第一种形态“谈话”表
- 2022年西安美术学院附属中等美术学校(西美附中)模拟英语
- 职高招生班主任经验交流发言材料
- 课题中期汇报课件
- 膝关节置换术护理课件
- 加气站安全生产责任制
- 2021年保定市高碑店市事业单位招聘笔试试题及答案解析
评论
0/150
提交评论