分享

TabHost通过手势切换Activity,滑动效果

 JUST SO LAZY 2012-05-14

一、自定义一个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表示放大

③参数fromXDeltatoXDelta都是指控件相对于parent的偏移距离,100%p就是正好在parent外面。左右是fromto来决定的(就是在根的左和右)。

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一定要有TabWidgetFramLayout这两个控件,并且TabWidget必须使用系统ID @android:id/tabsFrameLayout作为标签内容的基本框架,也必须使用系统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():初始化。设置各选项卡的iconidintent

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,由子ViewdispatchTouchEvent()方法再来派发。因此,要清楚自己的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轴移动的速度 单位:像素/

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多