您的位置:首页 > 产品设计 > UI/UE

简易UC首页demo续

2015-08-17 11:12 387 查看
Github代码已经更新:https://github.com/biricky/UCHome/tree/master

增加功能:

1.      增加下滑动画效果

2.      增加左滑及右滑动画效果(需要从屏幕边界处滑动,且作用View为存放图面的那个View)

 

功能实现

下滑动画

onInterceptTouchEvent()方法中由VelocityTracker的值判断手势动作方向及速度,调用setBackToOrigin方法完成动画效果,代码实现如下(略去第一版中存在的代码):

 

public void setBackToOrigin(){
if (!isOrigin){
....

TranslateAnimation viewGuide_ta = new TranslateAnimation(0,0,0,-mViewGuide.getHeight());
viewGuide_ta.setDuration(150);
viewGuide_ta.setFillAfter(true);
mViewGuide.setAnimation(viewGuide_ta);
viewGuide_ta.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub

}

@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub

}

@Override
public void onAnimationEnd(Animation animation) {
mViewGuide.setTranslationY(-mGuideHeight);
mViewGuide.clearAnimation();

}
});

mViewContent.setScrollY(-mViewContent.getScrollY());
TranslateAnimation viewContent_ta = new TranslateAnimation(0,0,mViewGuide.getHeight()-CONTENT_ORI_TOP_LOC,0);
viewContent_ta.setDuration(150);
viewContent_ta.setFillAfter(true);
mViewContent.setAnimation(viewContent_ta);
viewContent_ta.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub

}

@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub

}

@Override
public void onAnimationEnd(Animation animation) {
mViewContent.setTranslationY(0);
mViewContent.clearAnimation();

}
});

requestLayout();
}

}


侧滑动画

侧滑动作涉及的view比较多,动画也比较复杂,在实现中遇到了不小麻烦,举例三个最头痛的问题:

1.      如何将垂直滑动和水平滑动分开。这个问题没有解决,原因是使用了ViewDragHelper类,其中onTouchevent方法已经被覆盖,在进行滑动判断时会导致冲突,这个问题暴露了在设计方面的不足。

解决办法:退而求其次,使用边界拖拽,ViewDragHelper中提供了onEdgeDragStarted方法,该方法会在从边界滑动时调用,于是可以通过设置Flag完成垂直和水平滑动的分离。

2.      如何实现页面叠加的效果。开始很纠结,后来找到了bringtofront方法,顿时欣喜,但是没有提供这个方法的逆方法!这个问题的处理上很挑战逻辑,连蒙带猜解决了数个View的层次问题。这个问题证明逻辑很重要。

3.      动画效果计算。在进行动画效果设置时,尤其是自动的动画效果设置,需要用到不少算数知识,在动画的处理过程中,参数的设置花费了不少时间。这个问题暴露了对getWidth()、getBottom()等方法的理解不透彻。

 

整体的实现思路是:设置Flag将水平滑动与垂直滑动分离,在处理过程中,水平滑动的处理在onTouchevent中完成,而垂直滑动的处理和第一版相同,通过ViewDragHelper回调函数实现。具体实现如下:

public void onEdgeDragStarted(int edgeFlags, int pointerId) {
mDragHelper.captureChildView(mViewContent, pointerId);
if (!isShowNews){
isEdgeDrag = true;
}
}

该方法是ViewDragHelper回调函数提供的,在其中设置isEdgeDrag为true表示水平滑动。(isShowNews解决的问题是防止viewContent(带图画的view)上滑之后仍可进行边界滑动)

下面是onTouchevent实现。

public boolean onTouchEvent(MotionEvent event) {
if (!isEdgeDrag){
mDragHelper.processTouchEvent(event);
}
else {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
SlideWithHand(event);
}
if(event.getAction() == MotionEvent.ACTION_UP) {
if (!isShowNews){
if (getWidth()-event.getX() > getWidth()/3) {
SlideToLeftAuto(event);
}else {
SlideBackToRight(event);
}
}
else {
mDragHelper.smoothSlideViewTo(mViewContent, 0, mGuideHeight);
return true;
}
}
}
return false;
}
if语句用来处理垂直滑动,else完成水平滑动的处理,在ACTION_MOVE中的处理是这样的:

 public void SlideWithHand(MotionEvent event){ if (!isShowNews) {
float dx = event.getX();
float dy = event.getX()/getWidth();
float scale_dy = (getWidth()-event.getX())/getWidth();

mViewSecond.bringToFront();
mViewSearch.bringToFront();

mViewSecond.setTranslationX(dx-getWidth());
mViewSearch.setTranslationY(dy*search_len-search_len);

mTextViewinputSearch.setTranslationY(searchview_len-dy*searchview_len);
mTextViewinputSearch.setPivotX(getMeasuredWidth()/2);
mTextViewinputSearch.setPivotY(mViewGuide.getTop());
mTextViewinputSearch.setScaleX((1+scale_dy*0.2f));
mTextViewinputSearch.setScaleY((1+scale_dy*0.1f));

mViewWebGuide.setTranslationX(dx-getWidth());
mViewContent.setTranslationX(dx-getWidth());
if (!isDragEdgeOnRight) {
setBackToOrigin_Horizontal();
}
}
}
这里基本是动画效果的实现。最后一个if语句的作用要说明一下:当页面滑动到最左之后,mViewContent(带图片的view,也是DragHelper跟踪的view)的右边变为了屏幕的左边,所以从左边向右边的拖拽是允许的,这里做的处理是调用setBackToOrigin_Horizontal()让他自动恢复到原始状态。
下面是ACTION_UP的处理,设定当拖拽大于屏幕的三分之一时,切换到第二页,自动滑动的效果实现是这样的:
public void SlideToLeftAuto(MotionEvent event){
isOrigin_left = false;
isDragEdgeOnRight = false;

TranslateAnimation textview_ta = new TranslateAnimation(0, 0, 0, searchview_len-mTextViewinputSearch.getTranslationY());
textview_ta.setDuration(250);
textview_ta.setFillAfter(true);
mTextViewinputSearch.startAnimation(textview_ta);
TranslateAnimation viewsearch_ta = new TranslateAnimation(0, 0, 0, -search_len-mViewSearch.getTranslationY());
viewsearch_ta.setDuration(250);
viewsearch_ta.setFillAfter(true);
mViewSearch.startAnimation(viewsearch_ta);
requestLayout();

TranslateAnimation viewContent_ta = new TranslateAnimation(0, mViewContent.getX(), 0, 0);
viewContent_ta.setDuration(350);
viewContent_ta.setFillAfter(true);
mViewWebGuide.setAnimation(viewContent_ta);
mViewContent.setAnimation(viewContent_ta);

mDragHelper.smoothSlideViewTo(mViewSecond, (int) (getWidth() - mViewSecond.getX()), mViewGuide.getBottom());
postInvalidate();
}

实现非常简单,但是在实现过程中遇到了这样的问题:smoothSlideViewTo()方法不允许同时调用多次,如果调用多次,最终将只处理最后一个指定的子View的动作,一定要记得使用postInvalidate完成更新(这里有涉及到postInvalidate与Invalidate的区别),这里也浪费了很多的时间…。
当滑动不到三分之一时,实现方法如下:
public void SlideBackToRight(MotionEvent event) {
isOrigin_left = true;
isDragEdgeOnRight = true;

TranslateAnimation view_ta = new TranslateAnimation(0, -mViewContent.getTranslationX(), 0, 0);
view_ta.setDuration(200);
view_ta.setFillAfter(true);
mViewContent.setAnimation(view_ta);
mViewWebGuide.setAnimation(view_ta);
TranslateAnimation viewsearch_ta = new TranslateAnimation(0,0, 0,-mViewSearch.getTranslationY());
viewsearch_ta.setDuration(200);
viewsearch_ta.setFillAfter(true);
mViewSearch.setAnimation(viewsearch_ta);
viewsearch_ta.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationRepeat(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {
mViewSearch.setTranslationY(0);
mViewSearch.clearAnimation();
}
});

ScaleAnimation scale = new ScaleAnimation(mViewSearch.getScaleX(), 1, mViewSearch.getScaleY(), 1);
scale.setDuration(200);
scale.setFillAfter(true);
mTextViewinputSearch.setAnimation(scale);
scale.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationRepeat(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {
mTextViewinputSearch.clearAnimation();

}
});

TranslateAnimation viewSecond_ta = new TranslateAnimation(0,-mViewSecond.getTranslationX(),0,0);
viewSecond_ta.setDuration(200);
viewSecond_ta.setFillAfter(true);
mViewSecond.setAnimation(
a3df
viewSecond_ta);
view_ta.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationRepeat(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {
mViewContent.setTranslationX(0);
mViewWebGuide.setTranslationX(0);
mViewSearch.setTranslationX(0);
mViewContent.clearAnimation();
mViewWebGuide.clearAnimation();
mViewSearch.clearAnimation();
}
});
viewSecond_ta.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationRepeat(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {
mViewSecond.setTranslationX(0);
mViewSecond.clearAnimation();
}
});
requestLayout();

mDragHelper.smoothSlideViewTo(mViewContent, 0, CONTENT_ORI_TOP_LOC);
postInvalidate();

isEdgeDrag = false;
mViewGuide.bringToFront();
mViewContent.bringToFront();
mViewBottom.bringToFront();
}
代码比较长,同样动画效果的实现可以通过代码清楚理解。最后三行很重要,他们的顺序以及三行之间的顺序都不能改变,不要问我为什么,血的经验!因为View的层次会影响整体的动画效果,所以在使用BringTofront()是一定要慎重!
至此,这个简易的demo算是告一段落了,其中发现了许多的问题和不足:
1.      代码设计很差。因为对各方法的不熟悉,对动画的不清楚,在实现初期略过了设计阶段,走一步算一步的方式最终导致自己可能会被自己写的代码的逻辑绕晕。
2.      很多实现细节不够精细,使用的方法也是比较笨拙的方法,这还需要后续不断的学习和积累。
3.      对每个方法的理解还不够透彻。在每使用一个方法时一定要对其理解透彻,否则会造成:“应该可以的啊怎么就没达到想要的效果呢”这样白痴的想法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android ui 动画 uc