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
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中的类了解的太少,导致实现的过程走了不少弯路。
源代码说明:
功能的实现在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中的类了解的太少,导致实现的过程走了不少弯路。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories