您的位置:首页 > 移动开发 > Android开发

android让你的TabHost滑动起来

2012-09-12 17:06 281 查看
在Android应用中,一般TabActivity和若干个Tab选项卡(TabWidget)。如果选项卡的数量超过了5个,就不适合放到一个屏幕中,这样可以让这些选项卡滑动起来。

滑动的选项卡的实现有好几种方式,在这些方式中,最简单也是我最满意的还是在原生的TabActivity上修改,将上面的选项卡改为可滑动的状态。这样既有新的滑动的效果,也保留了原有TabActivity的各项功能。

实现Tab可滑动基本的思路就是把上面的TabWidget放到一个HorizontalScrollView中,让TabWidget滑动起来。不过如果仅仅修改XML还是会产生问题,就是没有办法控制每个选项卡的宽度。所以还是需要在程序中设置每个选项卡的宽度。例如:

[java] 

// 设置窗口的宽度  

DisplayMetrics dm = new DisplayMetrics();  

getWindowManager().getDefaultDisplay().getMetrics(dm);  

int screenWidth = dm.widthPixels;  

if (count < 4) {  

    for (int i = 0; i < count; i++) {  

        // 设置每个选项卡的宽度  

        tabWidget.getChildTabViewAt(i).setMinimumWidth(screenWidth / 4);  

    }  



自定义TabActivity主界面的XML:

[html]

<?xml version="1.0" encoding="utf-8"?>  

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 

    android:orientation="vertical" android:layout_width="fill_parent" 

    android:layout_height="fill_parent">  

    <TabHost android:id="@android:id/tabhost" android:layout_width="fill_parent" 

        android:layout_height="fill_parent">  

        <LinearLayout android:orientation="vertical" 

            android:layout_width="fill_parent" android:layout_height="fill_parent">  

            <HorizontalScrollView android:layout_height="wrap_content" 

                android:layout_width="fill_parent" android:scrollbars="none">  

                <TabWidget android:id="@android:id/tabs" 

                    android:layout_width="fill_parent" android:layout_height="60dp" />  

            </HorizontalScrollView>  

            <FrameLayout android:id="@android:id/tabcontent" 

                android:layout_width="fill_parent" android:layout_height="wrap_content" 

                android:layout_weight="1" />  

        </LinearLayout>  

    </TabHost>  

</LinearLayout> 

效果图如下



上面的tab是可以滑动的,屏幕左右滑动,tab也会切换

[java]

package com.xu81.testflip; 

 

import java.util.Vector; 

 

import android.content.Context; 

import android.util.AttributeSet; 

import android.view.MotionEvent; 

import android.view.VelocityTracker; 

import android.view.View; 

import android.view.ViewConfiguration; 

import android.view.ViewGroup; 

import android.widget.Scroller; 

 

public class ScrollLayout extends ViewGroup { 

 

    private Scroller mScroller; 

    private VelocityTracker mVelocityTracker; 

    private int mCurScreen; 

    private int mDefaultScreen = 0; 

    private static final int TOUCH_STATE_REST = 0; 

    private static final int TOUCH_STATE_SCROLLING = 1; 

    private static final int SNAP_VELOCITY = 500; 

    private int mTouchState = TOUCH_STATE_REST; 

    private int mTouchSlop; 

    private float mLastMotionX; 

    private int sensitivity = 30; 

    private boolean spring; 

    private Vector<LayoutChangeListener> listeners; 

 

    public ScrollLayout(Context context, AttributeSet attrs) { 

        super(context, attrs); 

        // TODO Auto-generated constructor stub 

        mScroller = new Scroller(context); 

        mCurScreen = mDefaultScreen; 

        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); 

        listeners = new Vector<LayoutChangeListener>(); 

    } 

 

    public void addChangeListener(LayoutChangeListener listener) { 

        listeners.add(listener); 

    } 

 

    @Override 

    protected void onLayout(boolean changed, int l, int t, int r, int b) { 

        // TODO Auto-generated method stub 

        int childLeft = 0; 

        final int childCount = getChildCount(); 

        for (int i = 0; i < childCount; i++) { 

            final View childView = getChildAt(i); 

            if (childView.getVisibility() != View.GONE) { 

                final int childWidth = childView.getMeasuredWidth(); 

                childView.layout(childLeft, 0, childLeft + childWidth, 

                        childView.getMeasuredHeight()); 

                childLeft += childWidth; 

            } 

        } 

    } 

 

    @Override 

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 

        super.onMeasure(widthMeasureSpec, heightMeasureSpec); 

        final int width = MeasureSpec.getSize(widthMeasureSpec); 

        final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 

        if (widthMode != MeasureSpec.EXACTLY) { 

            throw new IllegalStateException( 

                    "ScrollLayout only canmCurScreen run at EXACTLY mode!"); 

        } 

 

        final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 

        if (heightMode != MeasureSpec.EXACTLY) { 

            throw new IllegalStateException( 

                    "ScrollLayout only can run at EXACTLY mode!"); 

        } 

 

        // The children are given the same width and height as the scrollLayout 

        final int count = getChildCount(); 

        for (int i = 0; i < count; i++) { 

            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); 

        } 

        scrollTo(mCurScreen * width, 0); 

    } 

 

    public void snapToDestination() { 

        final int screenWidth = getWidth(); 

        final int destScreen = (getScrollX() + screenWidth / 2) / screenWidth; 

        snapToScreen(destScreen); 

    } 

 

    public void snapToScreen(int whichScreen) { 

        // get the valid layout page 

        int lastIndex = mCurScreen; 

        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); 

        if (getScrollX() != (whichScreen * getWidth())) { 

 

            final int delta = whichScreen * getWidth() - getScrollX(); 

            mScroller.startScroll(getScrollX(), 0, delta, 0, 

                    Math.abs(delta) * 2); 

            mCurScreen = whichScreen; 

            invalidate(); // Redraw the layout 

        } 

        for (LayoutChangeListener listener : listeners) 

            listener.doChange(lastIndex, whichScreen); 

    } 

 

    public void setToScreen(int whichScreen) { 

        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); 

        mCurScreen = whichScreen; 

        scrollTo(whichScreen * getWidth(), 0); 

    } 

 

    public int getCurScreen() { 

        return mCurScreen; 

    } 

 

    @Override 

    public void computeScroll() { 

        // TODO Auto-generated method stub 

        if (mScroller.computeScrollOffset()) { 

            scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); 

            postInvalidate(); 

        } 

    } 

 

    public boolean isSpring() { 

        return spring; 

    } 

 

    public void setSpring(boolean spring) { 

        this.spring = spring; 

    } 

 

    @Override 

    public boolean onTouchEvent(MotionEvent event) { 

        // TODO Auto-generated method stub 

        if (mVelocityTracker == null) 

            mVelocityTracker = VelocityTracker.obtain(); 

        mVelocityTracker.addMovement(event); 

        final int action = event.getAction(); 

        final float x = event.getX(); 

        switch (action) { 

        case MotionEvent.ACTION_DOWN: 

            if (!mScroller.isFinished()) 

                mScroller.abortAnimation(); 

            mLastMotionX = x; 

            break; 

        case MotionEvent.ACTION_MOVE: 

            int deltaX = (int) (mLastMotionX - x); 

            if (Math.abs(deltaX) > sensitivity) { 

                // 左滑动为正数、右为负数 

                if (spring) { 

                    scrollBy(deltaX, 0); 

                    mLastMotionX = x; 

                } else { 

                    final int childCount = getChildCount(); 

                    boolean max = mCurScreen < childCount - 1; 

                    boolean min = mCurScreen > 0; 

                    boolean canMove = deltaX > 0 ? (max ? true : false) 

                            : (min ? true : false); 

                    if (canMove) { 

                        scrollBy(deltaX, 0); 

                        mLastMotionX = x; 

                    } 

                } 

            } 

            break; 

        case MotionEvent.ACTION_UP: 

            final VelocityTracker velocityTracker = mVelocityTracker; 

            velocityTracker.computeCurrentVelocity(1000); 

            int velocityX = (int) velocityTracker.getXVelocity(); 

            if (velocityX > SNAP_VELOCITY && mCurScreen > 0) { 

                // Fling enough to move left 

                snapToScreen(mCurScreen - 1); 

            } else if (velocityX < -SNAP_VELOCITY 

                    && mCurScreen < getChildCount() - 1) { 

                // Fling enough to move right 

                snapToScreen(mCurScreen + 1); 

            } else { 

                snapToDestination(); 

            } 

            if (mVelocityTracker != null) { 

                mVelocityTracker.recycle(); 

                mVelocityTracker = null; 

            } 

            mTouchState = TOUCH_STATE_REST; 

            break; 

        case MotionEvent.ACTION_CANCEL: 

            mTouchState = TOUCH_STATE_REST; 

            break; 

        } 

        return true; 

    } 

 

    @Override 

    public boolean onInterceptTouchEvent(MotionEvent ev) { 

        // TODO Auto-generated method stub 

        final int action = ev.getAction(); 

        if ((action == MotionEvent.ACTION_MOVE) 

                && (mTouchState != TOUCH_STATE_REST)) 

            return true; 

        final float x = ev.getX(); 

        switch (action) { 

        case MotionEvent.ACTION_MOVE: 

            final int xDiff = (int) Math.abs(mLastMotionX - x); 

            if (xDiff > mTouchSlop) 

                mTouchState = TOUCH_STATE_SCROLLING; 

            break; 

        case MotionEvent.ACTION_DOWN: 

            mLastMotionX = x; 

            mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST 

                    : TOUCH_STATE_SCROLLING; 

            break; 

        case MotionEvent.ACTION_CANCEL: 

        case MotionEvent.ACTION_UP: 

            mTouchState = TOUCH_STATE_REST; 

            break; 

        } 

        return mTouchState != TOUCH_STATE_REST; 

    } 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息