2025-05-23

 半個月前就有這樣的想法,做出一個模仿launcher的效果。自己也曾從網上搜過很多資料,也思考過怎麼實現,最終還是參考瞭別人的資料實現瞭此效果,也解決瞭我這半個多月的冥思苦想,再次感謝,今天把代碼貼出來供大傢學習,因為這方面做得比較好的資料缺失比較少(因為本人搜瞭很多資料都不能達到效果),如果大傢覺得還不錯,請頂起。

       

            首先自定義一個 ViewGroup:

 

[html] public class MyScrollLayout extends ViewGroup{ 
 
    private VelocityTracker mVelocityTracker;           // 用於判斷甩動手勢     
    private static final int SNAP_VELOCITY = 600;         
    private Scroller  mScroller;                        // 滑動控制器     
    private int mCurScreen;                              
    private int mDefaultScreen = 0;                           
    private float mLastMotionX;        
 //   private int mTouchSlop;                            
     
   private OnViewChangeListener mOnViewChangeListener;   
  
    public MyScrollLayout(Context context) { 
        super(context); 
        // TODO Auto-generated constructor stub 
        init(context); 
    }    
    public MyScrollLayout(Context context, AttributeSet attrs) { 
        super(context, attrs); 
        // TODO Auto-generated constructor stub 
        init(context); 
    } 
     
    public MyScrollLayout(Context context, AttributeSet attrs, int defStyle) { 
        super(context, attrs, defStyle); 
        // TODO Auto-generated constructor stub      
        init(context); 
    } 
     
    private void init(Context context) 
    { 
        mCurScreen = mDefaultScreen;           
     //   mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();                 
        mScroller = new Scroller(context);  
         
    } 
 
    @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) { 
        // TODO Auto-generated method stub 
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        
        final int width = MeasureSpec.getSize(widthMeasureSpec);        
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);       
                 
        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     
            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                     
                if (mOnViewChangeListener != null) 
                { 
                    mOnViewChangeListener.OnViewChange(mCurScreen); 
                } 
            }     
        }     
 
    @Override 
    public void computeScroll() { 
        // TODO Auto-generated method stub 
        if (mScroller.computeScrollOffset()) {     
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());   
            postInvalidate();     
        }    
    } 
 
    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
        // TODO Auto-generated method stub                           
            final int action = event.getAction();     
            final float x = event.getX();     
            final float y = event.getY();     
                 
            switch (action) {     
            case MotionEvent.ACTION_DOWN:                
                  Log.i("", "onTouchEvent  ACTION_DOWN");                  
                if (mVelocityTracker == null) {     
                        mVelocityTracker = VelocityTracker.obtain();     
                        mVelocityTracker.addMovement(event);  
                }             
                if (!mScroller.isFinished()){     
                    mScroller.abortAnimation();     
                }                 
                mLastMotionX = x;               
                break;     
                     
            case MotionEvent.ACTION_MOVE:   
               int deltaX = (int)(mLastMotionX – x);                
               if (IsCanMove(deltaX)) 
               { 
                 if (mVelocityTracker != null) 
                 { 
                        mVelocityTracker.addMovement(event);  
                 }    
                mLastMotionX = x;      
                scrollBy(deltaX, 0);     
               } 
          
               break;                        
            case MotionEvent.ACTION_UP:                      
                int velocityX = 0; 
                if (mVelocityTracker != null) 
                { 
                    mVelocityTracker.addMovement(event);  
                    mVelocityTracker.computeCurrentVelocity(1000);   
                    velocityX = (int) mVelocityTracker.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;       
            }                    
            return true;     
    } 
 
    private boolean IsCanMove(int deltaX) 
    { 
        if (getScrollX() <= 0 && deltaX < 0 ){ 
            return false; 
        }    
        if  (getScrollX() >=  (getChildCount() – 1) * getWidth() && deltaX > 0){ 
            return false; 
        }        
        return true; 
    } 
     
    public void SetOnViewChangeListener(OnViewChangeListener listener) 
    { 
        mOnViewChangeListener = listener; 
    } 

public class MyScrollLayout extends ViewGroup{

    private VelocityTracker mVelocityTracker;     // 用於判斷甩動手勢   
    private static final int SNAP_VELOCITY = 600;       
    private Scroller  mScroller;      // 滑動控制器 
    private int mCurScreen;             
 private int mDefaultScreen = 0;          
    private float mLastMotionX;      
 //   private int mTouchSlop;       
   
   private OnViewChangeListener mOnViewChangeListener; 
 
 public MyScrollLayout(Context context) {
  super(context);
  // TODO Auto-generated constructor stub
  init(context);
 } 
 public MyScrollLayout(Context context, AttributeSet attrs) {
  super(context, attrs);
  // TODO Auto-generated constructor stub
  init(context);
 }
 
 public MyScrollLayout(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  // TODO Auto-generated constructor stub  
  init(context);
 }
 
 private void init(Context context)
 {
  mCurScreen = mDefaultScreen;      
  //   mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();            
     mScroller = new Scroller(context);
    
 }

 @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) {
  // TODO Auto-generated method stub
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  final int width = MeasureSpec.getSize(widthMeasureSpec);      
     final int widthMode = MeasureSpec.getMode(widthMeasureSpec);     
       
  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   
         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                
             if (mOnViewChangeListener != null)
             {
              mOnViewChangeListener.OnViewChange(mCurScreen);
             }
         }   
     }   

 @Override
 public void computeScroll() {
  // TODO Auto-generated method stub
  if (mScroller.computeScrollOffset()) {   
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); 
            postInvalidate();   
        }  
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  // TODO Auto-generated method stub                       
         final int action = event.getAction();   
         final float x = event.getX();   
         final float y = event.getY();   
            
         switch (action) {   
         case MotionEvent.ACTION_DOWN:           
            Log.i("", "onTouchEvent  ACTION_DOWN");           
          if (mVelocityTracker == null) {   
               mVelocityTracker = VelocityTracker.obtain();   
               mVelocityTracker.addMovement(event);
       }         
             if (!mScroller.isFinished()){   
                 mScroller.abortAnimation();   
             }               
             mLastMotionX = x;           
             break;   
                
         case MotionEvent.ACTION_MOVE: 
            int deltaX = (int)(mLastMotionX – x);           
            if (IsCanMove(deltaX))
            {
           if (mVelocityTracker != null)
             {
                 mVelocityTracker.addMovement(event);
             }  
               mLastMotionX = x;    
               scrollBy(deltaX, 0); 
            }
        
            break;                    
         case MotionEvent.ACTION_UP:                 
          int velocityX = 0;
             if (mVelocityTracker != null)
             {
              mVelocityTracker.addMovement(event);
              mVelocityTracker.computeCurrentVelocity(1000); 
              velocityX = (int) mVelocityTracker.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;     
         }                
         return true;   
 }

 private boolean IsCanMove(int deltaX)
 {
  if (getScrollX() <= 0 && deltaX < 0 ){
   return false;
  } 
  if  (getScrollX() >=  (getChildCount() – 1) * getWidth() && deltaX > 0){
   return false;
  }  
  return true;
 }
 
 public void SetOnViewChangeListener(OnViewChangeListener listener)
 {
  mOnViewChangeListener = listener;
 }
}

 

[html] public class SwitchViewDemoActivity extends Activity implements OnViewChangeListener, OnClickListener{ 
    /** Called when the activity is first created. */ 
 
    private MyScrollLayout mScrollLayout;    
    private ImageView[] mImageViews;     
    private int mViewCount;  
    private int mCurSel; 
     
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main);         
        init(); 
         
    } 
     
    private void init() 
    { 
        mScrollLayout = (MyScrollLayout) findViewById(R.id.ScrollLayout);    
        LinearLayout linearLayout = (LinearLayout) findViewById(R.id.llayout); 
        //動態添加一個layout控件 
        LinearLayout layout=new LinearLayout(this); 
        layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); 
        layout.setBackgroundResource(R.drawable.guide01); 
        mScrollLayout.addView(layout); 
        //動態添加一個imageView控件         
        ImageView imageView=new ImageView(this); 
        imageView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 
        imageView.setPadding(15, 15, 15, 15); 
        imageView.setImageResource(R.drawable.guide_round); 
        linearLayout.addView(imageView); 
         
        mViewCount = mScrollLayout.getChildCount(); 
        mImageViews = new ImageView[mViewCount];     
        for(int i = 0; i < mViewCount; i++)      { 
            mImageViews[i] = (ImageView) linearLayout.getChildAt(i); 
            mImageViews[i].setEnabled(true); 
            mImageViews[i].setOnClickListener(this); 
            mImageViews[i].setTag(i); 
        }        
        mCurSel = 0; 
        mImageViews[mCurSel].setEnabled(false);      
        mScrollLayout.SetOnViewChangeListener(this); 
         
    } 
 
    private void setCurPoint(int index) 
    { 
        if (index < 0 || index > mViewCount – 1 || mCurSel == index)      { 
            return ; 
        }        
        mImageViews[mCurSel].setEnabled(true); 
        mImageViews[index].setEnabled(false);        
        mCurSel = index; 
    } 
 
    @Override 
    public void OnViewChange(int view) { 
        // TODO Auto-generated method stub 
        setCurPoint(view); 
    } 
 
    @Override 
    public void onClick(View v) { 
        // TODO Auto-generated method stub 
        int pos = (Integer)(v.getTag()); 
        setCurPoint(pos); 
        mScrollLayout.snapToScreen(pos); 
    } 

public class SwitchViewDemoActivity extends Activity implements OnViewChangeListener, OnClickListener{
    /** Called when the activity is first created. */

 private MyScrollLayout mScrollLayout; 
 private ImageView[] mImageViews; 
 private int mViewCount; 
 private int mCurSel;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);       
        init();
       
    }
   
    private void init()
    {
     mScrollLayout = (MyScrollLayout) findViewById(R.id.ScrollLayout);  
     LinearLayout linearLayout = (LinearLayout) findViewById(R.id.llayout);
     //動態添加一個layout控件
     LinearLayout layout=new LinearLayout(this);
     layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
     layout.setBackgroundResource(R.drawable.guide01);
     mScrollLayout.addView(layout);
     //動態添加一個imageView控件       
     ImageView imageView=new ImageView(this);
     imageView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
     imageView.setPadding(15, 15, 15, 15);
     imageView.setImageResource(R.drawable.guide_round);
     linearLayout.addView(imageView);
     
     mViewCount = mScrollLayout.getChildCount();
     mImageViews = new ImageView[mViewCount];    
     for(int i = 0; i < mViewCount; i++)     {
      mImageViews[i] = (ImageView) linearLayout.getChildAt(i);
      mImageViews[i].setEnabled(true);
      mImageViews[i].setOnClickListener(this);
      mImageViews[i].setTag(i);
     }     
     mCurSel = 0;
     mImageViews[mCurSel].setEnabled(false);     
     mScrollLayout.SetOnViewChangeListener(this);
     
    }

    private void setCurPoint(int index)
    {
     if (index < 0 || index > mViewCount – 1 || mCurSel == index)     {
      return ;
     }     
     mImageViews[mCurSel].setEnabled(true);
     mImageViews[index].setEnabled(false);     
     mCurSel = index;
    }

    @Override
 public void OnViewChange(int view) {
  // TODO Auto-generated method stub
  setCurPoint(view);
 }

 @Override
 public void onClick(View v) {
  // TODO Auto-generated method stub
  int pos = (Integer)(v.getTag());
  setCurPoint(pos);
  mScrollLayout.snapToScreen(pos);
 }
}
最後是佈局文件 :

[html] <?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" > 
 
    <cn.com.karl.scroll.MyScrollLayout 
        xmlns:android="http://schemas.android.com/apk/res/android" 
        android:id="@+id/ScrollLayout" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" > 
 
        <LinearLayout 
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent" 
            android:background="@drawable/guide01" > 
        </LinearLayout> 
 
        <LinearLayout 
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent" 
            android:background="@drawable/guide02" > 
        </LinearLayout> 
 
        <LinearLayout 
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent" 
            android:background="@drawable/guide03" > 
        </LinearLayout> 
 
        <LinearLayout 
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent" 
            android:background="@drawable/guide04" > 
        </LinearLayout> 
 
        <LinearLayout 
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent" 
            android:background="@drawable/guide05" > 
        </LinearLayout> 
    </cn.com.karl.scroll.MyScrollLayout> 
 
    <LinearLayout 
        android:id="@+id/llayout" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_alignParentBottom="true" 
        android:layout_centerHorizontal="true" 
        android:layout_marginBottom="24.0dip" 
        android:orientation="horizontal" > 
 
        <ImageView 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:layout_gravity="center_vertical" 
            android:clickable="true" 
            android:padding="15.0dip" 
            android:src="@drawable/guide_round" /> 
 
        <ImageView 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:layout_gravity="center_vertical" 
            android:clickable="true" 
            android:padding="15.0dip" 
            android:src="@drawable/guide_round" /> 
 
        <ImageView 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:layout_gravity="center_vertical" 
            android:clickable="true" 
            android:padding="15.0dip" 
            android:src="@drawable/guide_round" /> 
 
        <ImageView 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:layout_gravity="center_vertical" 
            android:clickable="true" 
            android:padding="15.0dip" 
            android:src="@drawable/guide_round" /> 
 
        <ImageView 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:layout_gravity="center_vertical" 
            android:clickable="true" 
            android:padding="15.0dip" 
            android:src="@drawable/guide_round" /> 
    </LinearLayout> 
 
</RelativeLayout> 
<?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" >

    <cn.com.karl.scroll.MyScrollLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ScrollLayout"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="@drawable/guide01" >
        </LinearLayout>

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="@drawable/guide02" >
        </LinearLayout>

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="@drawable/guide03" >
        </LinearLayout>

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="@drawable/guide04" >
        </LinearLayout>

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="@drawable/guide05" >
        </LinearLayout>
    </cn.com.karl.scroll.MyScrollLayout>

    <LinearLayout
        android:id="@+id/llayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="24.0dip"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:clickable="true"
            android:padding="15.0dip"
            android:src="@drawable/guide_round" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:clickable="true"
            android:padding="15.0dip"
            android:src="@drawable/guide_round" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:clickable="true"
            android:padding="15.0dip"
            android:src="@drawable/guide_round" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:clickable="true"
            android:padding="15.0dip"
            android:src="@drawable/guide_round" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:clickable="true"
            android:padding="15.0dip"
            android:src="@drawable/guide_round" />
    </LinearLayout>

</RelativeLayout>
看看運行後的效果到底怎麼樣吧!

  

 

摘自  wangkuifeng0118的專欄 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *