一、自定义一个AnimationTabHost组件 ---------------------------------------------------------------------------------------------- AnimationTabHost.java 代码 /** 继承
TabHost 组件,带有切入切出的滑动动画效果。 */ public class AnimationTabHost extends TabHost { private Animation slideLeftIn; private Animation slideLeftOut; private Animation slideRightIn; private Animation slideRightOut;
/** 记录是否打开动画效果 */ private boolean isOpenAnimation; /** 记录当前标签页的总数 */ private int mTabCount;
public AnimationTabHost(Context
context, AttributeSet attrs) { super(context, attrs);
slideLeftIn = AnimationUtils.loadAnimation(context, R.anim.slide_left_in); slideLeftOut = AnimationUtils.loadAnimation(context, R.anim.slide_left_out); slideRightIn = AnimationUtils.loadAnimation(context, R.anim.slide_right_in); slideRightOut = AnimationUtils.loadAnimation(context, R.anim.slide_right_out);
isOpenAnimation = false; }
/** * 设置是否打开动画效果 * @param isOpenAnimation * true:打开 */ public void setOpenAnimation(boolean isOpenAnimation) { this.isOpenAnimation = isOpenAnimation; }
说明:这里的Animation都是自定义的动画效果,可以在res/anim中找到对应的XML文件,下面用slide_left_in.xml来说明定义的大概用法 slide_left_in.xml <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas./apk/res/android"> <translate android:fromXDelta="100%p"
android:toXDelta="0"
android:duration="800"/> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" /> </set> 说明: ①因为这个动画是由几个动画复合组成的,所以外围就用一个set标签括起来,组成一个AnimationSet。 ② Translate标签内主要定义位置的变化情况,fromXDelta="100%p",为动画起始时,X坐标上的伸缩尺寸。是指正下方刚好一个View的高度的距离的地方开始出现,100%p是一个相对值,大于0为下方,小于0为上方。toXDelta="0" ,为动画结束时,X坐标上的伸缩尺寸。另:0.0表示收缩到没有(即刚好达到布局文件的原始位置停止),1.0表示正常无伸缩,值小于1.0表示收缩,值大于1.0表示放大 。 ③参数fromXDelta和toXDelta都是指控件相对于parent的偏移距离,100%p就是正好在parent外面。左右是from和to来决定的(就是在根的左和右)。 ④duration="800",是指整个动作的时间用时为800毫秒,系统会根据这个时间自动调整速度。 ⑤alpha标签内定义的是透明度,0为全透明,1.0为不透明,过程为300毫秒,让View为逐渐出现的过程。
/** * 设置标签滑动动画。<br> * 动画顺序为“左进——>左出——>右进——>右出” * * @param animationResIDs * 动画的资源文件ID * @return true:四个动画文件;<br> * false:非四个动画文件(无法匹配,采用默认动画) */ public boolean setTabAnimation(int[] animationResIDs) { if (3 == animationResIDs.length) { slideLeftIn = AnimationUtils.loadAnimation(getContext(), animationResIDs[0]); slideLeftOut = AnimationUtils.loadAnimation(getContext(), animationResIDs[1]); slideRightIn = AnimationUtils.loadAnimation(getContext(), animationResIDs[2]); slideRightOut
=AnimationUtils.loadAnimation(getContext(), animationResIDs[3]);
return true; } else { return false; } }
/** * @return 返回当前标签页的总数 */ public int getTabCount() { return mTabCount; }
@Override public void addTab(TabSpec tabSpec) { mTabCount++; super.addTab(tabSpec); } @Override public void setCurrentTab(int index) { int mCurrentTabID = getCurrentTab();
if (null != getCurrentView()) { // 第一次设置 Tab 时,该值为 null。
if (isOpenAnimation) { if (mCurrentTabID == (mTabCount - 1) && index == 0) { getCurrentView().startAnimation(slideLeftOut); } else if (mCurrentTabID == 0
&& index == (mTabCount - 1)) { getCurrentView().startAnimation(slideRightOut); } else if (index > mCurrentTabID)
{ getCurrentView().startAnimation(slideLeftOut); } else if (index < mCurrentTabID)
{ getCurrentView().startAnimation(slideRightOut); } } }
super.setCurrentTab(index);
if (isOpenAnimation) { if (mCurrentTabID == (mTabCount - 1) && index ==
0) { getCurrentView().startAnimation(slideLeftIn); } else if (mCurrentTabID == 0 && index == (mTabCount - 1)) { getCurrentView().startAnimation(slideRightIn); } else if (index > mCurrentTabID) { getCurrentView().startAnimation(slideLeftIn); } else if (index < mCurrentTabID) { getCurrentView().startAnimation(slideRightIn); } } } }
说明:mTabCount为当前标签页的总数。setCurrentTab 设置当前标签页。index可以理解为:需要显示的那个标签页。
--------------------------------------------------------------------------------------------
二、TabHost选项卡 TabHostActivity.java 代码
public class TabHostActivity extends TabActivity implements OnTabChangeListener { private GestureDetector gestureDetector; private FrameLayout frameLayout;
private AnimationTabHost mTabHost; private TabWidget mTabWidget;
/** 记录当前分页ID */ private int currentTabID = 0;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.tab_host_test_view);
说明: ①OnTabChangeListener 接口,标签切换事件监听 ②使用TabHost有两种方法,一种是继承TabActivity;一种是不继承TabActivity;在这里是继承TabActivity的;首先我们得写好tab_host_test_view.xml布局文件,在写这个布局文件时要注意,使用TabHost一定要有TabWidget、FramLayout这两个控件,并且TabWidget必须使用系统ID @android:id/tabs;FrameLayout作为标签内容的基本框架,也必须使用系统ID
@android:id/tabcontent;而TabHost可以自定义ID,这是为了在系统初始化时能够使用,否则会报错!布局文件tab_host_test_view.xml如下: ------- tab_host_test_view.xml <net.courage.tab.view.AnimationTabHost xmlns:android="http://schemas./apk/res/android"
android:id="@android:id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent"
android:background="@drawable/default_bg"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
<FrameLayout android:gravity="center" android:id="@android:id/tabcontent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_weight="1.0"
/>
<TabWidget android:id="@android:id/tabs" android:background="#00ffffff" android:padding="3.0dip"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_weight="0.0"
/> </LinearLayout> </net.courage.tab.view.AnimationTabHost>
----------
mTabHost= (AnimationTabHost)findViewById(android.R.id.tabhost); mTabWidget = (TabWidget) findViewById(android.R.id.tabs); mTabHost.setOnTabChangedListener(this);
init();
gestureDetector = new GestureDetector(new TabHostTouch()); new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (gestureDetector.onTouchEvent(event)) { return true; } return false; } };
frameLayout = mTabHost.getTabContentView(); Log.i("TabHostActivity", "TabHostActivity====>>>onCreate()===>>>>frameLayout:
" + frameLayout.getChildCount()); } private void init() { setIndicator(R.drawable.tab_logo_0, 0, new Intent(this, TabHostTestOne.class)); setIndicator(R.drawable.tab_logo_1, 1, new Intent(this, TabHostTestTwo.class)); setIndicator(R.drawable.tab_logo_2, 2, new Intent(this, TabHostTestThree.class)); setIndicator(R.drawable.tab_logo_3, 3, new Intent(this, TabHostTestFour.class));
mTabHost.setOpenAnimation(true); } private void setIndicator(int icon, int tabId, Intent intent) {
View localView =
LayoutInflater.from(this.mTabHost.getContext()) .inflate(R.layout.tab_widget_view, null); ((ImageView)
localView.findViewById(R.id.main_activity_tab_image)) .setBackgroundResource(icon);
String str = String.valueOf(tabId); TabHost.TabSpec
localTabSpec =mTabHost.newTabSpec(str).setIndicator( localView).setContent(intent); mTabHost.addTab(localTabSpec); }
说明: ①mTabHost = (AnimationTabHost) findViewById(android.R.id.tabhost); mTabWidget = (TabWidget)
findViewById(android.R.id.tabs); 系统自带 ②init():初始化。设置各选项卡的icon、id、intent。 ③GestureDetector手势识别类。通过GestureDetector.OnGestureListener来获取当前被触发的操作手势。另:使用 OnTouchListener 可以比 OnClickListener 获得更细的控制粒度,例如涉及
down-touch/up-touch/no-drag ,多点,触摸的强度,按下,松开,拖动等。。。。,而 OnClickListener 只是点击,只适用于组件的事件触发。 ④使用setIndicator(localView)把localView添加进去。
public void onTabChanged(String tabId) { int tabID = Integer.valueOf(tabId);
for (int i = 0; i < mTabWidget.getChildCount(); i++) { if (i == tabID) { mTabWidget.getChildAt(Integer.valueOf(i)).setBackgroundColor( R.color.bule); } else { mTabWidget.getChildAt(Integer.valueOf(i)) .setBackgroundResource(R.drawable.main_meun_bg); } } }
说明:标签切换事件,使用getChildAt(int i)来取得每个标签
public boolean dispatchTouchEvent(MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) { event.setAction(MotionEvent.ACTION_CANCEL); }
return super.dispatchTouchEvent(event);
}
说明: dispatchOnTouchEvent()时派发事件,从最上层View开始派发,dispatchOnTouchEvent()返回true时,View将事件派发给自己onTouchEvent()方法处理,如果返回false,则交给interceptTouchEvent来决定是否要拦截,如果返回false,则传给子View,由子View的dispatchTouchEvent()方法再来派发。因此,要清楚自己的view的继承关系,不要派发到父类的窗口就可以了。 如果没有此段代码,点击各Tab,各页面之间跳转会有滑动动画效果,但是无法实现拖动页面时的动画效果。
private class TabHostTouch extends SimpleOnGestureListener { /** 滑动翻页所需距离
*/ private static final int ON_TOUCH_DISTANCE = 80;
public boolean onFling(MotionEvent e1,
MotionEvent e2, float velocityX, float velocityY) { if (e1.getX() - e2.getX()
<= (-ON_TOUCH_DISTANCE)) { currentTabID = mTabHost.getCurrentTab() - 1;
if (currentTabID < 0) { currentTabID = mTabHost.getTabCount() - 1; } } else if (e1.getX() - e2.getX() >= ON_TOUCH_DISTANCE) { currentTabID = mTabHost.getCurrentTab() + 1;
if (currentTabID >= mTabHost.getTabCount()) { currentTabID = 0; } } mTabHost.setCurrentTab(currentTabID); return false; } } }
说明: boolean onFling(MotionEvent e1, MotionEvent e2, float
velocityX, float velocityY) Touch了滑动一点距离后,up时触发。即用户按下屏幕,快速移动后松开(就是在屏幕上滑动) e1:第一个ACTION_DOWN事件(手指按下的那一点) e2:最后一个ACTION_MOVE事件 (手指松开的那一点) velocityX:手指在x轴移动的速度 单位:像素/秒
velocityY:手指在y轴移动的速度 单位:像素/秒
|
|
来自: JUST SO LAZY > 《java\android》