开头:每天记录一下自己学习到了什么,在此记录一下,这样才不会忘记。
1.思路是这样的。
1.1 自定义一个ViewGroup,里面嵌套两个ScollerView实现商品详情模仿图。
1.2 当第一个ScollerView 下拉到最底部的时候在向上滑动,就滑动到第二页,当第二页滑动到最顶部的时候,在滑动就滑动到第一页。
说了这么多的滑动那就不可能是生硬的滚动,而是很循环渐进的效果。
在这里需要考虑一下,
我们怎么滑动?怎么在规定时间滑动到目的地?滑动的距离?
我们可能第一时间会想到ScrollTo/ScrollBy吧?
(ScrollTo/ScrollBy 是对ViewGroup的内容进行位移的)
如果大家想问下它们之间有什么区别的话,其实也可以直接看源码
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
这里发现ScrollyBy 和 ScrollTo 之间的并没有什么很大的区别,那么mScrollX和mScrollY有时什么啦?
这里说明下
mScrollX的值总是等于View左边缘和View内容左边缘在水平方向的距离
mScrollY的值总是等于View上边缘和View内容上边缘竖直方向距离。
他们只能改变View内容的位置而不能改变内容在布局的位置,
但是试过的朋友可能会感觉到这个效果是不是有点快了,没有一点前奏啦。
那就要试试这个两个方法搭配了。
/**
* startX—> X 开始位置
* startY—> Y 开始位置
* dx—–> X位移距离
* dy—–> Y位移距离
*/
1.startScroll(int startX, int startY, int dx, int dy) ;
2.computeScroll()
第一种方法大家其实可以看到其中源码
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}
怎么可以这样,这不只是初始化一些参数吗?也没有什么牛X的方法可以调用
那么接下来就的看 computeScroll()的功能啦
第二个方法是在我们draw事件中会调用computeScroll()方法,而computerScroll()方法可以获取当前的scrollX和ScrollY;
然后再通过通过ScollerTo方法,接着调用postInvalidate() 来实现滑动,不过这个时候调用postInvalidate()它会再次触发重绘这样一直反复到是否结束 ;
通过这该方法来判断
scroller.computeScrollOffset(),
那就来看下这个方法具体实现
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}
过了一天的晚上
晚上一直在实现这个功能了,正在接入项目中,赶脚还不错。
想说下思路吧。
由于是我自己写的ViewGroup,所以我就需要进行对其中的子控件进行定位置,我定的位置走向就是竖直排列。
排列子View位置前还需要走的一个流程就是 onMeasure
如果不懂的话,可以看到 View测绘事件
这是我排列的代码 —–》好吧 我承认我有借鉴linerLayout的 vertical 排列规则。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childTop = 0;
int count = getChildCount();
//设置布局 将子试图顺序竖屏显示。
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
final int childWidth = child.getMeasuredWidth();
final int childHeight = child.getMeasuredHeight();
Log.d(TAG, "childHeight=" + childHeight);
child.layout(0, childTop, childWidth, childTop + childHeight);
/** * 记录Top高度 */
childTop += childHeight;
}
}
}
—- 排列顺序ok了,那么我们接下来就是处理什么时候向上滚动,什么时候想下滚动了
1.在第一页滚动到底,然后手指向上位移,那么就滚动到第二页。
2.第二页手指向下位移,并且已经到头部了,就滚动到第一页。
3.滚动的长度大小。
(这里需要有分发事件概念)
声明:我是艺术探索的读者
如果满足以上的条件,就需要ViewGroup自己去处理,子类滚动,以及滚动的方向。
这里给出伪代码—很经典的列子
public boolean dispatchTouchEvent(MotionEvent ev){
boolean consume=false;
if(onInterceptTouchEvent(ev)){
consume=onTouchEvent(ev);
}eles{
consume=child.dispatchTouchEvent(ev);
}
return consume;
}
明天写 拦截事件,和 OnTouchEvent。
(赶脚处理的不好,需要思考一下)