精华内容
下载资源
问答
  • Vue刷新页面的三种方式

    万次阅读 多人点赞 2019-06-08 10:54:18
    我们在写项目的时候,经常会遇到,用户执行完某个动作,改变了某些状态,需要重新刷新页面,以此来重新渲染页面。如:用户登录成功、增加、删除、更新等。 原始方法: location.reload(); vue自带的路由跳转: ...

    我们在写项目的时候,经常会遇到,用户执行完某个动作,改变了某些状态,需要重新刷新页面,以此来重新渲染页面。如:用户登录成功、增加、删除、更新等。

    1. 原始方法:
    location.reload();
    
    1. vue自带的路由跳转:
    this.$router.go(0);
    

    用过的人都知道,前两者都是强制刷新页面,会出现短暂的闪烁,用户体验效果不好。
    所以,我们选择第三种方式:
    3. 首先在App里面写下如下代码:

    <template>
        <div id="app">
        	<router-view v-if="isRouterAlive"></router-view>
    	</div>
    </template>
    <script>
        export default {
            name: 'App',
            provide () {    //父组件中通过provide来提供变量,在子组件中通过inject来注入变量。                                             
                return {
                    reload: this.reload                                              
                }
            },
            data() {
                return{
                    isRouterAlive: true                    //控制视图是否显示的变量
                }
            },
            methods: {
                reload () {
                    this.isRouterAlive = false;            //先关闭,
                    this.$nextTick(function () {
                        this.isRouterAlive = true;         //再打开
                    }) 
                }
            }}
    </script>
    

    接下来,我们就可以在需要刷新页面的组件里这样写:

    export default {
        inject:['reload'],                                 //注入App里的reload方法
        data () {
            return {
        	.......
            }
        },
    

    在需要刷新页面的代码块中使用:

    this.reload();
    
    展开全文
  • 最近项目中需要用到ListView下拉刷新的功能,一开始想图省事,在网上直接找一个现成的,可是尝试了网上多个版本的下拉刷新之后发现效果都不怎么理想。有些是因为功能不完整或有Bug,有些是因为使用起来太复杂,...

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9255575


    最近项目中需要用到ListView下拉刷新的功能,一开始想图省事,在网上直接找一个现成的,可是尝试了网上多个版本的下拉刷新之后发现效果都不怎么理想。有些是因为功能不完整或有Bug,有些是因为使用起来太复杂,十全十美的还真没找到。因此我也是放弃了在网上找现成代码的想法,自己花功夫编写了一种非常简单的下拉刷新实现方案,现在拿出来和大家分享一下。相信在阅读完本篇文章之后,大家都可以在自己的项目中一分钟引入下拉刷新功能。


    首先讲一下实现原理。这里我们将采取的方案是使用组合View的方式,先自定义一个布局继承自LinearLayout,然后在这个布局中加入下拉头和ListView这两个子元素,并让这两个子元素纵向排列。初始化的时候,让下拉头向上偏移出屏幕,这样我们看到的就只有ListView了。然后对ListView的touch事件进行监听,如果当前ListView已经滚动到顶部并且手指还在向下拉的话,那就将下拉头显示出来,松手后进行刷新操作,并将下拉头隐藏。原理示意图如下:




    那我们现在就来动手实现一下,新建一个项目起名叫PullToRefreshTest,先在项目中定义一个下拉头的布局文件pull_to_refresh.xml,代码如下所示:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/pull_to_refresh_head"
        android:layout_width="fill_parent"
        android:layout_height="60dip" >
    
        <LinearLayout
            android:layout_width="200dip"
            android:layout_height="60dip"
            android:layout_centerInParent="true"
            android:orientation="horizontal" >
    
            <RelativeLayout
                android:layout_width="0dip"
                android:layout_height="60dip"
                android:layout_weight="3"
                >
                <ImageView 
                    android:id="@+id/arrow"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:src="@drawable/arrow"
                    />
                <ProgressBar 
                    android:id="@+id/progress_bar"
                    android:layout_width="30dip"
                    android:layout_height="30dip"
                    android:layout_centerInParent="true"
                    android:visibility="gone"
                    />
            </RelativeLayout>
    
            <LinearLayout
                android:layout_width="0dip"
                android:layout_height="60dip"
                android:layout_weight="12"
                android:orientation="vertical" >
    
                <TextView
                    android:id="@+id/description"
                    android:layout_width="fill_parent"
                    android:layout_height="0dip"
                    android:layout_weight="1"
                    android:gravity="center_horizontal|bottom"
                    android:text="@string/pull_to_refresh" />
    
                <TextView
                    android:id="@+id/updated_at"
                    android:layout_width="fill_parent"
                    android:layout_height="0dip"
                    android:layout_weight="1"
                    android:gravity="center_horizontal|top"
                    android:text="@string/updated_at" />
            </LinearLayout>
        </LinearLayout>
    
    </RelativeLayout>

    在这个布局中,我们包含了一个下拉指示箭头,一个下拉状态文字提示,和一个上次更新的时间。当然,还有一个隐藏的旋转进度条,只有正在刷新的时候我们才会将它显示出来。


    布局中所有引用的字符串我们都放在strings.xml中,如下所示:
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    
        <string name="app_name">PullToRefreshTest</string>
    	<string name="pull_to_refresh">下拉可以刷新</string>
    	<string name="release_to_refresh">释放立即刷新</string>
    	<string name="refreshing">正在刷新…</string>
    	<string name="not_updated_yet">暂未更新过</string>
    	<string name="updated_at">上次更新于%1$s前</string>
    	<string name="updated_just_now">刚刚更新</string>
    	<string name="time_error">时间有问题</string>
        
    </resources>
    然后新建一个RefreshableView继承自LinearLayout,代码如下所示:
    public class RefreshableView extends LinearLayout implements OnTouchListener {
    
    	/**
    	 * 下拉状态
    	 */
    	public static final int STATUS_PULL_TO_REFRESH = 0;
    
    	/**
    	 * 释放立即刷新状态
    	 */
    	public static final int STATUS_RELEASE_TO_REFRESH = 1;
    
    	/**
    	 * 正在刷新状态
    	 */
    	public static final int STATUS_REFRESHING = 2;
    
    	/**
    	 * 刷新完成或未刷新状态
    	 */
    	public static final int STATUS_REFRESH_FINISHED = 3;
    
    	/**
    	 * 下拉头部回滚的速度
    	 */
    	public static final int SCROLL_SPEED = -20;
    
    	/**
    	 * 一分钟的毫秒值,用于判断上次的更新时间
    	 */
    	public static final long ONE_MINUTE = 60 * 1000;
    
    	/**
    	 * 一小时的毫秒值,用于判断上次的更新时间
    	 */
    	public static final long ONE_HOUR = 60 * ONE_MINUTE;
    
    	/**
    	 * 一天的毫秒值,用于判断上次的更新时间
    	 */
    	public static final long ONE_DAY = 24 * ONE_HOUR;
    
    	/**
    	 * 一月的毫秒值,用于判断上次的更新时间
    	 */
    	public static final long ONE_MONTH = 30 * ONE_DAY;
    
    	/**
    	 * 一年的毫秒值,用于判断上次的更新时间
    	 */
    	public static final long ONE_YEAR = 12 * ONE_MONTH;
    
    	/**
    	 * 上次更新时间的字符串常量,用于作为SharedPreferences的键值
    	 */
    	private static final String UPDATED_AT = "updated_at";
    
    	/**
    	 * 下拉刷新的回调接口
    	 */
    	private PullToRefreshListener mListener;
    
    	/**
    	 * 用于存储上次更新时间
    	 */
    	private SharedPreferences preferences;
    
    	/**
    	 * 下拉头的View
    	 */
    	private View header;
    
    	/**
    	 * 需要去下拉刷新的ListView
    	 */
    	private ListView listView;
    
    	/**
    	 * 刷新时显示的进度条
    	 */
    	private ProgressBar progressBar;
    
    	/**
    	 * 指示下拉和释放的箭头
    	 */
    	private ImageView arrow;
    
    	/**
    	 * 指示下拉和释放的文字描述
    	 */
    	private TextView description;
    
    	/**
    	 * 上次更新时间的文字描述
    	 */
    	private TextView updateAt;
    
    	/**
    	 * 下拉头的布局参数
    	 */
    	private MarginLayoutParams headerLayoutParams;
    
    	/**
    	 * 上次更新时间的毫秒值
    	 */
    	private long lastUpdateTime;
    
    	/**
    	 * 为了防止不同界面的下拉刷新在上次更新时间上互相有冲突,使用id来做区分
    	 */
    	private int mId = -1;
    
    	/**
    	 * 下拉头的高度
    	 */
    	private int hideHeaderHeight;
    
    	/**
    	 * 当前处理什么状态,可选值有STATUS_PULL_TO_REFRESH, STATUS_RELEASE_TO_REFRESH,
    	 * STATUS_REFRESHING 和 STATUS_REFRESH_FINISHED
    	 */
    	private int currentStatus = STATUS_REFRESH_FINISHED;;
    
    	/**
    	 * 记录上一次的状态是什么,避免进行重复操作
    	 */
    	private int lastStatus = currentStatus;
    
    	/**
    	 * 手指按下时的屏幕纵坐标
    	 */
    	private float yDown;
    
    	/**
    	 * 在被判定为滚动之前用户手指可以移动的最大值。
    	 */
    	private int touchSlop;
    
    	/**
    	 * 是否已加载过一次layout,这里onLayout中的初始化只需加载一次
    	 */
    	private boolean loadOnce;
    
    	/**
    	 * 当前是否可以下拉,只有ListView滚动到头的时候才允许下拉
    	 */
    	private boolean ableToPull;
    
    	/**
    	 * 下拉刷新控件的构造函数,会在运行时动态添加一个下拉头的布局。
    	 * 
    	 * @param context
    	 * @param attrs
    	 */
    	public RefreshableView(Context context, AttributeSet attrs) {
    		super(context, attrs);
    		preferences = PreferenceManager.getDefaultSharedPreferences(context);
    		header = LayoutInflater.from(context).inflate(R.layout.pull_to_refresh, null, true);
    		progressBar = (ProgressBar) header.findViewById(R.id.progress_bar);
    		arrow = (ImageView) header.findViewById(R.id.arrow);
    		description = (TextView) header.findViewById(R.id.description);
    		updateAt = (TextView) header.findViewById(R.id.updated_at);
    		touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    		refreshUpdatedAtValue();
    		setOrientation(VERTICAL);
    		addView(header, 0);
    	}
    
    	/**
    	 * 进行一些关键性的初始化操作,比如:将下拉头向上偏移进行隐藏,给ListView注册touch事件。
    	 */
    	@Override
    	protected void onLayout(boolean changed, int l, int t, int r, int b) {
    		super.onLayout(changed, l, t, r, b);
    		if (changed && !loadOnce) {
    			hideHeaderHeight = -header.getHeight();
    			headerLayoutParams = (MarginLayoutParams) header.getLayoutParams();
    			headerLayoutParams.topMargin = hideHeaderHeight;
    			listView = (ListView) getChildAt(1);
    			listView.setOnTouchListener(this);
    			loadOnce = true;
    		}
    	}
    
    	/**
    	 * 当ListView被触摸时调用,其中处理了各种下拉刷新的具体逻辑。
    	 */
    	@Override
    	public boolean onTouch(View v, MotionEvent event) {
    		setIsAbleToPull(event);
    		if (ableToPull) {
    			switch (event.getAction()) {
    			case MotionEvent.ACTION_DOWN:
    				yDown = event.getRawY();
    				break;
    			case MotionEvent.ACTION_MOVE:
    				float yMove = event.getRawY();
    				int distance = (int) (yMove - yDown);
    				// 如果手指是下滑状态,并且下拉头是完全隐藏的,就屏蔽下拉事件
    				if (distance <= 0 && headerLayoutParams.topMargin <= hideHeaderHeight) {
    					return false;
    				}
    				if (distance < touchSlop) {
    					return false;
    				}
    				if (currentStatus != STATUS_REFRESHING) {
    					if (headerLayoutParams.topMargin > 0) {
    						currentStatus = STATUS_RELEASE_TO_REFRESH;
    					} else {
    						currentStatus = STATUS_PULL_TO_REFRESH;
    					}
    					// 通过偏移下拉头的topMargin值,来实现下拉效果
    					headerLayoutParams.topMargin = (distance / 2) + hideHeaderHeight;
    					header.setLayoutParams(headerLayoutParams);
    				}
    				break;
    			case MotionEvent.ACTION_UP:
    			default:
    				if (currentStatus == STATUS_RELEASE_TO_REFRESH) {
    					// 松手时如果是释放立即刷新状态,就去调用正在刷新的任务
    					new RefreshingTask().execute();
    				} else if (currentStatus == STATUS_PULL_TO_REFRESH) {
    					// 松手时如果是下拉状态,就去调用隐藏下拉头的任务
    					new HideHeaderTask().execute();
    				}
    				break;
    			}
    			// 时刻记得更新下拉头中的信息
    			if (currentStatus == STATUS_PULL_TO_REFRESH
    					|| currentStatus == STATUS_RELEASE_TO_REFRESH) {
    				updateHeaderView();
    				// 当前正处于下拉或释放状态,要让ListView失去焦点,否则被点击的那一项会一直处于选中状态
    				listView.setPressed(false);
    				listView.setFocusable(false);
    				listView.setFocusableInTouchMode(false);
    				lastStatus = currentStatus;
    				// 当前正处于下拉或释放状态,通过返回true屏蔽掉ListView的滚动事件
    				return true;
    			}
    		}
    		return false;
    	}
    
    	/**
    	 * 给下拉刷新控件注册一个监听器。
    	 * 
    	 * @param listener
    	 *            监听器的实现。
    	 * @param id
    	 *            为了防止不同界面的下拉刷新在上次更新时间上互相有冲突, 请不同界面在注册下拉刷新监听器时一定要传入不同的id。
    	 */
    	public void setOnRefreshListener(PullToRefreshListener listener, int id) {
    		mListener = listener;
    		mId = id;
    	}
    
    	/**
    	 * 当所有的刷新逻辑完成后,记录调用一下,否则你的ListView将一直处于正在刷新状态。
    	 */
    	public void finishRefreshing() {
    		currentStatus = STATUS_REFRESH_FINISHED;
    		preferences.edit().putLong(UPDATED_AT + mId, System.currentTimeMillis()).commit();
    		new HideHeaderTask().execute();
    	}
    
    	/**
    	 * 根据当前ListView的滚动状态来设定 {@link #ableToPull}
    	 * 的值,每次都需要在onTouch中第一个执行,这样可以判断出当前应该是滚动ListView,还是应该进行下拉。
    	 * 
    	 * @param event
    	 */
    	private void setIsAbleToPull(MotionEvent event) {
    		View firstChild = listView.getChildAt(0);
    		if (firstChild != null) {
    			int firstVisiblePos = listView.getFirstVisiblePosition();
    			if (firstVisiblePos == 0 && firstChild.getTop() == 0) {
    				if (!ableToPull) {
    					yDown = event.getRawY();
    				}
    				// 如果首个元素的上边缘,距离父布局值为0,就说明ListView滚动到了最顶部,此时应该允许下拉刷新
    				ableToPull = true;
    			} else {
    				if (headerLayoutParams.topMargin != hideHeaderHeight) {
    					headerLayoutParams.topMargin = hideHeaderHeight;
    					header.setLayoutParams(headerLayoutParams);
    				}
    				ableToPull = false;
    			}
    		} else {
    			// 如果ListView中没有元素,也应该允许下拉刷新
    			ableToPull = true;
    		}
    	}
    
    	/**
    	 * 更新下拉头中的信息。
    	 */
    	private void updateHeaderView() {
    		if (lastStatus != currentStatus) {
    			if (currentStatus == STATUS_PULL_TO_REFRESH) {
    				description.setText(getResources().getString(R.string.pull_to_refresh));
    				arrow.setVisibility(View.VISIBLE);
    				progressBar.setVisibility(View.GONE);
    				rotateArrow();
    			} else if (currentStatus == STATUS_RELEASE_TO_REFRESH) {
    				description.setText(getResources().getString(R.string.release_to_refresh));
    				arrow.setVisibility(View.VISIBLE);
    				progressBar.setVisibility(View.GONE);
    				rotateArrow();
    			} else if (currentStatus == STATUS_REFRESHING) {
    				description.setText(getResources().getString(R.string.refreshing));
    				progressBar.setVisibility(View.VISIBLE);
    				arrow.clearAnimation();
    				arrow.setVisibility(View.GONE);
    			}
    			refreshUpdatedAtValue();
    		}
    	}
    
    	/**
    	 * 根据当前的状态来旋转箭头。
    	 */
    	private void rotateArrow() {
    		float pivotX = arrow.getWidth() / 2f;
    		float pivotY = arrow.getHeight() / 2f;
    		float fromDegrees = 0f;
    		float toDegrees = 0f;
    		if (currentStatus == STATUS_PULL_TO_REFRESH) {
    			fromDegrees = 180f;
    			toDegrees = 360f;
    		} else if (currentStatus == STATUS_RELEASE_TO_REFRESH) {
    			fromDegrees = 0f;
    			toDegrees = 180f;
    		}
    		RotateAnimation animation = new RotateAnimation(fromDegrees, toDegrees, pivotX, pivotY);
    		animation.setDuration(100);
    		animation.setFillAfter(true);
    		arrow.startAnimation(animation);
    	}
    
    	/**
    	 * 刷新下拉头中上次更新时间的文字描述。
    	 */
    	private void refreshUpdatedAtValue() {
    		lastUpdateTime = preferences.getLong(UPDATED_AT + mId, -1);
    		long currentTime = System.currentTimeMillis();
    		long timePassed = currentTime - lastUpdateTime;
    		long timeIntoFormat;
    		String updateAtValue;
    		if (lastUpdateTime == -1) {
    			updateAtValue = getResources().getString(R.string.not_updated_yet);
    		} else if (timePassed < 0) {
    			updateAtValue = getResources().getString(R.string.time_error);
    		} else if (timePassed < ONE_MINUTE) {
    			updateAtValue = getResources().getString(R.string.updated_just_now);
    		} else if (timePassed < ONE_HOUR) {
    			timeIntoFormat = timePassed / ONE_MINUTE;
    			String value = timeIntoFormat + "分钟";
    			updateAtValue = String.format(getResources().getString(R.string.updated_at), value);
    		} else if (timePassed < ONE_DAY) {
    			timeIntoFormat = timePassed / ONE_HOUR;
    			String value = timeIntoFormat + "小时";
    			updateAtValue = String.format(getResources().getString(R.string.updated_at), value);
    		} else if (timePassed < ONE_MONTH) {
    			timeIntoFormat = timePassed / ONE_DAY;
    			String value = timeIntoFormat + "天";
    			updateAtValue = String.format(getResources().getString(R.string.updated_at), value);
    		} else if (timePassed < ONE_YEAR) {
    			timeIntoFormat = timePassed / ONE_MONTH;
    			String value = timeIntoFormat + "个月";
    			updateAtValue = String.format(getResources().getString(R.string.updated_at), value);
    		} else {
    			timeIntoFormat = timePassed / ONE_YEAR;
    			String value = timeIntoFormat + "年";
    			updateAtValue = String.format(getResources().getString(R.string.updated_at), value);
    		}
    		updateAt.setText(updateAtValue);
    	}
    
    	/**
    	 * 正在刷新的任务,在此任务中会去回调注册进来的下拉刷新监听器。
    	 * 
    	 * @author guolin
    	 */
    	class RefreshingTask extends AsyncTask<Void, Integer, Void> {
    
    		@Override
    		protected Void doInBackground(Void... params) {
    			int topMargin = headerLayoutParams.topMargin;
    			while (true) {
    				topMargin = topMargin + SCROLL_SPEED;
    				if (topMargin <= 0) {
    					topMargin = 0;
    					break;
    				}
    				publishProgress(topMargin);
    				sleep(10);
    			}
    			currentStatus = STATUS_REFRESHING;
    			publishProgress(0);
    			if (mListener != null) {
    				mListener.onRefresh();
    			}
    			return null;
    		}
    
    		@Override
    		protected void onProgressUpdate(Integer... topMargin) {
    			updateHeaderView();
    			headerLayoutParams.topMargin = topMargin[0];
    			header.setLayoutParams(headerLayoutParams);
    		}
    
    	}
    
    	/**
    	 * 隐藏下拉头的任务,当未进行下拉刷新或下拉刷新完成后,此任务将会使下拉头重新隐藏。
    	 * 
    	 * @author guolin
    	 */
    	class HideHeaderTask extends AsyncTask<Void, Integer, Integer> {
    
    		@Override
    		protected Integer doInBackground(Void... params) {
    			int topMargin = headerLayoutParams.topMargin;
    			while (true) {
    				topMargin = topMargin + SCROLL_SPEED;
    				if (topMargin <= hideHeaderHeight) {
    					topMargin = hideHeaderHeight;
    					break;
    				}
    				publishProgress(topMargin);
    				sleep(10);
    			}
    			return topMargin;
    		}
    
    		@Override
    		protected void onProgressUpdate(Integer... topMargin) {
    			headerLayoutParams.topMargin = topMargin[0];
    			header.setLayoutParams(headerLayoutParams);
    		}
    
    		@Override
    		protected void onPostExecute(Integer topMargin) {
    			headerLayoutParams.topMargin = topMargin;
    			header.setLayoutParams(headerLayoutParams);
    			currentStatus = STATUS_REFRESH_FINISHED;
    		}
    	}
    
    	/**
    	 * 使当前线程睡眠指定的毫秒数。
    	 * 
    	 * @param time
    	 *            指定当前线程睡眠多久,以毫秒为单位
    	 */
    	private void sleep(int time) {
    		try {
    			Thread.sleep(time);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    
    	/**
    	 * 下拉刷新的监听器,使用下拉刷新的地方应该注册此监听器来获取刷新回调。
    	 * 
    	 * @author guolin
    	 */
    	public interface PullToRefreshListener {
    
    		/**
    		 * 刷新时会去回调此方法,在方法内编写具体的刷新逻辑。注意此方法是在子线程中调用的, 你可以不必另开线程来进行耗时操作。
    		 */
    		void onRefresh();
    
    	}
    
    }

    这个类是整个下拉刷新功能中最重要的一个类,注释已经写得比较详细了,我再简单解释一下。首先在RefreshableView的构造函数中动态添加了刚刚定义的pull_to_refresh这个布局作为下拉头,然后在onLayout方法中将下拉头向上偏移出了屏幕,再给ListView注册了touch事件。之后每当手指在ListView上滑动时,onTouch方法就会执行。在onTouch方法中的第一行就调用了setIsAbleToPull方法来判断ListView是否滚动到了最顶部,只有滚动到了最顶部才会执行后面的代码,否则就视为正常的ListView滚动,不做任何处理。当ListView滚动到了最顶部时,如果手指还在向下拖动,就会改变下拉头的偏移值,让下拉头显示出来,下拉的距离设定为手指移动距离的1/2,这样才会有拉力的感觉。如果下拉的距离足够大,在松手的时候就会执行刷新操作,如果距离不够大,就仅仅重新隐藏下拉头。


    具体的刷新操作会在RefreshingTask中进行,其中在doInBackground方法中回调了PullToRefreshListener接口的onRefresh方法,这也是大家在使用RefreshableView时必须要去实现的一个接口,因为具体刷新的逻辑就应该写在onRefresh方法中,后面会演示使用的方法。


    另外每次在下拉的时候都还会调用updateHeaderView方法来改变下拉头中的数据,比如箭头方向的旋转,下拉文字描述的改变等。更加深入的理解请大家仔细去阅读RefreshableView中的代码。


    现在我们已经把下拉刷新的所有功能都完成了,接下来就要看一看如何在项目中引入下拉刷新了。打开或新建activity_main.xml作为程序主界面的布局,加入如下代码:
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity" >
    
        <com.example.pulltorefreshtest.RefreshableView
            android:id="@+id/refreshable_view"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" >
    
            <ListView
                android:id="@+id/list_view"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" >
            </ListView>
        </com.example.pulltorefreshtest.RefreshableView>
    
    </RelativeLayout>
    可以看到,我们在自定义的RefreshableView中加入了一个ListView,这就意味着给这个ListView加入了下拉刷新的功能,就是这么简单!
    然后我们再来看一下程序的主Activity,打开或新建MainActivity,加入如下代码:
    public class MainActivity extends Activity {
    
    	RefreshableView refreshableView;
    	ListView listView;
    	ArrayAdapter<String> adapter;
    	String[] items = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L" };
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		requestWindowFeature(Window.FEATURE_NO_TITLE);
    		setContentView(R.layout.activity_main);
    		refreshableView = (RefreshableView) findViewById(R.id.refreshable_view);
    		listView = (ListView) findViewById(R.id.list_view);
    		adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items);
    		listView.setAdapter(adapter);
    		refreshableView.setOnRefreshListener(new PullToRefreshListener() {
    			@Override
    			public void onRefresh() {
    				try {
    					Thread.sleep(3000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				refreshableView.finishRefreshing();
    			}
    		}, 0);
    	}
    
    }

    可以看到,我们通过调用RefreshableView的setOnRefreshListener方法注册了一个监听器,当ListView正在刷新时就会回调监听器的onRefresh方法,刷新的具体逻辑就在这里处理。而且这个方法已经自动开启了线程,可以直接在onRefresh方法中进行耗时操作,比如向服务器请求最新数据等,在这里我就简单让线程睡眠3秒钟。另外在onRefresh方法的最后,一定要调用RefreshableView中的finishRefreshing方法,这个方法是用来通知RefreshableView刷新结束了,不然我们的ListView将一直处于正在刷新的状态。


    不知道大家有没有注意到,setOnRefreshListener这个方法其实是有两个参数的,我们刚刚也是传入了一个不起眼的0。那这第二个参数是用来做什么的呢?由于RefreshableView比较智能,它会自动帮我们记录上次刷新完成的时间,然后下拉的时候会在下拉头中显示距上次刷新已过了多久。这是一个非常好用的功能,让我们不用再自己手动去记录和计算时间了,但是却存在一个问题。如果当前我们的项目中有三个地方都使用到了下拉刷新的功能,现在在一处进行了刷新,其它两处的时间也都会跟着改变!因为刷新完成的时间是记录在配置文件中的,由于在一处刷新更改了配置文件,导致在其它两处读取到的配置文件时间已经是更改过的了。那解决方案是什么?就是每个用到下拉刷新的地方,给setOnRefreshListener方法的第二个参数中传入不同的id就行了。这样各处的上次刷新完成时间都是单独记录的,相互之间就不会再有影响。


    好了,全部的代码都在这里了,让我们来运行一下,看看效果吧。



    效果看起来还是非常不错的。我们最后再来总结一下,在项目中引入ListView下拉刷新功能只需三步:


    1. 在Activity的布局文件中加入自定义的RefreshableView,并让ListView包含在其中。

    2. 在Activity中调用RefreshableView的setOnRefreshListener方法注册回调接口。

    3. 在onRefresh方法的最后,记得调用RefreshableView的finishRefreshing方法,通知刷新结束。


    从此以后,在项目的任何地方,一分钟引入下拉刷新功能妥妥的。


    好了,今天的讲解到此结束,有疑问的朋友请在下面留言。


    源码下载,请点击这里


    关注我的技术公众号,每天都有优质技术文章推送。关注我的娱乐公众号,工作、学习累了的时候放松一下自己。

    微信扫一扫下方二维码即可关注:

            

    展开全文
  • mac chrome 强制刷新浏览器缓存

    万次阅读 2017-05-01 10:04:21
    普通刷新:command +r 强制刷新:command+shift+r

    普通刷新:command +r


    强制刷新:command+shift+r

    删除cookie等:command+shift+del 点击 清除数据
    注意勾选的选项(不要把保存的密码也删除)

    展开全文
  • zTree实现节点修改的实时刷新

    万次阅读 2016-02-24 17:09:34
    在实际应用中会遇到动态操作树各节点的需求,在增加树节点后如何实时动态刷新树就十分有必要了。 二、项目实践 比如要在test1234节点下新建子节点,首先要选中test1234节点,添加成功后,根据test1234结点的...

    一、应用场景

    在实际应用中会遇到动态操作树各节点的需求,在增加树节点后如何实时动态刷新树就十分有必要了。

    二、项目实践

     

    比如要在test1234节点下新建子节点,首先要选中test1234节点,添加成功后,根据test1234结点的TID去后台请求对应子节点数据,实现动态刷新。删除节点类似。

    三、代码实现

    1、初始化时必须设置配置

     

    <span style="font-size:14px;"> async:{
    			enable:true,
    			url:"../admin/scriptManager/loadNodeByID.htm",
    			autoParam:["id"],
    			dataType:"json",
    		},
    		view: {
    			selectedMulti: false
    		}
    	}</span>

     

     

    2、刷新方法

    2、刷新方法
    	/**
    	 * 刷新当前节点
    	 */
    	function refreshNode() {
    		/*根据 treeId 获取 zTree 对象*/
    		var zTree = $.fn.zTree.getZTreeObj("scriptTree"),
    		type = "refresh",
    		silent = false,
    		/*获取 zTree 当前被选中的节点数据集合*/
    		nodes = zTree.getSelectedNodes();
    		/*强行异步加载父节点的子节点。[setting.async.enable = true 时有效]*/
    		zTree.reAsyncChildNodes(nodes[0], type, silent);
    	}
    
    	/**
    	 * 刷新当前选择节点的父节点
    	 */
    	function refreshParentNode() {
    		var zTree = $.fn.zTree.getZTreeObj("scriptTree"),
    		type = "refresh",
    		silent = false,
    		nodes = zTree.getSelectedNodes();
    		/*根据 zTree 的唯一标识 tId 快速获取节点 JSON 数据对象*/
    		var parentNode = zTree.getNodeByTId(nodes[0].parentTId);
    		/*选中指定节点*/
    		zTree.selectNode(parentNode);
    		zTree.reAsyncChildNodes(parentNode, type, silent);
    	}
    

     

    3、涉及的方法详解

    1、$.fn.zTree.init(obj,zSetting,zNodes)zTree的初始化方法,创建zTree必须使用此方法

    参数说明
    obj JQuery Object用于展现zTree的DOM容器
    zSetting JSON zTree的配置数据,具体请参考 “setting 配置详解”中的各个属性详细说明
    zNodes Array(JSON)/JSON zTree的节点数据,具体请参考 “treeNode 节点数据详解”中的各个属性详细说明


    返回值
    zTree对象,提供操作zTree的各种方法,对于通过js操作zTree来说必须通过此对象
    如果不需要自行设定全局变量保存,可以利用
    2、zTreeObj.getSelectedNodes获取 zTree 当前被选中的节点数据集合
    返回值
    返回值 Array(JSON)当前被选中的节点数据集合


    方法实例:
    1. 获取当前被选中的节点数据集合
    var treeObj = $.fn.zTree.getZTreeObj("tree");
    var nodes = treeObj.getSelectedNodes();


    3、zTreeObj.getNodeByTId根据 zTree 的唯一标识 tId 快速获取节点 JSON 数据对象
    参数:tId String 节点在 zTree 内的唯一标识 tId
    返回值:返回值 JSON tId 对应的节点 JSON 数据对象如无结果,返回 null


    方法实例:
    1. 获取 tId = "tree_10" 的节点数据
    var treeObj = $.fn.zTree.getZTreeObj("tree");
    var node = treeObj.getNodeByTId("tree_10");


    4、zTreeObj.selectNode选中指定节点
    参数:treeNode JSON 需要被选中的节点数据
    addFlag Boolean
    addFlag = true 表示追加选中,会出现多点同时被选中的情况
    addFlag = false 表示单独选中,原先被选中的节点会被取消选中状态
    setting.view.selectedMulti = false 时,此参数无效,始终进行单独选中

    5、zTreeObj.reAsyncChildNodes强行异步加载父节点的子节点。[setting.async.enable = true 时有效]
    参数:parentNode JSON 指定需要异步加载的父节点 JSON 数据,
    reloadType String reloadType = "refresh" 表示清空后重新加载。reloadType != "refresh" 时,表示追加子节点处理
    isSilent Boolean 设定异步加载后是否自动展开父节点。isSilent = true 时,不展开父节点,其他值或缺省状态都自动展开。

    方法实例
    1. 重新异步加载当前选中的第一个节点


    var treeObj = $.fn.zTree.getZTreeObj("tree");
    var nodes = treeObj.getSelectedNodes();
    if (nodes.length>0) {
    treeObj.reAsyncChildNodes(nodes[0], "refresh");
    }

     

    4、部分后台代码

    /**
    * 查询工程对象
    * 
    * @return
    */
    @ResponseBody
    @RequestMapping("/loadNodeByID.htm")
    public List<ZTreeNode> loadNodeByID(Integer id) {
        List<ZTreeNode> nodes = cuScriptProjectService.loadNodesByID(id);
        // ZTreeNode zTreeNode = cuScriptProjectService.loadNodeByID(id);
        return nodes;
    }

     

    2、

    /**
     * 根据工程ID加载工程节点数据
    */
    @Override
    public List<ZTreeNode> loadNodesByID(Integer id) {
        /* 查询工程集合 */
        List<CUProject> allProjects = this.cuProjectDAO.findAllProjects();
        Map<Integer, List<CUProjectVO>> allPorjectList = this.buildProjectVOMap(allProjects);
    
    
        /* 查询脚本集合 */
        List<CUScript> allScripts = this.cuScriptDAO.findAllScripts();
        Map<Integer, List<CUScriptVO>> allScriptMap = this.buildScriptVOMap(allScripts);
    
    
        /* 构建ZTreeNode数据结构 */
        List<ZTreeNode> treeNodeList = new ArrayList<ZTreeNode>();
        loopBuildZTree(id, allPorjectList, allScriptMap, treeNodeList);
        return treeNodeList;
    }

     

    展开全文
  • vue 页面刷新 表格刷新 数据刷新

    千次阅读 2019-12-25 17:16:50
    每次跳转页面,有些需要刷新有些不需要刷新,如何做到呢,首先,vue-cli有一个默认的全局刷新v-loading:true,需要关闭它,然后在你的页面里面,把需要每次跳转回来刷新的数据放在actived(){}里面,就可以实现了。...
  • 1.简述 默认情况下ElasticSearch索引的...如果需要调整数据刷新方案,则有三种途径: 设置数据刷新间隔:refresh_interval。 调用数据刷新接口:_refresh。 设置数据刷新策略:RefreshPolicy。 本文只描述前两种途...
  • vue项目如何刷新当前页面

    万次阅读 多人点赞 2018-05-27 11:19:33
    想必大家在刨坑vue的时候也遇到过下面情形:比如在删除或者增加一条记录的时候希望当前页面可以重新刷新或者如下面这种:如果希望点击确定的时候,Dialog 对话框关闭的时候,当前...Dialog 对话框设置的数据可以在确定...
  • Spring Cloud 入门教程(三): 配置自动刷新 之前讲的配置管理, 只有在应用启动时会读取到GIT的内容, 之后只要应用不重启,GIT中文件的修改,应用无法感知, 即使重启Config Server也不行。 比如上一单元(Spring...
  • 昨天还好好的,今天打开项目,发现就一直在刷刷刷啊,自己搁那一直刷新。   然后不吐槽了,解决方案如下:  
  • 页面刷新和vue页面刷新

    万次阅读 2018-05-22 13:07:26
    history.go(0) location.reload() location=location location.assign(location) document.execCommand('Refresh') window.navigate(location) location.replace(location) ...这几个都可以刷新: ...
  • windows下host文件修改与刷新

    万次阅读 多人点赞 2019-07-31 13:46:58
    刷新方式: ctrl+r,输入CMD,回车 在命令行执行:ipconfig /flushdns #清除DNS缓存内容。 ps:ipconfig /displaydns //显示DNS缓存内容 2、linux环境 文件位置:/etc/hosts 刷新命令:sy...
  • js本地刷新和局部刷新

    万次阅读 2018-01-16 17:01:59
    最近做项目有个问题一直困扰了我很久了,今天灵机一动搞定了,就是jQuery的click事件我调用ajax后就不能二次点击了,本次做的是某个商品的启用和禁用,本来是用ajax调用后台程序,成功后局部刷新,之前搞了好久,...
  • 为什么要刷新? —— 长期不进行存储器 读/写 ,其存储单元内的原信息将慢慢消失。 一般是多长时间?——一般 2ms,对动态RAM的全部基本单元电路进行一次刷新。 注意:刷新只针对行地址 以下都以 128*128 矩阵的...
  • 浏览器刷新页面

    万次阅读 2020-05-19 00:05:04
    --每五秒刷新一次当前页面--> <meta http-equiv="refresh" content="5" /> <!--五秒后跳转到指定地址--> <meta http-equiv="refresh" content="5;url=https://www.baidu.com/" /> 方法二: ...
  • 试问采用哪种刷新方式比较合理?两次刷新的最大时间间隔是多少?对全部存储单元刷新一遍所需的实际刷新时间是多少? 先求存储单元是几行几列的(按芯片算),16K=214B=(27)2B=(128×128)B。得存储单元是128×128。 ...
  • uni-app下拉刷新加载刷新数据

    千次阅读 2019-10-12 18:02:54
    onPullDownRefresh监听该页面用户下拉刷新事件需要在 pages.json 里开启 enablePullDownRefresh "globalStyle": { } 当处理完数据刷新后,uni.stopPullDownRefresh 可以停止当前页面的下拉刷新 uni....
  • DRAM的三种刷新方式的刷新周期问题

    万次阅读 多人点赞 2019-05-04 11:08:43
    定时刷新的原因:由于存储单元的访问是随机的,有可能某些存储单元长期得不到访问,不进行存储器的读/写操作,其存储单元内的原信息将会慢慢消失,为此,必须采用定时刷新的方法,它规定在一定的时间内,对动态RAM的...
  • 使用vue进行开发时,如果要刷新当前路由,则调用router.go(0)方法即可。但是某些情况下,我们可能要求仅仅刷新某个组件,而不是路由,那么我们应该怎么做呢? 1.使用this.$forceUpdate()强制重新渲染 如果要在组件...
  • 存储器的集中刷新、分散刷新、异步刷新策略

    千次阅读 多人点赞 2019-03-31 12:02:04
    假设刷新1行的时间为0.5μs(刷新时间是等于存取周期的。因为刷新的过程与一次存取相同,只是没有在总线上输入输出。顺便说一下存取周期>真正用于存取的时间,因为存取周期内、存取操作结束后仍然需要一些时间来...
  • 第一种刷新:tableview的刷新 [self.tableView reloadData]; reloadData是刷新整个UITableView,有时候,我们可能需要局部刷新。比如:只刷新一个cell、只刷新一个section等等。这个时候在调用reloadData方法,虽然...
  • //刷新当前页面. parent.location.reload(); //刷新父亲对象(用于框架) opener.location.reload(); //刷新父窗口对象(用于单开窗口) top.location.reload(); //刷新最顶端对象(用于多开窗口) ...
  • vue 刷新当前页面或者跳转页面时候刷新

    万次阅读 多人点赞 2018-08-03 14:59:13
    2 采用window.reload() 或者router.go(0) hisory.go(0) 刷新的时候整个浏览器进行刷新加载, 但是页面闪烁, 体验不好 解决办法 方式一 先新建一个空白页面, 先跳到空白页面, 然后再从空白页面跳转回来 ...
  • 查看实时刷新刷新日志

    千次阅读 2017-07-05 23:38:47
    查看实时刷新刷新日志 tail -f /usr/local/apache/logs/error_log
  • MAC浏览器刷新/强制刷新

    万次阅读 2018-04-22 11:07:35
    MAC浏览器刷新 Command+r MAC浏览器强制刷新 Command+Shift+r
  • 之后所有的操作都是ajax刷新,但是点击进入某个模块页面时,之后按F5键...现在想按键F5只刷新ajax局部刷新的部分给刷新 现在想出来的办法,给每个页面拦截F5键之后在ajax刷新局部页面, 不知道有没有更好的办法???
  • Android下拉刷新ListView——RTPullListView

    千次下载 热门讨论 2012-11-18 13:22:59
    实现Android上类似新浪微博等App的下拉刷新功能
  • 第一次做网站,用的thinkPHP ,想请教下怎么让导航栏不刷新,而内容刷新?下面这样![图片说明](https://img-ask.csdn.net/upload/201805/26/1527344307_630367.png)
  • 一、前言 我们都知道,动态随机存储器DRAM的基本单元电路是由一个mos管和一个电容器组成。...于是我们引出了刷新的概念。大家如果对计算机组成原理感兴趣的话,可以去听一听中国大学MOOC的计算机组织...
  • 页面后退刷新、无刷新

    千次阅读 2017-09-19 15:11:12
    页面后退强制刷新
  • js 怎么检测页面被刷新 按F5刷新 这个刷新和在浏览器直接敲地址刷新 区别开来 还有区别页面的跳转 后退 操作 也就是说 只能按F5才能激活这个事件

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 221,470
精华内容 88,588
关键字:

刷新