本文简单介绍使用属性动画来实现上滑显示底部导航,下滑显示标题bar。先上图看效果,再分析:
可以看出这是个listview有标题和底部,有点像下拉刷新和上拉加载更多。只不过下拉或上拉一定时位置固定拉不动,且只在list的第一个item出现显示时,才平滑动画的让标题或底部显示或隐藏。
实现思路:
1、整个布局有三个部分构成,上部由一个RelativeLayout放ImageView或TextView.中间部分是个listView,下部是一个TextView.
2、采用LinearLayout摆放中下部分,让屏幕初始时把上部分移出屏幕外面。中间listview与底部往上移。
3、采用平移动画,移动动画有两种一种tween动画一种属性动画。而tween动画是假移事件焦点还在原来地方,而属性动画则是3.0支持的为了兼容3.0以下的这里采用nineoldandroids。
4、通过给listview设置touch listener,监听手掼是向下滑动的(Y比X移动距离大)且滑动距离足够大时,判断是向下反之亦然是向上。event move过程会有多次回调,为了保证在一次dowm 向下滑动时,需要在down 时设置标志,来保证一次down 向下滑动时只调用动画一次 做显示标题动作。
上代码:
布局文件:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
package com.test.projecta;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.TextureView;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.nineoldandroids.animation.ObjectAnimator;
public class HideShowTitleActivity extends Activity {
private RelativeLayout rl_title;
private ListView lv_data;
private List mListDatas;
private boolean mIsShowTitle = false;
private float mTranslateY;
private boolean mIsfirstVisible = true;
private TextView tv_bottom;
private float mBottomHeight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_newhideshowtitlelist_back);
findView();
setListener();
doLogic();
}
private void findView() {
rl_title = (RelativeLayout) findViewById(R.id.rl_title);
lv_data = (ListView) findViewById(R.id.lv_data);
tv_bottom = (TextView) findViewById(R.id.tv_bottom);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
if(hasFocus){
//获取listview的高度 那么bottom开始的位置是mTranslateY+height值
int height = lv_data.getHeight();
mBottomHeight = mTranslateY + height;
showHideTitle(false,0);
}
}
private void setListener() {
lv_data.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
//判断当前是否在显示list的第一项数据
mIsfirstVisible = firstVisibleItem==0;
//手掼滑动太快时非显示第一项还显示标题时,隐藏掉标题
if(mIsShowTitle && !mIsfirstVisible){
showHideTitle(false,500);
}
}
});
lv_data.setOnTouchListener(new OnTouchListener() {
private float lastX;
private float lastY;
boolean isChange = false;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = event.getX();
lastY = event.getY();
isChange = false;
return false;
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
float xGapDistance = Math.abs(x-lastX);
float yGapDistance = Math.abs(y-lastY);
boolean isDown = y-lastY>5;
//没有显示标题时,且是向下的,就显示
boolean isShow = yGapDistance > 8 && xGapDistance<8 && !mIsShowTitle && isDown;
boolean isHide = yGapDistance > 8 && xGapDistance<8 && mIsShowTitle && !isDown;
lastX = x;
lastY = y;
//一次down,只变化一次,防止一次滑动时抖动下,造成某一个的向下时,y比lastY小
if(!isChange&&mIsfirstVisible&&isShow){
// 显示此标题
showHideTitle(true,500);
isChange = true;
}//显示标题时,且是向上的,就隐蔽
else if(!isChange&&mIsfirstVisible&&isHide){
// 隐蔽标题
showHideTitle(false,500);
isChange = true;
}
break;
default:
break;
}
return false;
}
});
}
private void showHideTitle(boolean isShow,int duration) {
if(isShow){
ObjectAnimator.ofFloat(lv_data, "y",0,mTranslateY).setDuration(duration).start();
ObjectAnimator.ofFloat(rl_title, "y", -mTranslateY,0).setDuration(duration).start();
ObjectAnimator.ofFloat(tv_bottom, "y", mBottomHeight-mTranslateY,mBottomHeight).setDuration(duration).start();
}else{//隐藏时,把标题隐藏了,底部出来了
ObjectAnimator.ofFloat(lv_data, "y", mTranslateY,0).setDuration(duration).start();
ObjectAnimator.ofFloat(rl_title, "y", 0f,-mTranslateY).setDuration(duration).start();
ObjectAnimator.ofFloat(tv_bottom, "y", mBottomHeight,mBottomHeight-mTranslateY).setDuration(duration).start();
}
mIsShowTitle = isShow;
}
private void doLogic() {
mListDatas = new ArrayList();
for(int i=0;i<50;i++){
mListDatas.add("数据"+i);
}
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, mListDatas);
lv_data.setAdapter(adapter);
//将标题栏高度50dp转成显示的高度
mTranslateY = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics());
}
}