android让你的TabHost滑动起来

在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; 
    } 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值