下载稻草人下来刷新+gallery
新手发帖,很多方面都是刚入门,有错误的地方请大家见谅,欢迎批评指正
废话少说先上图
    
demo 下载地址 http://download.csdn.net/detail/jansin_love/5428921
其中上半部份是一个gallery,下边是一个listview
UGallery .java
    package com.gallery.test;
 
 
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.widget.Gallery;
 
 
 public class UGallery extends Gallery {
 
 
 public UGallery(Context context, AttributeSet attrs) {
 super(context, attrs);
 }
    
 private boolean isScrollingLeft(MotionEvent e1, MotionEvent e2) {
 return e2.getX() > e1.getX();
 }
 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
 float velocityY) {
 int keyCode;
 if (isScrollingLeft(e1, e2)) {
 keyCode = KeyEvent.KEYCODE_DPAD_LEFT;
 } else {
 keyCode = KeyEvent.KEYCODE_DPAD_RIGHT;
 }
 onKeyDown(keyCode, null);
 return true;
 }
 }
PullToRefreshListActivity .java
    package com.stay.pull;
 
 
 import android.app.ListActivity;
 import android.content.Context;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.Gallery;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.AdapterView.OnItemSelectedListener;
 
 
 import com.gallery.test.UGallery;
 import com.stay.pull.lib.PullToRefreshBase.OnRefreshListener;
 import com.stay.pull.lib.PullToRefreshListView;
 
 
 public class PullToRefreshListActivity extends ListActivity {
 
 
 static final int MENU_MANUAL_REFRESH = 0;
 static final int MENU_DISABLE_SCROLL = 1;
 private PullToRefreshListView mPullRefreshListView;
 // Gallery mGallery;
 private UGallery uGallery;
 private ViewGroup vg;
 private LinearLayout change_layout;
 private LinearLayout viewGroup;
 private LinearLayout title_layout;
 private ImageView imageView;
 private ImageView[] imageViews;
 private TextView[] txt_titles;
 private TextView txt_title;
 private ListView actualListView;
 private Integer[] mImage = { R.drawable.image1, R.drawable.image2,
 R.drawable.image3, };
 private String[] mtitle = { "这是俏丽的风景", "这是可憎的稻草人", "这是迷人的大海" };
 private ImageView change_1, change_2, change_3;
 
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 
 
 setContentView(R.layout.pull_to_refresh_list);
 
 
 imageViews = new ImageView[mImage.length];
 vg= (ViewGroup) LayoutInflater.from(this).inflate(R.layout.main1, null);
 uGallery = (UGallery) vg.findViewById(R.id.gly_images);
 change_layout = (LinearLayout) vg.findViewById(R.id.change_layout);
 viewGroup = (LinearLayout) vg.findViewById(R.id.viewGroup);
 title_layout = (LinearLayout) vg.findViewById(R.id.title_layout);
 txt_title = new TextView(this);
 title_layout.addView(txt_title);
 change_layout.getBackground().setAlpha(180);
 uGallery.setAdapter(new ImageAdapter(PullToRefreshListActivity.this));
 for (int i = 0; i < mImage.length; i++) {
 imageView = new ImageView(this);
 imageView.setLayoutParams(new LayoutParams(18, 12));
 imageViews[i] = imageView;
 
 
 if (i == 0) {
 // 默认进入程序后第一张图片被选中;
 imageViews[i].setBackgroundResource(R.drawable.selectedflag);
 } else {
 imageViews[i].setBackgroundResource(R.drawable.unselectedflag);
 }
 
 
 viewGroup.addView(imageView);
 
 
 }
 
 
 uGallery.setOnItemSelectedListener(new OnItemSelectedListener() {
 
 
 @Override
 public void onItemSelected(AdapterView<?> arg0, View arg1,
 int arg2, long arg3) {
 txt_title.setText(mtitle[arg2]);
 for (int i = 0; i < imageViews.length; i++) {
 imageViews[arg2].setBackgroundResource(R.drawable.selectedflag);
 if (arg2 != i) {
 imageViews[i].setBackgroundResource(R.drawable.unselectedflag);
 }
 }
 
 
 }
 
 
 @Override
 public void onNothingSelected(AdapterView<?> arg0) {
 // TODO Auto-generated method stub
 
 
 }
 });
 
 
 mPullRefreshListView = (PullToRefreshListView) findViewById(R.id.pull_refresh_list);
 mPullRefreshListView.setOnRefreshListener(new OnRefreshListener() {
 @Override
 public void onRefresh() {
 new GetDataTask().execute();
 }
 });
 actualListView = mPullRefreshListView.getRefreshableView();
 actualListView.setAdapter(new Mybaseadapter());
 
 
 }
 
 
 private class GetDataTask extends AsyncTask<Void, Void, String[]> {
 
 
 @Override
 protected String[] doInBackground(Void... params) {
 try {
 Thread.sleep(4000);
 } catch (InterruptedException e) {
 }
 return new String[] { "返回数据" };
 }
 
 
 @Override
 protected void onPostExecute(String[] result) {
 //mAdapter.notifyDataSetChanged();
 mPullRefreshListView.onRefreshComplete();
 
 
 super.onPostExecute(result);
 }
 }
 
 
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
 menu.add(0, MENU_MANUAL_REFRESH, 0, "Manual Refresh");
 menu.add(
 0,
 MENU_DISABLE_SCROLL,
 1,
 mPullRefreshListView.isDisableScrollingWhileRefreshing() ? "Enable Scrolling while Refreshing"
 : "Disable Scrolling while Refreshing");
 return super.onCreateOptionsMenu(menu);
 }
 
 
 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
 
 
 switch (item.getItemId()) {
 
 
 case MENU_MANUAL_REFRESH:
 new GetDataTask().execute();
 mPullRefreshListView.setRefreshing(false);
 break;
 case MENU_DISABLE_SCROLL:
 mPullRefreshListView.setDisableScrollingWhileRefreshing(!mPullRefreshListView
 .isDisableScrollingWhileRefreshing());
 break;
 }
 
 
 return super.onOptionsItemSelected(item);
 }
 
 
 private class Mybaseadapter extends BaseAdapter {
 @Override
 public int getCount() {
 return 31;
 }
 
 
 @Override
 public Object getItem(int position) {
 return 0;
 }
 
 
 @Override
 public long getItemId(int position) {
 return 0;
 }
 
 
 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
 if (position == 0) {
 return vg;
 } else {
 TextView mTextView = new TextView(PullToRefreshListActivity.this);
 mTextView.setText(position - 1 + "");
 return mTextView;
 }
 }
 
 
 }
 private class ImageAdapter extends BaseAdapter {
 private Context mContext;
 private int i = 0;
 
 
 public ImageAdapter(Context c) {
 mContext = c;
 }
 
 
 @Override
 public int getCount() {
 return mImage.length;
 }
 
 
 @Override
 public Object getItem(int position) {
 // TODO Auto-generated method stub
 
 
 return position;
 }
 
 
 @Override
 public long getItemId(int position) {
 // TODO Auto-generated method stub
 
 
 return position;
 }
 
 
 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
 // TODO Auto-generated method stub
 
 
 ImageView i = new ImageView(mContext);
 i.setImageResource(mImage[position]);
 // i.setScaleType(ImageView.ScaleType.FIT_XY);
 i.setLayoutParams(new Gallery.LayoutParams(800, LayoutParams.WRAP_CONTENT));
 
 
 return i;
 }
 
 
 };
 }
下拉刷新的动画部份
    package com.stay.pull.lib;
 
 
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.widget.AbsListView;
 import android.widget.AbsListView.OnScrollListener;
 import android.widget.FrameLayout;
 import android.widget.GridView;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ListView;
 
 
 import com.stay.pull.lib.internal.EmptyViewMethodAccessor;
 
 
 
 
 public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extends PullToRefreshBase<T> implements
 OnScrollListener {
 
 
 private int lastSavedFirstVisibleItem = -1;
 private OnScrollListener onScrollListener;
 private OnLastItemVisibleListener onLastItemVisibleListener;
 private View emptyView;
 private FrameLayout refreshableViewHolder;
 private ImageView mTopImageView;
 
 
 public PullToRefreshAdapterViewBase(Context context) {
 super(context);
 refreshableView.setOnScrollListener(this);
 }
 
 
 public PullToRefreshAdapterViewBase(Context context, int mode) {
 super(context, mode);
 refreshableView.setOnScrollListener(this);
 }
 
 
 public PullToRefreshAdapterViewBase(Context context, AttributeSet attrs) {
 super(context, attrs);
 refreshableView.setOnScrollListener(this);
 }
 
 
 abstract public ContextMenuInfo getContextMenuInfo();
 
 
 public final void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount,
 final int totalItemCount) {
 
 
 if (null != onLastItemVisibleListener) {
 // detect if last item is visible
 if (visibleItemCount > 0 && (firstVisibleItem + visibleItemCount == totalItemCount)) {
 // only process first event
 if (firstVisibleItem != lastSavedFirstVisibleItem) {
 lastSavedFirstVisibleItem = firstVisibleItem;
 onLastItemVisibleListener.onLastItemVisible();
 }
 }
 }
 
 
 if (null != onScrollListener) {
 onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
 }
 }
 
 
 public final void onScrollStateChanged(final AbsListView view, final int scrollState) {
 if (null != onScrollListener) {
 onScrollListener.onScrollStateChanged(view, scrollState);
 }
 }
 
 public void setBackToTopView(ImageView mTopImageView){
 this.mTopImageView = mTopImageView;
 mTopImageView.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 if (refreshableView instanceof ListView ) {
 ((ListView)refreshableView).setSelection(0);
 }else if(refreshableView instanceof GridView){
 ((GridView)refreshableView).setSelection(0);
 }
 }
 });
 }
 
 
 /**
 * Sets the Empty View to be used by the Adapter View.
 * 
 * We need it handle it ourselves so that we can Pull-to-Refresh when the
 * Empty View is shown.
 * 
 * Please note, you do <strong>not</strong> usually need to call this method
 * yourself. Calling setEmptyView on the AdapterView will automatically call
 * this method and set everything up. This includes when the Android
 * Framework automatically sets the Empty View based on it's ID.
 * 
 * @param newEmptyView
 *            - Empty View to be used
 */
 public final void setEmptyView(View newEmptyView) {
 // If we already have an Empty View, remove it
 if (null != emptyView) {
 refreshableViewHolder.removeView(emptyView);
 }
 
 
 if (null != newEmptyView) {
 ViewParent newEmptyViewParent = newEmptyView.getParent();
 if (null != newEmptyViewParent && newEmptyViewParent instanceof ViewGroup) {
 ((ViewGroup) newEmptyViewParent).removeView(newEmptyView);
 }
 
 
 this.refreshableViewHolder.addView(newEmptyView, ViewGroup.LayoutParams.FILL_PARENT,
 ViewGroup.LayoutParams.FILL_PARENT);
 }
 
 
 if (refreshableView instanceof EmptyViewMethodAccessor) {
 ((EmptyViewMethodAccessor) refreshableView).setEmptyViewInternal(newEmptyView);
 } else {
 this.refreshableView.setEmptyView(newEmptyView);
 }
 }
 
 
 public final void setOnLastItemVisibleListener(OnLastItemVisibleListener listener) {
 onLastItemVisibleListener = listener;
 }
 
 
 public final void setOnScrollListener(OnScrollListener listener) {
 onScrollListener = listener;
 }
 
 
 protected void addRefreshableView(Context context, T refreshableView) {
 refreshableViewHolder = new FrameLayout(context);
 refreshableViewHolder.addView(refreshableView, ViewGroup.LayoutParams.FILL_PARENT,
 ViewGroup.LayoutParams.FILL_PARENT);
 addView(refreshableViewHolder, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, 0, 1.0f));
 };
 
 
 protected boolean isReadyForPullDown() {
 return isFirstItemVisible();
 }
 
 
 protected boolean isReadyForPullUp() {
 return isLastItemVisible();
 }
 
 
 private boolean isFirstItemVisible() {
 if (this.refreshableView.getCount() == 0) {
 return true;
 } else if (refreshableView.getFirstVisiblePosition() == 0) {
 
 final View firstVisibleChild = refreshableView.getChildAt(0);
 
 if (firstVisibleChild != null) {
 return firstVisibleChild.getTop() >= refreshableView.getTop();
 }
 }
 
 return false;
 }
 
 
 private boolean isLastItemVisible() {
 final int count = this.refreshableView.getCount();
 final int lastVisiblePosition = refreshableView.getLastVisiblePosition();
 
 
 if (count == 0) {
 return true;
 } else if (lastVisiblePosition == count - 1) {
 
 
 final int childIndex = lastVisiblePosition - refreshableView.getFirstVisiblePosition();
 final View lastVisibleChild = refreshableView.getChildAt(childIndex);
 
 
 if (lastVisibleChild != null) {
 return lastVisibleChild.getBottom() <= refreshableView.getBottom();
 }
 }
 return false;
 }
 }
    package com.stay.pull.lib;
 
 
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.os.Handler;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.widget.LinearLayout;
 
 
 import com.stay.pull.R;
 import com.stay.pull.lib.internal.LoadingLayout;
 
 
 public abstract class PullToRefreshBase<T extends View> extends LinearLayout {
 
 
 final class SmoothScrollRunnable implements Runnable {
 
 
 static final int ANIMATION_DURATION_MS = 190;
 static final int ANIMATION_FPS = 1000 / 60;
 
 
 private final Interpolator interpolator;
 private final int scrollToY;
 private final int scrollFromY;
 private final Handler handler;
 
 
 private boolean continueRunning = true;
 private long startTime = -1;
 private int currentY = -1;
 
 
 public SmoothScrollRunnable(Handler handler, int fromY, int toY) {
 this.handler = handler;
 this.scrollFromY = fromY;
 this.scrollToY = toY;
 this.interpolator = new AccelerateDecelerateInterpolator();
 }
 
 
 @Override
 public void run() {
 
 
 /**
 * Only set startTime if this is the first time we're starting, else
 * actually calculate the Y delta
 */
 if (startTime == -1) {
 startTime = System.currentTimeMillis();
 } else {
 
 
 /**
 * We do do all calculations in long to reduce software float
 * calculations. We use 1000 as it gives us good accuracy and
 * small rounding errors
 */
 long normalizedTime = (1000 * (System.currentTimeMillis() - startTime)) / ANIMATION_DURATION_MS;
 normalizedTime = Math.max(Math.min(normalizedTime, 1000), 0);
 
 
 final int deltaY = Math.round((scrollFromY - scrollToY)
 * interpolator.getInterpolation(normalizedTime / 1000f));
 this.currentY = scrollFromY - deltaY;
 setHeaderScroll(currentY);
 }
 
 
 // If we're not at the target Y, keep going...
 if (continueRunning && scrollToY != currentY) {
 handler.postDelayed(this, ANIMATION_FPS);
 }
 }
 
 
 public void stop() {
 this.continueRunning = false;
 this.handler.removeCallbacks(this);
 }
 };
 
 
 // ===========================================================
 // Constants
 // ===========================================================
 
 
 static final float FRICTION = 2.0f;
 
 
 static final int PULL_TO_REFRESH = 0x0;
 static final int RELEASE_TO_REFRESH = 0x1;
 static final int REFRESHING = 0x2;
 static final int MANUAL_REFRESHING = 0x3;
 
 
 public static final int MODE_PULL_DOWN_TO_REFRESH = 0x1;
 public static final int MODE_PULL_UP_TO_REFRESH = 0x2;
 public static final int MODE_BOTH = 0x3;
 
 
 // ===========================================================
 // Fields
 // ===========================================================
 
 
 private int touchSlop;
 
 
 private float initialMotionY;
 private float lastMotionX;
 private float lastMotionY;
 private boolean isBeingDragged = false;
 
 
 private int state = PULL_TO_REFRESH;
 private int mode = MODE_PULL_DOWN_TO_REFRESH;
 private int currentMode;
 
 
 private boolean disableScrollingWhileRefreshing = true;
 
 
 T refreshableView;
 private boolean isPullToRefreshEnabled = true;
 
 
 private LoadingLayout headerLayout;
 private LoadingLayout footerLayout;
 private int headerHeight;
 
 
 private final Handler handler = new Handler();
 
 
 private OnRefreshListener onRefreshListener;
 
 
 private SmoothScrollRunnable currentSmoothScrollRunnable;
 
 
 // ===========================================================
 // Constructors
 // ===========================================================
 
 
 public PullToRefreshBase(Context context) {
 super(context);
 init(context, null);
 }
 
 
 public PullToRefreshBase(Context context, int mode) {
 super(context);
 this.mode = mode;
 init(context, null);
 }
 
 
 public PullToRefreshBase(Context context, AttributeSet attrs) {
 super(context, attrs);
 init(context, attrs);
 }
 
 
 // ===========================================================
 // Getter & Setter
 // ===========================================================
 
 
 /**
 * Deprecated. Use {@link #getRefreshableView()} from now on.
 * 
 * @deprecated
 * @return The Refreshable View which is currently wrapped
 */
 public final T getAdapterView() {
 return refreshableView;
 }
 
 
 /**
 * Get the Wrapped Refreshable View. Anything returned here has already been
 * added to the content view.
 * 
 * @return The View which is currently wrapped
 */
 public final T getRefreshableView() {
 return refreshableView;
 }
 
 
 /**
 * Whether Pull-to-Refresh is enabled
 * 
 * @return enabled
 */
 public final boolean isPullToRefreshEnabled() {
 return isPullToRefreshEnabled;
 }
 
 
 /**
 * Returns whether the widget has disabled scrolling on the Refreshable View
 * while refreshing.
 * 
 * @param true if the widget has disabled scrolling while refreshing
 */
 public final boolean isDisableScrollingWhileRefreshing() {
 return disableScrollingWhileRefreshing;
 }
 
 
 /**
 * Returns whether the Widget is currently in the Refreshing state
 * 
 * @return true if the Widget is currently refreshing
 */
 public final boolean isRefreshing() {
 return state == REFRESHING || state == MANUAL_REFRESHING;
 }
 
 
 /**
 * By default the Widget disabled scrolling on the Refreshable View while
 * refreshing. This method can change this behaviour.
 * 
 * @param disableScrollingWhileRefreshing
 *            - true if you want to disable scrolling while refreshing
 */
 public final void setDisableScrollingWhileRefreshing(boolean disableScrollingWhileRefreshing) {
 this.disableScrollingWhileRefreshing = disableScrollingWhileRefreshing;
 }
 
 
 /**
 * Mark the current Refresh as complete. Will Reset the UI and hide the
 * Refreshing View
 */
 public final void onRefreshComplete() {
 if (state != PULL_TO_REFRESH) {
 resetHeader();
 }
 }
 
 
 /**
 * Set OnRefreshListener for the Widget
 * 
 * @param listener
 *            - Listener to be used when the Widget is set to Refresh
 */
 public final void setOnRefreshListener(OnRefreshListener listener) {
 onRefreshListener = listener;
 }
 
 
 /**
 * A mutator to enable/disable Pull-to-Refresh for the current View
 * 
 * @param enable
 *            Whether Pull-To-Refresh should be used
 */
 public final void setPullToRefreshEnabled(boolean enable) {
 this.isPullToRefreshEnabled = enable;
 }
 
 
 /**
 * Set Text to show when the Widget is being pulled, and will refresh when
 * released
 * 
 * @param releaseLabel
 *            - String to display
 */
 public void setReleaseLabel(String releaseLabel) {
 if (null != headerLayout) {
 headerLayout.setReleaseLabel(releaseLabel);
 }
 if (null != footerLayout) {
 footerLayout.setReleaseLabel(releaseLabel);
 }
 }
 
 
 /**
 * Set Text to show when the Widget is being Pulled
 * 
 * @param pullLabel
 *            - String to display
 */
 public void setPullLabel(String pullLabel) {
 if (null != headerLayout) {
 headerLayout.setPullLabel(pullLabel);
 }
 if (null != footerLayout) {
 footerLayout.setPullLabel(pullLabel);
 }
 }
 
 
 /**
 * Set Text to show when the Widget is refreshing
 * 
 * @param refreshingLabel
 *            - String to display
 */
 public void setRefreshingLabel(String refreshingLabel) {
 if (null != headerLayout) {
 headerLayout.setRefreshingLabel(refreshingLabel);
 }
 if (null != footerLayout) {
 footerLayout.setRefreshingLabel(refreshingLabel);
 }
 }
 
 
 public final void setRefreshing() {
 this.setRefreshing(true);
 }
 
 
 /**
 * Sets the Widget to be in the refresh state. The UI will be updated to
 * show the 'Refreshing' view.
 * 
 * @param doScroll
 *            - true if you want to force a scroll to the Refreshing view.
 */
 public final void setRefreshing(boolean doScroll) {
 if (!isRefreshing()) {
 setRefreshingInternal(doScroll);
 state = MANUAL_REFRESHING;
 }
 }
 
 
 public final boolean hasPullFromTop() {
 return currentMode != MODE_PULL_UP_TO_REFRESH;
 }
 
 
 // ===========================================================
 // Methods for/from SuperClass/Interfaces
 // ===========================================================
 
 
 @Override
 public final boolean onTouchEvent(MotionEvent event) {
 if (!isPullToRefreshEnabled) {
 return false;
 }
 
 
 if (isRefreshing() && disableScrollingWhileRefreshing) {
 return true;
 }
 
 
 if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {
 return false;
 }
 
 
 switch (event.getAction()) {
 
 
 case MotionEvent.ACTION_MOVE: {
 if (isBeingDragged) {
 lastMotionY = event.getY();
 this.pullEvent();
 return true;
 }
 break;
 }
 
 
 case MotionEvent.ACTION_DOWN: {
 if (isReadyForPull()) {
 lastMotionY = initialMotionY = event.getY();
 return true;
 }
 break;
 }
 
 
 case MotionEvent.ACTION_CANCEL:
 case MotionEvent.ACTION_UP: {
 if (isBeingDragged) {
 isBeingDragged = false;
 
 
 if (state == RELEASE_TO_REFRESH && null != onRefreshListener) {
 setRefreshingInternal(true);
 onRefreshListener.onRefresh();
 } else {
 smoothScrollTo(0);
 }
 return true;
 }
 break;
 }
 }
 
 
 return false;
 }
 
 
 @Override
 public final boolean onInterceptTouchEvent(MotionEvent event) {
 
 
 if (!isPullToRefreshEnabled) {
 return false;
 }
 
 
 if (isRefreshing() && disableScrollingWhileRefreshing) {
 return true;
 }
 
 
 final int action = event.getAction();
 
 
 if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
 isBeingDragged = false;
 return false;
 }
 
 
 if (action != MotionEvent.ACTION_DOWN && isBeingDragged) {
 return true;
 }
 
 
 switch (action) {
 case MotionEvent.ACTION_MOVE: {
 if (isReadyForPull()) {
 
 
 final float y = event.getY();
 final float dy = y - lastMotionY;
 final float yDiff = Math.abs(dy);
 final float xDiff = Math.abs(event.getX() - lastMotionX);
 
 
 if (yDiff > touchSlop && yDiff > xDiff) {
 if ((mode == MODE_PULL_DOWN_TO_REFRESH || mode == MODE_BOTH) && dy >= 0.0001f
 && isReadyForPullDown()) {
 lastMotionY = y;
 isBeingDragged = true;
 if (mode == MODE_BOTH) {
 currentMode = MODE_PULL_DOWN_TO_REFRESH;
 }
 } else if ((mode == MODE_PULL_UP_TO_REFRESH || mode == MODE_BOTH) && dy <= 0.0001f
 && isReadyForPullUp()) {
 lastMotionY = y;
 isBeingDragged = true;
 if (mode == MODE_BOTH) {
 currentMode = MODE_PULL_UP_TO_REFRESH;
 }
 }
 }
 }
 break;
 }
 case MotionEvent.ACTION_DOWN: {
 if (isReadyForPull()) {
 lastMotionY = initialMotionY = event.getY();
 lastMotionX = event.getX();
 isBeingDragged = false;
 }
 break;
 }
 }
 
 
 return isBeingDragged;
 }
 
 
 protected void addRefreshableView(Context context, T refreshableView) {
 addView(refreshableView, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, 0, 1.0f));
 }
 
 
 /**
 * This is implemented by derived classes to return the created View. If you
 * need to use a custom View (such as a custom ListView), override this
 * method and return an instance of your custom class.
 * 
 * Be sure to set the ID of the view in this method, especially if you're
 * using a ListActivity or ListFragment.
 * 
 * @param context
 * @param attrs
 *            AttributeSet from wrapped class. Means that anything you
 *            include in the XML layout declaration will be routed to the
 *            created View
 * @return New instance of the Refreshable View
 */
 protected abstract T createRefreshableView(Context context, AttributeSet attrs);
 
 
 protected final int getCurrentMode() {
 return currentMode;
 }
 
 
 protected final LoadingLayout getFooterLayout() {
 return footerLayout;
 }
 
 
 protected final LoadingLayout getHeaderLayout() {
 return headerLayout;
 }
 
 
 protected final int getHeaderHeight() {
 return headerHeight;
 }
 
 
 protected final int getMode() {
 return mode;
 }
 
 
 /**
 * Implemented by derived class to return whether the View is in a state
 * where the user can Pull to Refresh by scrolling down.
 * 
 * @return true if the View is currently the correct state (for example, top
 *         of a ListView)
 */
 protected abstract boolean isReadyForPullDown();
 
 
 /**
 * Implemented by derived class to return whether the View is in a state
 * where the user can Pull to Refresh by scrolling up.
 * 
 * @return true if the View is currently in the correct state (for example,
 *         bottom of a ListView)
 */
 protected abstract boolean isReadyForPullUp();
 
 
 // ===========================================================
 // Methods
 // ===========================================================
 
 
 protected void resetHeader() {
 state = PULL_TO_REFRESH;
 isBeingDragged = false;
 
 
 if (null != headerLayout) {
 headerLayout.reset();
 }
 if (null != footerLayout) {
 footerLayout.reset();
 }
 
 
 smoothScrollTo(0);
 }
 
 
 protected void setRefreshingInternal(boolean doScroll) {
 state = REFRESHING;
 
 
 if (null != headerLayout) {
 headerLayout.refreshing();
 }
 if (null != footerLayout) {
 footerLayout.refreshing();
 }
 
 
 if (doScroll) {
 smoothScrollTo(currentMode == MODE_PULL_DOWN_TO_REFRESH ? -headerHeight : headerHeight);
 }
 }
 
 
 protected final void setHeaderScroll(int y) {
 scrollTo(0, y);
 }
 
 
 protected final void smoothScrollTo(int y) {
 if (null != currentSmoothScrollRunnable) {
 currentSmoothScrollRunnable.stop();
 }
 
 
 if (this.getScrollY() != y) {
 this.currentSmoothScrollRunnable = new SmoothScrollRunnable(handler, getScrollY(), y);
 handler.post(currentSmoothScrollRunnable);
 }
 }
 
 
 private void init(Context context, AttributeSet attrs) {
 
 
 setOrientation(LinearLayout.VERTICAL);
 
 
 touchSlop = ViewConfiguration.getTouchSlop();
 
 
 // Styleables from XML
 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PullToRefresh);
 if (a.hasValue(R.styleable.PullToRefresh_mode)) {
 mode = a.getInteger(R.styleable.PullToRefresh_mode, MODE_PULL_DOWN_TO_REFRESH);
 }
 
 
 // Refreshable View
 // By passing the attrs, we can add ListView/GridView params via XML
 refreshableView = this.createRefreshableView(context, attrs);
 this.addRefreshableView(context, refreshableView);
 
 
 // Loading View Strings
 String pullLabel = context.getString(R.string.pull_to_refresh_pull_label);
 String refreshingLabel = context.getString(R.string.pull_to_refresh_refreshing_label);
 String releaseLabel = context.getString(R.string.pull_to_refresh_release_label);
 
 
 // Add Loading Views
 if (mode == MODE_PULL_DOWN_TO_REFRESH || mode == MODE_BOTH) {
 headerLayout = new LoadingLayout(context, MODE_PULL_DOWN_TO_REFRESH, releaseLabel, pullLabel,
 refreshingLabel);
 addView(headerLayout, 0, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
 ViewGroup.LayoutParams.WRAP_CONTENT));
 measureView(headerLayout);
 headerHeight = headerLayout.getMeasuredHeight();
 }
 if (mode == MODE_PULL_UP_TO_REFRESH || mode == MODE_BOTH) {
 footerLayout = new LoadingLayout(context, MODE_PULL_UP_TO_REFRESH, releaseLabel, pullLabel, refreshingLabel);
 addView(footerLayout, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
 ViewGroup.LayoutParams.WRAP_CONTENT));
 measureView(footerLayout);
 headerHeight = footerLayout.getMeasuredHeight();
 }
 
 
 // Styleables from XML
 if (a.hasValue(R.styleable.PullToRefresh_headerTextColor)) {
 final int color = a.getColor(R.styleable.PullToRefresh_headerTextColor, Color.BLACK);
 if (null != headerLayout) {
 headerLayout.setTextColor(color);
 }
 if (null != footerLayout) {
 footerLayout.setTextColor(color);
 }
 }
 if (a.hasValue(R.styleable.PullToRefresh_headerBackground)) {
 this.setBackgroundResource(a.getResourceId(R.styleable.PullToRefresh_headerBackground, Color.WHITE));
 }
 if (a.hasValue(R.styleable.PullToRefresh_adapterViewBackground)) {
 refreshableView.setBackgroundResource(a.getResourceId(R.styleable.PullToRefresh_adapterViewBackground,
 Color.WHITE));
 }
 a.recycle();
 
 
 // Hide Loading Views
 switch (mode) {
 case MODE_BOTH:
 setPadding(0, -headerHeight, 0, -headerHeight);
 break;
 case MODE_PULL_UP_TO_REFRESH:
 setPadding(0, 0, 0, -headerHeight);
 break;
 case MODE_PULL_DOWN_TO_REFRESH:
 default:
 setPadding(0, -headerHeight, 0, 0);
 break;
 }
 
 
 // If we're not using MODE_BOTH, then just set currentMode to current
 // mode
 if (mode != MODE_BOTH) {
 currentMode = mode;
 }
 }
 
 
 private void measureView(View child) {
 ViewGroup.LayoutParams p = child.getLayoutParams();
 if (p == null) {
 p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
 }
 
 
 int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
 int lpHeight = p.height;
 int childHeightSpec;
 if (lpHeight > 0) {
 childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
 } else {
 childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
 }
 child.measure(childWidthSpec, childHeightSpec);
 }
 
 
 /**
 * Actions a Pull Event
 * 
 * @return true if the Event has been handled, false if there has been no
 *         change
 */
 private boolean pullEvent() {
 
 
 final int newHeight;
 final int oldHeight = this.getScrollY();
 
 
 switch (currentMode) {
 case MODE_PULL_UP_TO_REFRESH:
 newHeight = Math.round(Math.max(initialMotionY - lastMotionY, 0) / FRICTION);
 //newHeight = Math.round((initialMotionY - lastMotionY) / FRICTION);
 break;
 case MODE_PULL_DOWN_TO_REFRESH:
 default:
 newHeight = Math.round(Math.min(initialMotionY - lastMotionY, 0) / FRICTION);
 //newHeight = Math.round((initialMotionY - lastMotionY) / FRICTION);
 break;
 }
 
 
 setHeaderScroll(newHeight);
 
 
 if (newHeight != 0) {
 if (state == PULL_TO_REFRESH && headerHeight < Math.abs(newHeight)) {
 state = RELEASE_TO_REFRESH;
 
 
 switch (currentMode) {
 case MODE_PULL_UP_TO_REFRESH:
 footerLayout.releaseToRefresh();
 break;
 case MODE_PULL_DOWN_TO_REFRESH:
 headerLayout.releaseToRefresh();
 break;
 }
 
 
 return true;
 
 
 } else if (state == RELEASE_TO_REFRESH && headerHeight >= Math.abs(newHeight)) {
 state = PULL_TO_REFRESH;
 
 
 switch (currentMode) {
 case MODE_PULL_UP_TO_REFRESH:
 footerLayout.pullToRefresh();
 break;
 case MODE_PULL_DOWN_TO_REFRESH:
 headerLayout.pullToRefresh();
 break;
 }
 
 
 return true;
 }
 }
 
 
 return oldHeight != newHeight;
 }
 
 
 private boolean isReadyForPull() {
 switch (mode) {
 case MODE_PULL_DOWN_TO_REFRESH:
 return isReadyForPullDown();
 case MODE_PULL_UP_TO_REFRESH:
 return isReadyForPullUp();
 case MODE_BOTH:
 return isReadyForPullUp() || isReadyForPullDown();
 }
 return false;
 }
 
 
 // ===========================================================
 // Inner and Anonymous Classes
 // ===========================================================
 
 
 public static interface OnRefreshListener {
 
 
 public void onRefresh();
 
 
 }
 
 
 public static interface OnLastItemVisibleListener {
 
 
 public void onLastItemVisible();
 
 
 }
 
 
 @Override
 public void setLongClickable(boolean longClickable) {
 getRefreshableView().setLongClickable(longClickable);
 }
 }
    package com.stay.pull.lib;
 
 
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.View;
 import android.widget.ListView;
 
 
 import com.stay.pull.lib.internal.EmptyViewMethodAccessor;
 
 
 public class PullToRefreshListView extends PullToRefreshAdapterViewBase<ListView> {
                                                   
 //private LoadingLayout headerLoadingView;
 //private LoadingLayout footerLoadingView;
 
 
 class InternalListView extends ListView implements EmptyViewMethodAccessor {
 
 public InternalListView(Context context, AttributeSet attrs) {
 super(context, attrs);
 }
 
 
 @Override
 public void setEmptyView(View emptyView) {
 PullToRefreshListView.this.setEmptyView(emptyView);
 }
 
 @Override
 public void setEmptyViewInternal(View emptyView) {
 super.setEmptyView(emptyView);
 }
 
 
 public ContextMenuInfo getContextMenuInfo() {
 return super.getContextMenuInfo();
 }
 }
 
 
 public PullToRefreshListView(Context context) {
 super(context);
 this.setDisableScrollingWhileRefreshing(false);
 }
 
 public PullToRefreshListView(Context context, int mode) {
 super(context, mode);
 this.setDisableScrollingWhileRefreshing(false);
 }
 
 
 public PullToRefreshListView(Context context, AttributeSet attrs) {
 super(context, attrs);
 this.setDisableScrollingWhileRefreshing(false);
 }
 
 
 @Override
 public ContextMenuInfo getContextMenuInfo() {
 return ((InternalListView) getRefreshableView()).getContextMenuInfo();
 }
 
 
 //public void setReleaseLabel(String releaseLabel) {
 //super.setReleaseLabel(releaseLabel);
 //if (null != headerLoadingView) {
 //headerLoadingView.setReleaseLabel(releaseLabel);
 //}
 //if (null != footerLoadingView) {
 //footerLoadingView.setReleaseLabel(releaseLabel);
 //}
 //}
 //
 //public void setPullLabel(String pullLabel) {
 //super.setPullLabel(pullLabel);
 //
 //if (null != headerLoadingView) {
 //headerLoadingView.setPullLabel(pullLabel);
 //}
 //if (null != footerLoadingView) {
 //footerLoadingView.setPullLabel(pullLabel);
 //}
 //}
 //
 //public void setRefreshingLabel(String refreshingLabel) {
 //super.setRefreshingLabel(refreshingLabel);
 //
 //if (null != headerLoadingView) {
 //headerLoadingView.setRefreshingLabel(refreshingLabel);
 //}
 //if (null != footerLoadingView) {
 //footerLoadingView.setRefreshingLabel(refreshingLabel);
 //}
 //}
 
 
 @Override
 protected final ListView createRefreshableView(Context context, AttributeSet attrs) {
 ListView lv = new InternalListView(context, attrs);
 //final int mode = this.getMode();
 //
 //// Loading View Strings
 //String pullLabel = context.getString(R.string.pull_to_refresh_pull_label);
 //String refreshingLabel = context.getString(R.string.pull_to_refresh_refreshing_label);
 //String releaseLabel = context.getString(R.string.pull_to_refresh_release_label);
 
 
 // Add Loading Views
 //if (mode == MODE_PULL_DOWN_TO_REFRESH || mode == MODE_BOTH) {
 //FrameLayout frame = new FrameLayout(context);
 //headerLoadingView = new LoadingLayout(context, MODE_PULL_DOWN_TO_REFRESH, releaseLabel, pullLabel,
 //refreshingLabel);
 //frame.addView(headerLoadingView, FrameLayout.LayoutParams.FILL_PARENT,
 //FrameLayout.LayoutParams.WRAP_CONTENT);
 //headerLoadingView.setVisibility(View.GONE);
 //lv.addHeaderView(frame);
 //}
 //if (mode == MODE_PULL_UP_TO_REFRESH || mode == MODE_BOTH) {
 //FrameLayout frame = new FrameLayout(context);
 //footerLoadingView = new LoadingLayout(context, MODE_PULL_UP_TO_REFRESH, releaseLabel, pullLabel,
 //refreshingLabel);
 //frame.addView(footerLoadingView, FrameLayout.LayoutParams.FILL_PARENT,
 //FrameLayout.LayoutParams.WRAP_CONTENT);
 //footerLoadingView.setVisibility(View.GONE);
 //lv.addFooterView(frame);
 //}
 
 
 // Set it to this so it can be used in ListActivity/ListFragment
 lv.setId(android.R.id.list);
 return lv;
 }
 
 
 //@Override
 //protected void setRefreshingInternal(boolean doScroll) {
 //super.setRefreshingInternal(false);
 //
 //final LoadingLayout originalLoadingLayout, listViewLoadingLayout;
 //final int selection, scrollToY;
 //
 //switch (getCurrentMode()) {
 //case MODE_PULL_UP_TO_REFRESH:
 //originalLoadingLayout = this.getFooterLayout();
 //listViewLoadingLayout = this.footerLoadingView;
 //selection = refreshableView.getCount() - 1;
 //scrollToY = getScrollY() - getHeaderHeight();
 //break;
 //case MODE_PULL_DOWN_TO_REFRESH:
 //default:
 //originalLoadingLayout = this.getHeaderLayout();
 //listViewLoadingLayout = this.headerLoadingView;
 //selection = 0;
 //scrollToY = getScrollY() + getHeaderHeight();
 //break;
 //}
 //
 //if (doScroll) {
 //// We scroll slightly so that the ListView's header/footer is at the
 //// same Y position as our normal header/footer
 //this.setHeaderScroll(scrollToY);
 //}
 //
 //// Hide our original Loading View
 //originalLoadingLayout.setVisibility(View.INVISIBLE);
 //
 //// Show the ListView Loading View and set it to refresh
 //listViewLoadingLayout.setVisibility(View.VISIBLE);
 //listViewLoadingLayout.refreshing();
 //
 //if (doScroll) {
 //// Make sure the ListView is scrolled to show the loading
 //// header/footer
 //refreshableView.setSelection(selection);
 //
 //// Smooth scroll as normal
 //smoothScrollTo(0);
 //}
 //}
 
 
 //@Override
 //protected void resetHeader() {
 //
 //LoadingLayout originalLoadingLayout;
 //LoadingLayout listViewLoadingLayout;
 //
 //int scrollToHeight = getHeaderHeight();
 //final boolean doScroll;
 //
 //switch (getCurrentMode()) {
 //case MODE_PULL_UP_TO_REFRESH:
 //originalLoadingLayout = this.getFooterLayout();
 //listViewLoadingLayout = footerLoadingView;
 //doScroll = this.isReadyForPullUp();
 //break;
 //case MODE_PULL_DOWN_TO_REFRESH:
 //default:
 //originalLoadingLayout = this.getHeaderLayout();
 //listViewLoadingLayout = headerLoadingView;
 //scrollToHeight *= -1;
 //doScroll = this.isReadyForPullDown();
 //break;
 //}
 //
 //// Set our Original View to Visible
 //originalLoadingLayout.setVisibility(View.VISIBLE);
 //
 //// Scroll so our View is at the same Y as the ListView header/footer,
 //// but only scroll if the ListView is at the top/bottom
 //if (doScroll) {
 //this.setHeaderScroll(scrollToHeight);
 //}
 //
 //// Hide the ListView Header/Footer
 //listViewLoadingLayout.setVisibility(View.GONE);
 //
 //super.resetHeader();
 //}
 
 
 }
    package com.stay.pull.lib.internal;
 
 
 import android.view.View;
 import android.widget.ImageView;
 
 
 /**
  * Interface that allows PullToRefreshBase to hijack the call to
  * AdapterView.setEmptyView()
  * 
  * @author chris
  */
 public interface EmptyViewMethodAccessor {
 
 
 /**
 * Calls upto AdapterView.setEmptyView()
 * 
 * @param View
 *            to set as Empty View
 */
 public void setEmptyViewInternal(View emptyView);
 
 
 /**
 * Should call PullToRefreshBase.setEmptyView() which will then
 * automatically call through to setEmptyViewInternal()
 * 
 * @param View
 *            to set as Empty View
 */
 public void setEmptyView(View emptyView);
 
 
 
 
 }
    package com.stay.pull.lib.internal;
 
 
 import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.Animation;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.view.animation.RotateAnimation;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
 
 import com.stay.pull.R;
 import com.stay.pull.lib.PullToRefreshBase;
 
 
 public class LoadingLayout extends FrameLayout {
 
 
 static final int DEFAULT_ROTATION_ANIMATION_DURATION = 150;
 
 
 private final ImageView headerImage;
 private final ProgressBar headerProgress;
 private final TextView headerText;
 
 
 private String pullLabel;
 private String refreshingLabel;
 private String releaseLabel;
 
 
 private final Animation rotateAnimation, resetRotateAnimation;
 
 
 public LoadingLayout(Context context, final int mode, String releaseLabel, String pullLabel, String refreshingLabel) {
 super(context);
 ViewGroup header = (ViewGroup) LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header, this);
 headerText = (TextView) header.findViewById(R.id.pull_to_refresh_text);
 headerImage = (ImageView) header.findViewById(R.id.pull_to_refresh_image);
 headerProgress = (ProgressBar) header.findViewById(R.id.pull_to_refresh_progress);
 
 
 final Interpolator interpolator = new LinearInterpolator();
 rotateAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
        0.5f);
 rotateAnimation.setInterpolator(interpolator);
 rotateAnimation.setDuration(DEFAULT_ROTATION_ANIMATION_DURATION);
 rotateAnimation.setFillAfter(true);
 
 
 resetRotateAnimation = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f,
        Animation.RELATIVE_TO_SELF, 0.5f);
 resetRotateAnimation.setInterpolator(interpolator);
 resetRotateAnimation.setDuration(DEFAULT_ROTATION_ANIMATION_DURATION);
 resetRotateAnimation.setFillAfter(true);
 
 
 this.releaseLabel = releaseLabel;
 this.pullLabel = pullLabel;
 this.refreshingLabel = refreshingLabel;
 
 
 switch (mode) {
 case PullToRefreshBase.MODE_PULL_UP_TO_REFRESH:
 headerImage.setImageResource(R.drawable.pulltorefresh_up_arrow);
 break;
 case PullToRefreshBase.MODE_PULL_DOWN_TO_REFRESH:
 default:
 headerImage.setImageResource(R.drawable.pulltorefresh_down_arrow);
 break;
 }
 }
 
 
 public void reset() {
 headerText.setText(pullLabel);
 headerImage.setVisibility(View.VISIBLE);
 headerProgress.setVisibility(View.GONE);
 }
 
 
 public void releaseToRefresh() {
 headerText.setText(releaseLabel);
 headerImage.clearAnimation();
 headerImage.startAnimation(rotateAnimation);
 }
 
 
 public void setPullLabel(String pullLabel) {
 this.pullLabel = pullLabel;
 }
 
 
 public void refreshing() {
 headerText.setText(refreshingLabel);
 headerImage.clearAnimation();
 headerImage.setVisibility(View.INVISIBLE);
 headerProgress.setVisibility(View.VISIBLE);
 }
 
 
 public void setRefreshingLabel(String refreshingLabel) {
 this.refreshingLabel = refreshingLabel;
 }
 
 
 public void setReleaseLabel(String releaseLabel) {
 this.releaseLabel = releaseLabel;
 }
 
 
 public void pullToRefresh() {
 headerText.setText(pullLabel);
 headerImage.clearAnimation();
 headerImage.startAnimation(resetRotateAnimation);
 }
 
 
 public void setTextColor(int color) {
 headerText.setTextColor(color);
 }
 
 
 }
文章结束给大家分享下程序员的一些笑话语录: 
程序语言综述
    CLIPPER 程序员不去真的猎捕大象,他们只是购买大象部分的库然后花几年的时间试图综合它们。
    DBASE 程序员只在夜间猎捕大象,因为那时没人会注意到他们还在使用石弓。
    FOXPRO 程序员开始使用更新更好的步枪,这使他们花掉比实际狩猎更多的时间学习新的射击技术。
    C 程序员拒绝直接购买步枪,宁可带着钢管和一个移动式机器车间到非洲,意欲从零开始造一枝完美的步枪。
    PARADOX 程序员去非洲时带着好莱坞关于猎捕大象的电影剧本,他们认为照剧本行事就会逮到一头大象。
    ACCESS 程序员在没有任何猎象经验的经验下就出发了,他们穿着华丽的猎装、带着全部装备,用漂亮的望远镜找到了大象,然后发觉忘了带扳机。
    RBASE 程序员比大象还要稀少,事实上,如果一头大象看到了一个RBASE程序员,对他是个幸运日。
    VISUAL ACCESS 程序员装上子弹、举起步枪、瞄准大象,这使大象感到可笑,究竟谁逃跑。他们无法抓住大象,因为由于他们对多重控制的偏爱,他们的吉普车有太多的方向盘因而无法驾驶。
    ADA、APL和FORTRAN 程序员与圣诞老人和仙女一样是虚构的。
    COBOL 程序员对和自己一样濒临灭绝的大象寄予了深切的同情。
                    
                
                
            
        
浙公网安备 33010602011771号