<?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" > <com.login.setup.SwitchLayout android:id="@+id/switchLayoutID" android:layout_width="fill_parent" android:layout_height="fill_parent" > <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/yindao_image_01" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/yindao_image_02" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/yindao_image_03" /> </com.login.setup.SwitchLayout> <LinearLayout android:id="@+id/linerLayoutID" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="24dip" android:orientation="horizontal" > <TextView android:layout_width="18sp" android:layout_height="18sp" android:layout_gravity="center_vertical" android:background="@drawable/guide_round" android:clickable="true" android:gravity="center" android:textSize="15sp" /> <TextView android:layout_width="18sp" android:layout_height="18sp" android:layout_gravity="center_vertical" android:background="@drawable/guide_round" android:clickable="true" android:gravity="center" android:textSize="15sp" /> <TextView android:layout_width="18sp" android:layout_height="18sp" android:layout_gravity="center_vertical" android:background="@drawable/guide_round" android:clickable="true" android:gravity="center" android:textSize="15sp" /> </LinearLayout> </RelativeLayout>
以上xml文件中引用的guide_round.xml (页面滑动下面的实心圈和空心圈)
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="true" android:drawable="@drawable/guide_dot_black" /> <item android:state_enabled="false" android:drawable="@drawable/guide_dot_white" /> </selector>
自定义组件 SwitchLayout
public class SwitchLayout extends ViewGroup { private int mCurScreen; // 瞬间速度 private static final int SNAP_VELOCITY = 600; // 改变imageView private OnViewChangeListener onViewChangeListener; // 拖动手势的速率跟踪器 private VelocityTracker tracker; // 滚动控制器 private Scroller scroller; private float mLastMotionX; private Context context; public SwitchLayout(Context context) { super(context); this.context = context; init(context); } public SwitchLayout(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; init(context); } public SwitchLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.context = context; init(context); } /** 初始化控件 */ private void init(Context context) { mCurScreen = 0; scroller = new Scroller(context); } @Override /** 必须要调用的方法 目的:当前的view在给自己的子控件指派大小和位置必须要调用的方法 */ protected void onLayout(boolean changed, int l, int t, int r, int b) { if (changed) { int childLeft = 0; int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); if (childView.getVisibility() != View.GONE) { int childWidth = childView.getMeasuredWidth(); // 子控件被填充在父控件中(第二个阶段,第一个阶段为onMeasure,即计算) childView.layout(childLeft, 0, childLeft + childWidth, childView.getMeasuredHeight()); // 改变左边的起始位置 childLeft += childWidth; } } } } @Override /** 计算控件的宽和高 */ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int count = getChildCount(); for (int i = 0; i < count; i++) { getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); } // 滚到到哪一屏,通过width来控制 scrollTo(mCurScreen * width, 0); } public void setOnViewChangeListener(OnViewChangeListener changeListener) { this.onViewChangeListener = changeListener; } /** * 设置自定义控件中的哪个子控件展示在当前屏幕中 * @param pos */ public void snapToScreen(int pos) { //System.out.println("当前的位置:" + pos); if (getScrollX() != (pos * getWidth())) { int destina = pos * getWidth() - getScrollX();// 要移动的距离 // 开始滚动,从起始地开始,后两个参数为滚动的距离。用坐标来表示 scroller.startScroll(getScrollX(), 0, destina, 0); mCurScreen = pos; // 在主线程中调用这个方法来重绘view,必须在主线程中调用 invalidate(); // 改变imageView的显示(根据guide_round.xml可以看出,当状态enabled的 // 的时候,用黑点表示,也就是不是当前选中。) //System.out.println("ImageView改变监听" + onViewChangeListener); if (onViewChangeListener != null) { onViewChangeListener.onViewChange(pos); } } } @Override public void computeScroll() { if (scroller.computeScrollOffset()) { scrollTo(scroller.getCurrX(), scroller.getCurrY()); postInvalidate(); } } @Override public boolean onTouchEvent(MotionEvent event) { // Return the kind of action being performed -- // one of either ACTION_DOWN, ACTION_MOVE, ACTION_UP, or ACTION_CANCEL. int action = event.getAction(); /** * 屏幕上的每一次触摸都会被onTouchEvent捕获到,可以从event得到其x,y的值。 * 特别注意:并且得到的是你当前的触点的x,y坐标的值,也就是说,往左划动的话, 你的x的值是变小的。 */ float x = event.getX(); //System.out.println("onTouchEvent--" + x); switch (action) { // 按下 case MotionEvent.ACTION_DOWN: if (tracker == null) { tracker = VelocityTracker.obtain(); tracker.addMovement(event); } if (!scroller.isFinished()) // 防止scroller滚动到最终的x和y的位置 scroller.abortAnimation(); mLastMotionX = x; //System.out.println("mLastMotionX--" + mLastMotionX); break; // 移动 case MotionEvent.ACTION_MOVE: // 开始位置的触点与当前位置的差值 int deltalX = (int) (mLastMotionX - x); if (canMove(deltalX)) { if (tracker != null) { tracker.addMovement(event); } mLastMotionX = x; // 控件滚动的位置 scrollBy(deltalX, 0); } break; // 松手 case MotionEvent.ACTION_UP: /** 往左滑动,因为x是在减小,所以横向速率是负值。 往右滑动,因为x是在增大,所以横向速率是正值。 */ int velocityX = 0; if (tracker != null) { tracker.addMovement(event); tracker.computeCurrentVelocity(1000);// 计算1s滚动的速度 //System.out.println("tracker -- " + tracker); velocityX = (int) tracker.getXVelocity();// 得到最终的横向速率 //System.out.println("横向速率--" + velocityX); //System.out.println("mCurScreen--" + mCurScreen); } // 不是第一屏,且是往右滑动 if (velocityX > SNAP_VELOCITY && mCurScreen > 0) snapToScreen(mCurScreen - 1); // 往左滑动,且不是最后一个 else if (velocityX < -SNAP_VELOCITY && mCurScreen < (getChildCount() - 1)) { snapToScreen(mCurScreen + 1); } // 往左滑动,且是最后一个,这里直接finish掉activity else if (velocityX == 0 && mCurScreen == (getChildCount() - 1)) { //System.out.println("-----------"); Activity activity = (Activity) context; Intent intent = new Intent(); intent.setClass(context, LandingTwoActivity.class); context.startActivity(intent); activity.finish(); } else { // 速率不够快是,另一种跳转方式 snapToDestination(); } if (tracker != null) { tracker.recycle(); tracker = null; } break; } return true; } /** 滑动到下一屏 */ private void snapToDestination() { int screenWidth = getWidth(); // 最终滑动的位置超过1\2时,才滚动,否则,destScreen得到将是当前屏的值。 int destScreen = (getScrollX() + screenWidth / 2) / screenWidth; snapToScreen(destScreen); } /** 可滚动的条件 */ private boolean canMove(int deltalX) { // getScrollX(),得到触点view在左边的x轴的坐标,它的值是从第一张图到最后一张图算的, // 也就是说:getScrollX()得到的值是 将整个图展开,然后相对的那个x坐标。 // 显示的是第一张图,并且是往右划 if (getScrollX() <= 0 && deltalX < 0) { return false; } // 显示的是最后一张图并且是往左划 if (getScrollX() >= (getChildCount() - 1) * getWidth() && deltalX > 0) { return false; } return true; } }
SetupPageActivity加载显示效果
public class SetupPageActivity extends Activity { private static String TAG = "SetupPageActivity1"; private SwitchLayout switchLayout; private LinearLayout linearLayout; private TextView bottom_img[]; // 底部的ImageView private int viewCount; // 自定义控件中子控件的个数 private int viewSel; // 当前选中的ImageView @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); super.setContentView(R.layout.setup_page1); init(); } private void init() { switchLayout = (SwitchLayout) findViewById(R.id.switchLayoutID); linearLayout = (LinearLayout) findViewById(R.id.linerLayoutID); // 得到子控件的个数 viewCount = switchLayout.getChildCount(); bottom_img = new TextView[viewCount]; // 设置imageView for (int i = 0; i < viewCount; i++) { // 得到LinearLayout中的子控件(底部) bottom_img[i] = (TextView) linearLayout.getChildAt(i); bottom_img[i].setEnabled(true); // 控件激活 bottom_img[i].setTag(i); bottom_img[i].setOnClickListener(new MOnClickListener()); bottom_img[i].getPaint().setFakeBoldText(true); } // 设置第一个imageView不被激活 viewSel = -1; int initCurScreen = 0; setCurPoint(initCurScreen); switchLayout.snapToScreen(initCurScreen); // bottom_img[viewSel].setEnabled(false); switchLayout.setOnViewChangeListener(new MOnViewChangeListener()); } /** bottom_img点击事件的监听器 */ private class MOnClickListener implements OnClickListener { @Override public void onClick(View v) { int pos = (Integer) v.getTag(); // 设置当前显示的ImageView setCurPoint(pos); // 设置自定义控件中的哪个子控件展示在当前屏幕中 switchLayout.snapToScreen(pos); } } /** 设置当前显示的ImageView */ private void setCurPoint(int pos) { if (pos < 0 || pos > viewCount - 1 || viewSel == pos) return; // 当前的imgaeView将可以被激活 if (viewSel != -1) { bottom_img[viewSel].setEnabled(true); bottom_img[viewSel].setText(" "); } // 将要跳转过去的那个imageView变成不可激活 bottom_img[pos].setEnabled(false); //bottom_img[pos].setText(" " + (pos + 1)+" " ); viewSel = pos; } /** 自定义控件中View改变的事件监听 */ private class MOnViewChangeListener implements OnViewChangeListener { @Override public void onViewChange(int view) { // TODO Auto-generated method stub Log.i(TAG, "view:--" + view); if (view < 0 || viewSel == view) { return; } else if (view > viewCount - 1) { Log.i(TAG, "finish activity"); SetupPageActivity.this.finish(); } setCurPoint(view); } } }
以上Activity使用到的接口
public interface OnViewChangeListener { public void onViewChange(int view); }