您的位置:首页 > 移动开发 > Android开发

Android处子Demo—简易的UC首页动画

2015-08-10 17:39 561 查看
源代码在这里:https://github.com/biricky/UCHome

源代码说明:

功能的实现在UCLinear.java文件中,返回键及home键的监听在MainActivity中。

忽略DragHelperCallBack及NewsSetting两个文件。

UI抽象

  

            

整体布局:将首页的布局抽象为五部分:

第一部分是被隐藏的新闻导航栏,暂时用TextView替代;

第二部分是搜索栏,用TextView替代;

第三部分为网站导航,由多个Button组成,仅画一个作为代表;

第四部分为新闻栏,使用ScrollView实现;

第五部分为底部导航,由多个Button横向线性排列;

源代码位置:res/layout/

 

类介绍

介绍具体实现之前,要介绍一下使用到的几个类。

两个最最最重要的类

ViewDragHelp 

https://developer.android.com/reference/android/support/v4/widget/ViewDragHelper.html

直接把它的说明翻译过来(英语很渣...):

ViewDragHelper是一个用来编写用户自定义ViewGroups的实用类,它为用户提供了许多实用的方法,可以跟踪用户的拖拽动作,并可以重新定位子views在其父ViewGroup中的位置。

 

ViewDragHelp.Callback

http://developer.android.com/reference/android/support/v4/widget/ViewDragHelper.Callback.html

类的名字已经很明显了,就是ViewDragHelper的回调函数。

关于他的使用方法,这里给了一个非常好的总结:http://flavienlaurent.com/blog/2013/08/28/each-navigation-drawer-hides-a-viewdraghelper/

VelocityTracker

http://developer.android.com/reference/android/view/VelocityTracker.html

获取滑动速度的类。

UCLinear.java

package com.example.ucfirstpage;

import android.R.bool;
import android.R.integer;
import android.content.Context;
import android.support.v4.view.VelocityTrackerCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationSet;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterViewAnimator;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class UCLinear extends RelativeLayout{
private static int CONTENT_ORI_TOP_LOC;

private boolean isInRange = true;
public boolean isOrigin = true; //是否是初始状态,用于返回判断

private ViewDragHelper mDragHelper;
private DragHelperCallback mCallBack;
private VelocityTracker mVTracker;

private int mGuideHeight; //导航栏高度
private int mSearchHeight; //搜索栏高度
private int mWebGuideHeight; //网站导航高度
private int mContentHeight; //内容高度
private int mTotalHeight;  //总高度

private View mViewGuide; //导航栏
private View mViewSearch; //搜索部分
private View mViewWebGuide; //网站导航
private View mViewContent; //内容
private View mViewBottom;//底部导航

//bottom中的五个button
private Button btnPrev,btnNext,btnMore,btnPage,btnToHome;

public UCLinear(Context context, AttributeSet attrs) {
super(context, attrs);

mCallBack = new DragHelperCallback();
mDragHelper = ViewDragHelper.create(this, mCallBack);
this.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
@Override
public boolean onPreDraw() {
CONTENT_ORI_TOP_LOC = mViewContent.getTop();
mGuideHeight = mViewGuide.getHeight();
mSearchHeight = mViewSearch.getHeight();
mWebGuideHeight = mViewWebGuide.getHeight();
mTotalHeight = UCLinear.this.getHeight();
mViewGuide.bringToFront();
mViewGuide.setTranslationY(-mGuideHeight);
UCLinear.this.getViewTreeObserver().removeOnPreDrawListener(this)
4000
;
return false;
}
});
}

public void setBackToOrigin(){
if (!isOrigin){
isInRange = true;
isOrigin = true;

mViewSearch.setScaleX(1);
mViewSearch.setScaleY(1);

mViewWebGuide.setScaleX(1);
mViewWebGuide.setScaleY(1);

TranslateAnimation btnPrev_ta = new TranslateAnimation(0,-btnPrev.getTranslationX(), 0, 0);
btnPrev_ta.setDuration(100);
btnPrev_ta.setFillAfter(true);
btnPrev.startAnimation(btnPrev_ta);
btnPrev.setAlpha(1);
btnPrev_ta.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}

@Override
public void onAnimationEnd(Animation animation) {
btnPrev.setTranslationX(0);
btnPrev.clearAnimation();

}
});

TranslateAnimation btnNext_ta = new TranslateAnimation(0,-btnNext.getTranslationX(), 0, 0);
btnNext_ta.setDuration(100);
btnNext_ta.setFillAfter(true);
btnNext.startAnimation(btnNext_ta);
btnNext.setAlpha(1);
btnNext_ta.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {
}

@Override
public void onAnimationRepeat(Animation animation) {
}

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

TranslateAnimation btnPage_ta = new TranslateAnimation(0,-btnPage.getTranslationX(),  0, 0);
btnPage_ta.setDuration(100);
btnPage_ta.setFillAfter(true);
btnPage.startAnimation(btnPage_ta);
btnPage.setAlpha(1);
btnPage_ta.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationRepeat(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {
btnPage.setTranslationX(0);
btnPage.clearAnimation();
}
});
TranslateAnimation btnToHome_ta = new TranslateAnimation(0, -btnToHome.getTranslationX(), 0, 0);
btnToHome_ta.setDuration(100);
btnToHome_ta.setFillAfter(true);
btnToHome.startAnimation(btnToHome_ta);
btnToHome_ta.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationRepeat(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {
btnToHome.setTranslationX(0);
btnToHome.clearAnimation();
}
});
btnMore.setAlpha(1);

mViewGuide.setTranslationY(-mGuideHeight);
mViewContent.setScrollY(-mViewContent.getScrollY());
requestLayout();
}
}
//计算拖动速度
@Override
public void computeScroll() {
if(mDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mVTracker == null) {
mVTracker = VelocityTracker.obtain();
}
mVTracker.addMovement(ev);
final VelocityTracker vt = mVTracker;
if (ev.getAction() == MotionEvent.ACTION_MOVE) {
vt.computeCurrentVelocity(1000);
if ( vt.getYVelocity() < -1500 && isInRange) {
mDragHelper.smoothSlideViewTo(mViewContent, 0, mGuideHeight);
this.postInvalidate();

isInRange = false;
isOrigin = false;

return false;
}
else if (vt.getYVelocity() > 500 && mViewContent.getScrollY() == 0) {
this.setBackToOrigin();
return true;
}
}
return mDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mDragHelper.processTouchEvent(event);
return false;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mViewGuide.layout(
0,
0,
mViewGuide.getMeasuredWidth(),
mViewGuide.getMeasuredHeight());
mViewSearch.layout(
0,
0,
mViewSearch.getMeasuredWidth(),
mViewSearch.getMeasuredHeight());
mViewWebGuide.layout(
0,
mViewSearch.getMeasuredHeight(),
mViewWebGuide.getMeasuredWidth(),
mViewSearch.getMeasuredHeight()+mViewWebGuide.getMeasuredHeight());
mViewBottom.layout(
0,
getMeasuredHeight()-mViewBottom.getMeasuredHeight(),
mViewBottom.getMeasuredWidth(),
getMeasuredHeight());
mViewContent.layout(
0,
mViewWebGuide.getMeasuredHeight()+mViewSearch.getMeasuredHeight(),
mViewContent.getMeasuredWidth(),
mViewWebGuide.getMeasuredHeight()+mViewSearch.getMeasuredHeight()+
getMeasuredHeight()-mViewGuide.getMeasuredHeight()-
mViewBottom.getMeasuredHeight());
}

public void initButton(){
btnPrev = (Button) findViewById(R.id.btnPrev);
btnNext = (Button) findViewById(R.id.btnNext);
btnMore = (Button) findViewById(R.id.btnMore);
btnPage = (Button) findViewById(R.id.btnPage);
btnToHome = (Button) findViewById(R.id.btnToHome);
}
@Override
protected void onFinishInflate() {
initButton();
mViewGuide= findViewById(R.id.uc_guide);
mViewSearch=findViewById(R.id.uc_search);
mViewWebGuide=findViewById(R.id.uc_webguide);
mViewContent=findViewById(R.id.uc_news);
mViewBottom=findViewById(R.id.uc_bottom);
}

class DragHelperCallback extends ViewDragHelper.Callback {

/**
* 设置mViewContent可拖拽
*/
@Override
public boolean tryCaptureView(View arg0, int arg1) {
if (mDragHelper.continueSettling(true))
return false;
return mViewContent == arg0 && isInRange;
}
/**
* 垂直拖拽的处理,这里对拖拽过程中mViewContent的移动进行处理
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
int topBound = mGuideHeight;
int bottomBound = mViewWebGuide.getBottom();
int newTop = Math.min(Math.max(top, topBound), bottomBound);
return newTop;
}
/**
* 水平拖拽的处理
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return super.clampViewPositionHorizontal(child, left, dx);
}
/**
* 水平可拖拽的距离范围
*/
@Override
public int getViewHorizontalDragRange(View child) {
return mViewContent.getWidth();
}
/**
* 垂直可拖拽的距离范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return mTotalHeight;
}
/**
* 监听到View位置的变化,完成其他view动画的处理
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {

//获取导航栏相对手指移动的相对距离
float guidedy = dy / (float)(mSearchHeight+mWebGuideHeight-mGuideHeight) * mGuideHeight;
mViewGuide.setTranslationY(mViewGuide.getTranslationY() - guidedy);

//设置mViewSearch及mViewWebGuide缩放效果
float scale = (float) ((mViewWebGuide.getBottom()-mViewContent.getTop()) /
(float)(mSearchHeight+mWebGuideHeight-mGuideHeight));
mViewSearch.setPivotY(mViewSearch.getTop());
mViewSearch.setPivotX(getWidth()/2);
mViewSearch.setScaleY(1-scale/10);
mViewSearch.setScaleX(1-scale/10);
mViewWebGuide.setPivotY(mViewSearch.getTop());
mViewWebGuide.setPivotX(getWidth()/2);
mViewWebGuide.setScaleY(1-scale/10);
mViewWebGuide.setScaleX(1-scale/10);

//设置bottom中各button的效果
float alphady = (mViewWebGuide.getBottom() - mViewContent.getTop())/
(float)(mSearchHeight+mWebGuideHeight-mGuideHeight);
btnMore.setAlpha(1-alphady);

float homedy_tran = dy / (float)(mSearchHeight+mWebGuideHeight-mGuideHeight) *
(mViewBottom.getWidth()/2-btnToHome.getWidth()/2);
btnToHome.setTranslationX(btnToHome.getTranslationX() + homedy_tran);

float pagedy_tran = dy/(float)(mSearchHeight+mWebGuideHeight-mGuideHeight) *
(btnPage.getWidth()/2+btnMore.getWidth()/2);
btnPage.setTranslationX(btnPage.getTranslationX() + pagedy_tran);
btnPage.setAlpha(1-alphady);

float prevdy_tran = dy / (float)(mSearchHeight+mWebGuideHeight-mGuideHeight) *
(mViewBottom.getWidth()/2-btnPrev.getWidth()/2);
btnPrev.setTranslationX(btnPrev.getTranslationX() - prevdy_tran);
btnPrev.setAlpha(1-alphady);

float nextdy_tran = dy/(float)(mSearchHeight+mWebGuideHeight-mGuideHeight) *
(btnNext.getWidth()/2+btnMore.getWidth()/2);
btnNext.setTranslationX(btnNext.getTranslationX() - nextdy_tran);
btnNext.setAlpha(1-alphady);
}
/**
* 释放拖拽后执行,根据mViewContent的拖拽距离决定是否上滑或返回原位
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
int movelen = CONTENT_ORI_TOP_LOC - mViewContent.getTop();
if (movelen > mWebGuideHeight){
isInRange = false;
isOrigin = false;
mDragHelper.settleCapturedViewAt(0, mGuideHeight);
postInvalidate();
}else {
mDragHelper.settleCapturedViewAt(0, CONTENT_ORI_TOP_LOC);
postInvalidate();
}
}
}
}

MainActivity.java实现

package com.example.ucfirstpage;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {
public UCLinear ucView;
public Button btnHome;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ucView = (UCLinear)findViewById(R.id.uc_liner);
btnHome = (Button) findViewById(R.id.btnToHome);
btnHome.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (!ucView.isOrigin) {
ucView.setBackToOrigin();
}else {

}
}
});
}

@Override
public void onBackPressed() {
if (!ucView.isOrigin) {
ucView.setBackToOrigin();
}else {
super.onBackPressed();
}
}
}
总结

收获:1. 学习了ViewGroup、View以及事件分发机制;

            2.  Animation的使用更熟练;

            3. 学习了ViewDragHelper;

            4.  Android UI的实现过程有了认识

            5. 熟悉了Android的开发环境

不足:

            1.下滑动画效果的处理不理想,这里需要解决ScrollView和ViewGroup动画冲突的问题,暂时想到的解决办法是覆盖ScrollView的onTouchevent()。

            2.还需要继续扩展其他首页动画

            3.经验太浅,对Android中的类了解的太少,导致实现的过程走了不少弯路。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android ui 动画 uc