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

源代码在这里:https://github.com/biricky/UCHome

源代码说明:

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

忽略DragHelperCallBackNewsSetting两个文件。

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);
				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. 学习了ViewGroupView以及事件分发机制;

            2.  Animation的使用更熟练;

            3. 学习了ViewDragHelper

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

            5. 熟悉了Android的开发环境

不足:

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

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

            3.经验太浅,对Android中的类了解的太少,导致实现的过程走了不少弯路。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值