Android FlingGallery类完美手势拖动实现

jopen 12年前

网上找了很多关于FlingGallery类拖动的例子,还是很不错的,但是感觉不是很完美,拖动的只能是界面一致的布局,很不灵活,我觉得如果能 够拖动不同的布局页面,就是拖动一下换一个页面布局,那就很完美了,于是我就在原有的基础上修改了一点点代码,最终被我给解决了这个问题。下面我就给大家 看看我修改后的代码:

先贴上几张图

Android FlingGallery类完美手势拖动实现         Android FlingGallery类完美手势拖动实现

 

FlingGalleryActivity.java 实现类:

package com.droidful.flinggallery;    import android.app.Activity;  import android.content.Context;  import android.os.Bundle;  import android.util.Log;  import android.view.MotionEvent;  import android.view.View;  import android.view.View.OnClickListener;  import android.view.ViewGroup;  import android.widget.ArrayAdapter;  import android.widget.CheckBox;  import android.widget.LinearLayout;  import android.widget.TableLayout;  import android.widget.TextView;  import android.widget.Toast;    public class FlingGalleryActivity extends Activity  {      private final String[] mLabelArray = {"View1", "View2", "View3", "View4"};     private FlingGallery mGallery;   private CheckBox mCheckBox;   private TextView t1;      // Note: The following handler is critical to correct function of      // the FlingGallery class. This enables the FlingGallery class to      // detect when the motion event has ended by finger being lifted        @Override      public boolean onTouchEvent(MotionEvent event)   {          return mGallery.onGalleryTouchEvent(event);      }        public void onCreate(Bundle savedInstanceState)      {          super.onCreate(savedInstanceState);            mGallery = new FlingGallery(this);          mGallery.setPaddingWidth(5);          mGallery.setAdapter(new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, mLabelArray)          {           @Override           public View getView(int position, View convertView, ViewGroup parent)           {            Log.d("msg", "count="+position);  //             if (convertView != null && convertView instanceof GalleryViewItem)  //                {  //              GalleryViewItem galleryView = (GalleryViewItem) convertView;  //  //              galleryView.mEdit1.setText("");  //              galleryView.mText1.setText(mLabelArray[position]);  //              galleryView.mText1.setBackgroundColor(mColorArray[position]);  //              galleryView.mText2.setText(mLabelArray[position]);  //              galleryView.mText2.setBackgroundColor(mColorArray[position]);  //              Log.d("msg", "count="+position);     //              return galleryView;  //                }               return new GalleryViewItem(getApplicationContext(), position);           }          });            LinearLayout layout = new LinearLayout(getApplicationContext());          layout.setOrientation(LinearLayout.VERTICAL);      LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(      LinearLayout.LayoutParams.MATCH_PARENT,      LinearLayout.LayoutParams.MATCH_PARENT);      //layoutParams.setMargins(10, 10, 10, 10);    layoutParams.weight = 1.0f;              layout.addView(mGallery, layoutParams);                 mCheckBox = new CheckBox(getApplicationContext());          mCheckBox.setText("Gallery is Circular");          mCheckBox.setPadding(50, 10, 0, 10);          mCheckBox.setTextSize(30);          mCheckBox.setChecked(true);          mCheckBox.setOnClickListener(new OnClickListener()          {     @Override     public void onClick(View view)     {      mGallery.setIsGalleryCircular(mCheckBox.isChecked());     }          });            layout.addView(mCheckBox, new LinearLayout.LayoutParams(         LinearLayout.LayoutParams.MATCH_PARENT,         LinearLayout.LayoutParams.WRAP_CONTENT));                 setContentView(layout);                          }    private class GalleryViewItem extends TableLayout   {    public GalleryViewItem(Context context, int position)    {     super(context);       this.setOrientation(LinearLayout.VERTICAL);     this.setLayoutParams(new LinearLayout.LayoutParams(          LinearLayout.LayoutParams.WRAP_CONTENT,          LinearLayout.LayoutParams.WRAP_CONTENT));             if(position==0){         View view = (View)getLayoutInflater().inflate(R.layout.main01,null);         //给里面控件设置事件监听               t1 = (TextView)view.findViewById(R.id.main_view01);               t1.setOnClickListener(new OnClickListener() {                    @Override          public void onClick(View v) {           Toast.makeText(getApplicationContext(), t1.getText().toString(), Toast.LENGTH_SHORT).show();          }         });         this.addView(view,new LinearLayout.LayoutParams(              LinearLayout.LayoutParams.FILL_PARENT,              LinearLayout.LayoutParams.FILL_PARENT));        }else if(position==1){         View view = (View)getLayoutInflater().inflate(R.layout.main02,null);         this.addView(view,new LinearLayout.LayoutParams(              LinearLayout.LayoutParams.FILL_PARENT,              LinearLayout.LayoutParams.FILL_PARENT));        }else if(position==2){         View view = (View)getLayoutInflater().inflate(R.layout.main03,null);         this.addView(view,new LinearLayout.LayoutParams(              LinearLayout.LayoutParams.FILL_PARENT,              LinearLayout.LayoutParams.FILL_PARENT));        }else if(position==3){         View view = (View)getLayoutInflater().inflate(R.layout.main04,null);         this.addView(view,new LinearLayout.LayoutParams(              LinearLayout.LayoutParams.FILL_PARENT,              LinearLayout.LayoutParams.FILL_PARENT));        }    }   }  }

 


FlingGallery.java 工具类

package com.droidful.flinggallery;    import android.content.Context;  import android.view.GestureDetector;  import android.view.KeyEvent;  import android.view.MotionEvent;  import android.view.View;  import android.view.animation.Animation;  import android.view.animation.AnimationUtils;  import android.view.animation.Interpolator;  import android.view.animation.Transformation;  import android.widget.Adapter;  import android.widget.FrameLayout;  import android.widget.LinearLayout;    // TODO:    // 1. In order to improve performance Cache screen bitmap and use for animation  // 2. Establish superfluous memory allocations and delay or replace with reused objects  //   Probably need to make sure we are not allocating objects (strings, etc.) in loops    //为了提高性能,使用缓存屏幕图动画  //建立多余的内存分配和延迟或替换为重用对象可能需要确保我们不分配对象(字符串,等等。)在循环  public class FlingGallery extends FrameLayout  {   // Constants 常量      private final int swipe_min_distance = 120;      private final int swipe_max_off_path = 250;      private final int swipe_threshold_veloicty = 400;        // Properties 属性         private int mViewPaddingWidth = 0;      private int mAnimationDuration = 250;      private float mSnapBorderRatio = 0.5f;      private boolean mIsGalleryCircular = true;        // Members 成员        private int mGalleryWidth = 0;      private boolean mIsTouched = false;      private boolean mIsDragging = false;      private float mCurrentOffset = 0.0f;      private long mScrollTimestamp = 0;      private int mFlingDirection = 0;      private int mCurrentPosition = 0;      private int mCurrentViewNumber = 0;        private Context mContext;      private Adapter mAdapter;      private FlingGalleryView[] mViews;      private FlingGalleryAnimation mAnimation;      private GestureDetector mGestureDetector;      private Interpolator mDecelerateInterpolater;        public FlingGallery(Context context)   {    super(context);      mContext = context;    mAdapter = null;              mViews = new FlingGalleryView[3];          mViews[0] = new FlingGalleryView(0, this);          mViews[1] = new FlingGalleryView(1, this);          mViews[2] = new FlingGalleryView(2, this);      mAnimation = new FlingGalleryAnimation();    mGestureDetector = new GestureDetector(new FlingGestureDetector());    mDecelerateInterpolater = AnimationUtils.loadInterpolator(mContext, android.R.anim.decelerate_interpolator);   }     public void setPaddingWidth(int viewPaddingWidth)   {    mViewPaddingWidth = viewPaddingWidth;   }     public void setAnimationDuration(int animationDuration)   {    mAnimationDuration = animationDuration;   }      public void setSnapBorderRatio(float snapBorderRatio)   {    mSnapBorderRatio = snapBorderRatio;   }     public void setIsGalleryCircular(boolean isGalleryCircular)    {    if (mIsGalleryCircular != isGalleryCircular)    {     mIsGalleryCircular = isGalleryCircular;        if (mCurrentPosition == getFirstPosition())     {      // We need to reload the view immediately to the left to change it to circular view or blank         //我们需要重新加载视图立即到左边来改变它圆视图或空白      mViews[getPrevViewNumber(mCurrentViewNumber)].recycleView(getPrevPosition(mCurrentPosition));        }        if (mCurrentPosition == getLastPosition())     {      // We need to reload the view immediately to the right to change it to circular view or blank         //我们需要重新加载视图立即向右改变它圆视图或空白      mViews[getNextViewNumber(mCurrentViewNumber)].recycleView(getNextPosition(mCurrentPosition));        }    }   }     public int getGalleryCount()   {    return (mAdapter == null) ? 0 : mAdapter.getCount();   }     public int getFirstPosition()   {    return 0;   }     public int getLastPosition()   {    return (getGalleryCount() == 0) ? 0 : getGalleryCount() - 1;   }     private int getPrevPosition(int relativePosition)   {    int prevPosition = relativePosition - 1;      if (prevPosition < getFirstPosition())    {     prevPosition = getFirstPosition() - 1;       if (mIsGalleryCircular == true)     {      prevPosition = getLastPosition();     }    }      return prevPosition;   }     private int getNextPosition(int relativePosition)   {    int nextPosition = relativePosition + 1;      if (nextPosition > getLastPosition())    {     nextPosition = getLastPosition() + 1;       if (mIsGalleryCircular == true)     {      nextPosition = getFirstPosition();     }    }      return nextPosition;   }     private int getPrevViewNumber(int relativeViewNumber)   {    return (relativeViewNumber == 0) ? 2 : relativeViewNumber - 1;   }     private int getNextViewNumber(int relativeViewNumber)   {    return (relativeViewNumber == 2) ? 0 : relativeViewNumber + 1;   }      @Override   protected void onLayout(boolean changed, int left, int top, int right, int bottom)   {    super.onLayout(changed, left, top, right, bottom);      // Calculate our view width 计算我们的视图的宽度    mGalleryWidth = right - left;      if (changed == true)    {        // Position views at correct starting offsets 在正确的开始偏移位置的观点        mViews[0].setOffset(0, 0, mCurrentViewNumber);        mViews[1].setOffset(0, 0, mCurrentViewNumber);        mViews[2].setOffset(0, 0, mCurrentViewNumber);       }   }     public void setAdapter(Adapter adapter)      {       mAdapter = adapter;       mCurrentPosition = 0;          mCurrentViewNumber = 0;            // Load the initial views from adapter 加载初始视图从适配器          mViews[0].recycleView(mCurrentPosition);       mViews[1].recycleView(getNextPosition(mCurrentPosition));       mViews[2].recycleView(getPrevPosition(mCurrentPosition));         // Position views at correct starting offsets  在正确的开始偏移位置的观点       mViews[0].setOffset(0, 0, mCurrentViewNumber);       mViews[1].setOffset(0, 0, mCurrentViewNumber);       mViews[2].setOffset(0, 0, mCurrentViewNumber);      }     private int getViewOffset(int viewNumber, int relativeViewNumber)   {    // Determine width including configured padding width 确定宽度包括配置填充宽度    int offsetWidth = mGalleryWidth + mViewPaddingWidth;      // Position the previous view one measured width to left 位置之前的观点一个测量宽度到左    if (viewNumber == getPrevViewNumber(relativeViewNumber))    {     return offsetWidth;    }      // Position the next view one measured width to the right 位置下一个视图向右一个测量宽度    if (viewNumber == getNextViewNumber(relativeViewNumber))    {     return offsetWidth * -1;    }      return 0;   }     void movePrevious()   {    // Slide to previous view 滑到上一个视图    mFlingDirection = 1;    processGesture();   }     void moveNext()   {    // Slide to next view  滑到下一个视图    mFlingDirection = -1;    processGesture();   }      @Override    public boolean onKeyDown(int keyCode, KeyEvent event)    {       switch (keyCode)       {       case KeyEvent.KEYCODE_DPAD_LEFT:           movePrevious();           return true;          case KeyEvent.KEYCODE_DPAD_RIGHT:           moveNext();           return true;          case KeyEvent.KEYCODE_DPAD_CENTER:       case KeyEvent.KEYCODE_ENTER:       }         return super.onKeyDown(keyCode, event);   }     public boolean onGalleryTouchEvent(MotionEvent event)   {    boolean consumed = mGestureDetector.onTouchEvent(event);        if (event.getAction() == MotionEvent.ACTION_UP)    {     if (mIsTouched || mIsDragging)     {      processScrollSnap();      processGesture();     }    }              return consumed;      }     void processGesture()   {    int newViewNumber = mCurrentViewNumber;    int reloadViewNumber = 0;    int reloadPosition = 0;      mIsTouched = false;    mIsDragging = false;      if (mFlingDirection > 0)    {     if (mCurrentPosition > getFirstPosition() || mIsGalleryCircular == true)     {      // Determine previous view and outgoing view to recycle 确定之前的观点和外向视图回收      newViewNumber = getPrevViewNumber(mCurrentViewNumber);      mCurrentPosition = getPrevPosition(mCurrentPosition);      reloadViewNumber = getNextViewNumber(mCurrentViewNumber);       reloadPosition = getPrevPosition(mCurrentPosition);     }    }      if (mFlingDirection < 0)    {     if (mCurrentPosition < getLastPosition() || mIsGalleryCircular == true)     {      // Determine the next view and outgoing view to recycle 确定下一个视图和外向视图回收      newViewNumber = getNextViewNumber(mCurrentViewNumber);      mCurrentPosition = getNextPosition(mCurrentPosition);      reloadViewNumber = getPrevViewNumber(mCurrentViewNumber);      reloadPosition = getNextPosition(mCurrentPosition);     }    }      if (newViewNumber != mCurrentViewNumber)    {     mCurrentViewNumber = newViewNumber;        // Reload outgoing view from adapter in new position 重新加载外向视图从适配器在新位置     mViews[reloadViewNumber].recycleView(reloadPosition);    }      // Ensure input focus on the current view 确保输入关注当前视图    mViews[mCurrentViewNumber].requestFocus();      // Run the slide animations for view transitions 运行这个幻灯片动画视图转换      mAnimation.prepareAnimation(mCurrentViewNumber);    this.startAnimation(mAnimation);      // Reset fling state 重置扔状态    mFlingDirection = 0;   }     void processScrollSnap()   {    // Snap to next view if scrolled passed snap position 对齐到下一个视图如果滚动通过快速的位置    float rollEdgeWidth = mGalleryWidth * mSnapBorderRatio;    int rollOffset = mGalleryWidth - (int) rollEdgeWidth;    int currentOffset = mViews[mCurrentViewNumber].getCurrentOffset();      if (currentOffset <= rollOffset * -1)    {     // Snap to previous view     mFlingDirection = 1;    }      if (currentOffset >= rollOffset)    {     // Snap to next view     mFlingDirection = -1;    }   }     private class FlingGalleryView   {    private int mViewNumber;    private FrameLayout mParentLayout;        private FrameLayout mInvalidLayout = null;    private LinearLayout mInternalLayout = null;    private View mExternalView = null;      public FlingGalleryView(int viewNumber, FrameLayout parentLayout)    {     mViewNumber = viewNumber;     mParentLayout = parentLayout;       // Invalid layout is used when outside gallery 无效的布局时,使用的是画廊外     mInvalidLayout = new FrameLayout(mContext);     mInvalidLayout.setLayoutParams(new LinearLayout.LayoutParams(                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));       // Internal layout is permanent for duration 内部布局是永久的持续时间     mInternalLayout = new LinearLayout(mContext);     mInternalLayout.setLayoutParams(new LinearLayout.LayoutParams(                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));       mParentLayout.addView(mInternalLayout);    }      public void recycleView(int newPosition)    {     if (mExternalView != null)     {      mInternalLayout.removeView(mExternalView);     }       if (mAdapter != null)     {      if (newPosition >= getFirstPosition() && newPosition <= getLastPosition())      {       mExternalView = mAdapter.getView(newPosition, mExternalView, mInternalLayout);      }      else      {       mExternalView = mInvalidLayout;      }     }       if (mExternalView != null)     {      mInternalLayout.addView(mExternalView, new LinearLayout.LayoutParams(                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));     }    }      public void setOffset(int xOffset, int yOffset, int relativeViewNumber)    {     // Scroll the target view relative to its own position relative to currently displayed view     //滚动目标视图相对于自己的位置相对于当前显示视图     mInternalLayout.scrollTo(getViewOffset(mViewNumber, relativeViewNumber) + xOffset, yOffset);    }        public int getCurrentOffset()    {     // Return the current scroll position     //返回当前滚动位置     return mInternalLayout.getScrollX();    }      public void requestFocus()    {     mInternalLayout.requestFocus();    }   }        private class FlingGalleryAnimation extends Animation      {       private boolean mIsAnimationInProgres;       private int mRelativeViewNumber;       private int mInitialOffset;       private int mTargetOffset;       private int mTargetDistance;              public FlingGalleryAnimation()       {        mIsAnimationInProgres = false;        mRelativeViewNumber = 0;           mInitialOffset = 0;           mTargetOffset = 0;           mTargetDistance = 0;       }          public void prepareAnimation(int relativeViewNumber)       {        // If we are animating relative to a new view 如果我们是相对于一个新视图动画        if (mRelativeViewNumber != relativeViewNumber)        {      if (mIsAnimationInProgres == true)      {       // We only have three views so if requested again to animate in same direction we must snap        int newDirection = (relativeViewNumber == getPrevViewNumber(mRelativeViewNumber)) ? 1 : -1;          int animDirection = (mTargetDistance < 0) ? 1 : -1;             // If animation in same direction          if (animDirection == newDirection)          {              // Ran out of time to animate so snap to the target offset              mViews[0].setOffset(mTargetOffset, 0, mRelativeViewNumber);        mViews[1].setOffset(mTargetOffset, 0, mRelativeViewNumber);        mViews[2].setOffset(mTargetOffset, 0, mRelativeViewNumber);           }      }         // Set relative view number for animation         mRelativeViewNumber = relativeViewNumber;        }       // Note: In this implementation the targetOffset will always be zero        // as we are centering the view; but we include the calculations of     // targetOffset and targetDistance for use in future implementations       mInitialOffset = mViews[mRelativeViewNumber].getCurrentOffset();     mTargetOffset = getViewOffset(mRelativeViewNumber, mRelativeViewNumber);     mTargetDistance = mTargetOffset - mInitialOffset;       // Configure base animation properties     this.setDuration(mAnimationDuration);     this.setInterpolator(mDecelerateInterpolater);       // Start/continued animation     mIsAnimationInProgres = true;    }            @Override          protected void applyTransformation(float interpolatedTime, Transformation transformation)          {           // Ensure interpolatedTime does not over-shoot then calculate new offset           interpolatedTime = (interpolatedTime > 1.0f) ? 1.0f : interpolatedTime;     int offset = mInitialOffset + (int) (mTargetDistance * interpolatedTime);       for (int viewNumber = 0; viewNumber < 3; viewNumber++)     {      // Only need to animate the visible views as the other view will always be off-screen      if ((mTargetDistance > 0 && viewNumber != getNextViewNumber(mRelativeViewNumber)) ||       (mTargetDistance < 0 && viewNumber != getPrevViewNumber(mRelativeViewNumber)))      {       mViews[viewNumber].setOffset(offset, 0, mRelativeViewNumber);      }     }          }            @Override          public boolean getTransformation(long currentTime, Transformation outTransformation)          {           if (super.getTransformation(currentTime, outTransformation) == false)           {            // Perform final adjustment to offsets to cleanup animation            mViews[0].setOffset(mTargetOffset, 0, mRelativeViewNumber);      mViews[1].setOffset(mTargetOffset, 0, mRelativeViewNumber);      mViews[2].setOffset(mTargetOffset, 0, mRelativeViewNumber);        // Reached the animation target      mIsAnimationInProgres = false;        return false;           }              // Cancel if the screen touched           if (mIsTouched || mIsDragging)           {            // Note that at this point we still consider ourselves to be animating            // because we have not yet reached the target offset; its just that the            // user has temporarily interrupted the animation with a touch gesture              return false;           }             return true;          }      }     private class FlingGestureDetector extends GestureDetector.SimpleOnGestureListener      {       @Override       public boolean onDown(MotionEvent e)       {        // Stop animation        mIsTouched = true;          // Reset fling state        mFlingDirection = 0;              return true;       }         @Override       public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)       {        if (e2.getAction() == MotionEvent.ACTION_MOVE)           {         if (mIsDragging == false)         {             // Stop animation          mIsTouched = true;              // Reconfigure scroll          mIsDragging = true;          mFlingDirection = 0;          mScrollTimestamp = System.currentTimeMillis();          mCurrentOffset = mViews[mCurrentViewNumber].getCurrentOffset();         }                 float maxVelocity = mGalleryWidth / (mAnimationDuration / 1000.0f);            long timestampDelta = System.currentTimeMillis() - mScrollTimestamp;            float maxScrollDelta = maxVelocity * (timestampDelta / 1000.0f);             float currentScrollDelta = e1.getX() - e2.getX();              if (currentScrollDelta < maxScrollDelta * -1) currentScrollDelta = maxScrollDelta * -1;            if (currentScrollDelta > maxScrollDelta) currentScrollDelta = maxScrollDelta;            int scrollOffset = Math.round(mCurrentOffset + currentScrollDelta);              // We can't scroll more than the width of our own frame layout            if (scrollOffset >= mGalleryWidth) scrollOffset = mGalleryWidth;            if (scrollOffset <= mGalleryWidth * -1) scrollOffset = mGalleryWidth * -1;                        mViews[0].setOffset(scrollOffset, 0, mCurrentViewNumber);         mViews[1].setOffset(scrollOffset, 0, mCurrentViewNumber);         mViews[2].setOffset(scrollOffset, 0, mCurrentViewNumber);           }                return false;       }         @Override       public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)       {              if (Math.abs(e1.getY() - e2.getY()) <= swipe_max_off_path)              {                  if (e2.getX() - e1.getX() > swipe_min_distance && Math.abs(velocityX) > swipe_threshold_veloicty)                  {                   movePrevious();                  }                    if(e1.getX() - e2.getX() > swipe_min_distance && Math.abs(velocityX) > swipe_threshold_veloicty)                  {                   moveNext();                  }              }                return false;       }         @Override       public void onLongPress(MotionEvent e)       {        // Finalise scrolling        mFlingDirection = 0;              processGesture();       }         @Override       public void onShowPress(MotionEvent e)       {       }         @Override       public boolean onSingleTapUp(MotionEvent e)       {        // Reset fling state        mFlingDirection = 0;              return false;       }      }  }

main01.xml文件

<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:id="@+id/main"      android:orientation="vertical"      android:layout_width="fill_parent"      android:layout_height="fill_parent"      android:background="#FF9820"      android:gravity="center"      >   <TextView         android:id="@+id/main_view01"       android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:gravity="center"       android:text="View1"       android:textSize="20dp"       android:textColor="#FFFFFF"       />  </LinearLayout>

main02.xml文件

<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:id="@+id/main"      android:orientation="vertical"      android:layout_width="fill_parent"      android:layout_height="fill_parent"      android:background="#ee4520"      android:gravity="center"      >   <TextView         android:id="@+id/main_view01"       android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:gravity="center"       android:text="View1"       android:textSize="20dp"       android:textColor="#FFFFFF"       />  </LinearLayout>

main03.xml文件

<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:id="@+id/main"      android:orientation="vertical"      android:layout_width="fill_parent"      android:layout_height="fill_parent"      android:background="#aacc20"      android:gravity="center"      >   <TextView         android:id="@+id/main_view01"       android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:gravity="center"       android:text="View3"       android:textSize="20dp"       android:textColor="#FFFFFF"       />  </LinearLayout>

main04.xml文件

<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:id="@+id/main"      android:orientation="vertical"      android:layout_width="fill_parent"      android:layout_height="fill_parent"      android:background="#ddeeff"      android:gravity="center"      >   <TextView         android:id="@+id/main_view01"       android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:gravity="center"       android:text="View4"       android:textSize="20dp"       android:textColor="#FFFFFF"       />  </LinearLayout>
转自:http://blog.csdn.net/h7870181/article/details/7946259