天天看點

android多個頁面滑動視圖實作

android設計中,有時需要實作一組頁面進行滑動,例如在一個Activity視圖中,頂部是一個導航欄,底部是菜單欄 ,中間是3個可以滑動的區域,其功能跟android系統的Launcher的workspace相似 。

程式運作界面效果:

android多個頁面滑動視圖實作
android多個頁面滑動視圖實作
android多個頁面滑動視圖實作

以下為核心代碼:

布局檔案: res/layout/main.xml:

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

<RelativeLayout

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

    Android:layout_width="fill_parent"

    Android:layout_height="fill_parent"

    Android:orientation="vertical">

    <RelativeLayout

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

        Android:id="@+id/view_top"

        Android:orientation="horizontal"

        Android:layout_width="fill_parent"

        Android:layout_height="wrap_content"

        Android:layout_alignParentTop="true"

        Android:gravity="center">

        <TextView

            Android:text="head"

            Android:textSize="15pt"

            Android:layout_width="fill_parent"

            Android:layout_height="wrap_content" />

        <ImageView

            Android:layout_width="wrap_content"

            Android:layout_height="wrap_content"

            Android:src="@drawable/btn_star_1"

            Android:id="@+id/imageView1"

            Android:layout_alignParentTop="true"

            Android:layout_alignParentRight="true"></ImageView>

        <TextView

            Android:layout_width="wrap_content"

            Android:id="@+id/textView_header"

            Android:text="center page"

            Android:layout_height="wrap_content"

            Android:textAppearance="?android:attr/textAppearanceMedium"

            Android:layout_centerVertical="true"

            Android:layout_alignParentLeft="true"

            Android:layout_marginLeft="78dp"></TextView>

    </RelativeLayout>

    <RelativeLayout

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

        Android:id="@+id/view_bottom"

        Android:orientation="horizontal"

        Android:layout_width="fill_parent"

        Android:layout_height="wrap_content"

        Android:layout_alignParentBottom="true"

        Android:gravity="center">

        <TextView

            Android:text="footer"

            Android:textSize="15pt"

            Android:layout_width="fill_parent"

            Android:layout_height="wrap_content" />

    </RelativeLayout>

    <com.xxx.ScrollLayout

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

        Android:id="@+id/ScrollLayoutID"

        Android:layout_width="fill_parent"

        Android:layout_height="fill_parent"

        Android:orientation="vertical"

        Android:layout_above="@id/view_bottom"

        Android:layout_below="@id/view_top">

        <LinearLayout

            Android:background="#ffffffff"

            Android:layout_width="fill_parent"

            Android:layout_height="fill_parent">

            <Button

                Android:layout_width="wrap_content"

                Android:layout_height="wrap_content"

                Android:text="Left" />

        </LinearLayout>

        <LinearLayout

            Android:background="#ffffffff"

            Android:layout_width="fill_parent"

            Android:layout_height="fill_parent">

            <Button

                Android:layout_width="wrap_content"

                Android:layout_height="wrap_content"

                Android:text="Center" />

        </LinearLayout>

        <LinearLayout

            Android:background="#ffffffff"

            Android:layout_width="wrap_content"

            Android:layout_height="wrap_content">

            <Button

                Android:layout_width="wrap_content"

                Android:layout_height="wrap_content"

                Android:text="Right" />

        </LinearLayout>

    </com.xxx.ScrollLayout>

</RelativeLayout>

自定義控件 ScrollLayout.java  :

package com.xxx;

import android.content.Context;

import android.util.AttributeSet;

import android.util.Log;

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 static final String TAG = "ScrollLayout";      

    private Scroller mScroller = null;      

    private VelocityTracker mVelocityTracker = null;      

    private int mCurScreen = 0;      

    private int mDefaultScreen = 1;      

    private static final int TOUCH_STATE_REST = 0;      

    private static final int TOUCH_STATE_SCROLLING = 1;      

    private static final int SNAP_VELOCITY = 600;      

    private int mTouchState = TOUCH_STATE_REST;      

    private int mTouchSlop = 0;      

    private float mLastMotionX = 0;      

    private float mLastMotionY = 0;     

    private OnScreenChangedListener mOnScreenChangedListener;

    public void setOnScreenChangedListener(OnScreenChangedListener l){

    mOnScreenChangedListener = l;

    }

    public interface OnScreenChangedListener {

    void onScreenChanged(ScrollLayout sc ,int whichScreen);

    }

    public ScrollLayout(Context context, AttributeSet attrs) {      

        this(context, attrs, 0);

    }

    public ScrollLayout(Context context, AttributeSet attrs, int defStyle) {      

        super(context, attrs, defStyle);

        mScroller = new Scroller(context);      

        mCurScreen = mDefaultScreen;      

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

    }      

    @Override      

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

        // TODO Auto-generated method stub      

        if (changed) {      

            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) {         

        Log.e(TAG, "onMeasure");      

        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 can 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);         

        }         

        // Log.e(TAG, "moving to screen "+mCurScreen);         

        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      

        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    

            mOnScreenChangedListener.onScreenChanged(this, mCurScreen);

        }      

    }      

    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() {      

        if (mScroller.computeScrollOffset()) {      

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

            postInvalidate();      

        }      

    }   

    @Override      

    public boolean onTouchEvent(MotionEvent event) {

        if (mVelocityTracker == null) {      

            mVelocityTracker = VelocityTracker.obtain();      

        }      

        mVelocityTracker.addMovement(event);      

        final int action = event.getAction();      

        final float x = event.getX();      

        final float y = event.getY();      

        switch (action) {      

            case MotionEvent.ACTION_DOWN:      

                Log.e(TAG, "event down!");      

                if (!mScroller.isFinished()){      

                    mScroller.abortAnimation();      

                }      

                mLastMotionX = x;      

                break;      

            case MotionEvent.ACTION_MOVE:      

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

                mLastMotionX = x;      

                scrollBy(deltaX, 0);      

                break;      

            case MotionEvent.ACTION_UP:      

                Log.e(TAG, "event : up");         

                // if (mTouchState == TOUCH_STATE_SCROLLING) {         

                final VelocityTracker velocityTracker = mVelocityTracker;         

                velocityTracker.computeCurrentVelocity(1000);         

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

                Log.e(TAG, "velocityX:"+velocityX);       

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

                    // Fling enough to move left         

                    Log.e(TAG, "snap left");      

                    snapToScreen(mCurScreen - 1);         

                } else if (velocityX < -SNAP_VELOCITY         

                        && mCurScreen < getChildCount() - 1) {         

                    // Fling enough to move right         

                    Log.e(TAG, "snap 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) {       

        Log.e(TAG, "onInterceptTouchEvent-slop:"+mTouchSlop);      

        final int action = ev.getAction();      

        if ((action == MotionEvent.ACTION_MOVE) &&       

                (mTouchState != TOUCH_STATE_REST)) {      

            return true;      

        }      

        final float x = ev.getX();      

        final float y = ev.getY();      

        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;      

                mLastMotionY = y;      

                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;      

    }      

}      

Main.java :

package com.xxx;

import com.ex84.ScrollLayout.OnScreenChangedListener;

import android.app.Activity;

import android.content.res.Resources;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnFocusChangeListener;

import android.widget.ImageView;

import android.widget.TextView;

public class MainActivity extends Activity implements OnScreenChangedListener {

private ImageView mImageView;

private TextView mTextView;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

ScrollLayout scrollLayout = (ScrollLayout) findViewById(R.id.ScrollLayoutID);

int curScreen = scrollLayout.getCurScreen();

scrollLayout.setOnScreenChangedListener(this);

mImageView = (ImageView) findViewById(R.id.imageView1);

mTextView = (TextView) findViewById(R.id.textView_header);

}

@Override

public void onScreenChanged(ScrollLayout sc, int whichScreen) {

switch (whichScreen) {

case 0:

mImageView.setImageResource(R.drawable.btn_star_0);

mTextView.setText("left page");

break;

case 1:

mTextView.setText("center page");

mImageView.setImageResource(R.drawable.btn_star_1);

break;

case 2:

mTextView.setText("right page");

mImageView.setImageResource(R.drawable.btn_star_2);

break;

}

}

}