- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我想在 Android 应用程序中实现下拉刷新,但我不想使用互联网上可用的下拉刷新库,因为它对于我正在使用的 gridView 来说太慢了。所以想自己动手实现,你知道怎么做吗?或者我应该从 GridView 使用哪些方法?
最佳答案
PullRefreshContainerView.java
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
/**
* A container for a ListView that can be pulled to refresh.
* This will create a ListView and refresh header automatically, but you can
* customize them by using {@link #setList(ListView)} and {@link #setRefreshHeader(View, int)}
* <p>
* To use, put this where you would normally put your ListView. Since this does not extend
* ListView, you must use {@link #getList()} to modify the list or provide your own.
* <p>
* To get the actions of the list, use a {@link OnChangeStateListener} with {@link #setOnChangeStateListener(OnChangeStateListener)}.
* If you want to change how the refresh header looks, you should do it during these state changes.
*/
public class PullRefreshContainerView extends LinearLayout {
/**
* Interface for listening to when the refresh container changes state.
*/
public interface OnChangeStateListener {
/**
* Notifies a listener when the refresh view's state changes.
* @param container The container that contains the header
* @param state The state of the header. May be STATE_IDLE, STATE_READY,
* or STATE_REFRESHING.
*/
public void onChangeState(PullRefreshContainerView container, int state);
}
/**
* State of the refresh header when it is doing nothing or being pulled down slightly.
*/
public static final int STATE_IDLE = 0;
/**
* State of the refresh header when it has been pulled down but not enough to start refreshing, and
* has not yet been released.
*/
public static final int STATE_PULL = 1;
/**
* State of the refresh header when it has been pulled down enough to start refreshing, but
* has not yet been released.
*/
public static final int STATE_RELEASE = 2;
/**
* State of the refresh header when the list should be refreshing.
*/
public static final int STATE_LOADING = 3;
private LinearLayout mHeaderContainer;
private View mHeaderView;
private ListView mList;
private int mState;
private OnChangeStateListener mOnChangeStateListener;
private int REFRESH_VIEW_HEIGHT = 60;
/**
* Creates a new pull to refresh container.
*
* @param context the application context
*/
public PullRefreshContainerView(Context context) {
super(context);
init(context);
}
/**
* Creates a new pull to refresh container.
*
* @param context the application context
* @param attrs the XML attribute set
*/
public PullRefreshContainerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
/**
* Creates a new pull to refresh container.
*
* @param context the application context
* @param attrs the XML attribute set
* @param defStyle the style for this view
*/
public PullRefreshContainerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
init(context);
}
private void init(Context context) {
mState = STATE_IDLE; // Start out as idle.
float densityFactor = context.getResources().getDisplayMetrics().density;
REFRESH_VIEW_HEIGHT *= densityFactor;
// We don't want to see the fading edge on the container.
setVerticalFadingEdgeEnabled(false);
setVerticalScrollBarEnabled(false);
setOrientation(LinearLayout.VERTICAL);
// Set the default list and header.
mHeaderContainer = new LinearLayout(context);
addView(mHeaderContainer);
setRefreshViewHeight(1);
TextView headerView = new TextView(context);
headerView.setText("Default refresh header.");
setRefreshHeader(headerView);
ListView list = new ListView(context);
setList(list);
}
private boolean mScrollingList = true;
private float mInterceptY;
private int mLastMotionY;
@Override
public boolean dispatchTouchEvent (MotionEvent ev) {
float oldLastY = mInterceptY;
mInterceptY = ev.getY();
if (mState == STATE_LOADING) {
return super.dispatchTouchEvent(ev);
}
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastMotionY = (int) ev.getY();
mScrollingList = true;
return super.dispatchTouchEvent(ev);
case MotionEvent.ACTION_MOVE:
if (mList.getFirstVisiblePosition() == 0
&& (mList.getChildCount() == 0 || mList.getChildAt(0).getTop() == 0)) {
if ((mInterceptY - oldLastY > 5) || (mState == STATE_PULL) || (mState == STATE_RELEASE)) {
mScrollingList = false;
applyHeaderHeight(ev);
return true;
} else {
mScrollingList = true;
return super.dispatchTouchEvent(ev);
}
} else if (mScrollingList) {
return super.dispatchTouchEvent(ev);
} else {
return super.dispatchTouchEvent(ev);
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mState == STATE_RELEASE) {
refresh();
} else {
changeState(STATE_IDLE);
}
if (mScrollingList) {
return super.dispatchTouchEvent(ev);
} else {
return true;
}
default:
return super.dispatchTouchEvent(ev);
}
}
private void applyHeaderHeight(MotionEvent ev) {
final int historySize = ev.getHistorySize();
if (historySize > 0) {
for (int h = 0; h < historySize; h++) {
int historicalY = (int) (ev.getHistoricalY(h));
updateRefreshView(historicalY - mLastMotionY);
}
} else {
int historicalY = (int) ev.getY();
updateRefreshView(historicalY - mLastMotionY);
}
}
private void updateRefreshView(int height) {
if (height <= 0) {
return;
}
if ((REFRESH_VIEW_HEIGHT/4 <= mCurRefreshViewHeight) && (mCurRefreshViewHeight < REFRESH_VIEW_HEIGHT)) {
setRefreshViewHeight(height);
changeState(STATE_PULL);
} else if (mCurRefreshViewHeight >= REFRESH_VIEW_HEIGHT) {
if (height > REFRESH_VIEW_HEIGHT) {
height = (int) (REFRESH_VIEW_HEIGHT + (height - REFRESH_VIEW_HEIGHT) * REFRESH_VIEW_HEIGHT * 1.0f/height);
}
setRefreshViewHeight(height);
changeState(STATE_RELEASE);
} else {
setRefreshViewHeight(height);
}
}
private int mCurRefreshViewHeight = 60;
private void setRefreshViewHeight(int height) {
if (mCurRefreshViewHeight == height) {
return;
}
if (height == 1) {
mHeaderContainer.setLayoutParams(new LayoutParams(1, 1));
} else {
mHeaderContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, height));
}
mCurRefreshViewHeight = height;
}
private void changeState(int state) {
switch (state) {
case STATE_IDLE:
setRefreshViewHeight(1);
break;
case STATE_PULL:
break;
case STATE_RELEASE:
break;
case STATE_LOADING:
setRefreshViewHeight(REFRESH_VIEW_HEIGHT);
break;
}
mState = state;
notifyStateChanged();
}
/**
* Sets the list to be used in this pull to refresh container.
* @param list the list to use
*/
public void setList(ListView list) {
if (mList != null) {
removeView(mList);
}
mList = list;
if (mList.getParent() != null) {
ViewGroup parent = (ViewGroup) mList.getParent();
parent.removeView(mList);
}
mList.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
addView(mList);
}
/**
* @return the list inside this pull to refresh container
*/
public ListView getList() {
return mList;
}
/**
* Sets the view to use as the refresh header.
* <p />
* The header view is the view at the top that will show while the list
* is refreshing. Usually, this will be a simple rectangle that says "refreshing" and the like.
* <p />
*
* @param headerView the view to use as the whole header.
*/
public void setRefreshHeader(View header) {
if (mHeaderView != null) {
mHeaderContainer.removeView(mHeaderView);
}
if (header == null) {
throw new RuntimeException("Please supply a non-null header container.");
}
mHeaderContainer.addView(header, 0);
mHeaderView = header;
}
public void refresh() {
changeState(STATE_LOADING);
}
/**
* Notifies the pull-to-refresh view that the refreshing is complete.
* This will hide the refreshing header.
*/
public void completeRefresh() {
changeState(STATE_IDLE);
}
/**
* Notifies the listener that the state has changed.
*/
private void notifyStateChanged() {
if (mOnChangeStateListener != null) {
mOnChangeStateListener.onChangeState(this, mState);
}
}
/**
* @param listener the listener to be notified when the header state should change
*/
public void setOnChangeStateListener(OnChangeStateListener listener) {
mOnChangeStateListener = listener;
}
}
如何使用UsageDemoActivity.java
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import com.dmobile.pulltorefresh.PullRefreshContainerView.OnChangeStateListener;
import com.dmobile.pulltorefresh.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.ViewGroup.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class UsageDemoActivity extends Activity {
private PullRefreshContainerView mContainerView;
private TextView mRefreshHeader;
private ListView mList;
private ArrayList<String> mStrings = new ArrayList<String>();
private ArrayAdapter<String> mAdapter;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mRefreshHeader = new TextView(this);
mRefreshHeader.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
mRefreshHeader.setGravity(Gravity.CENTER);
mRefreshHeader.setText("Pull to refresh...");
mContainerView = (PullRefreshContainerView) findViewById(R.id.container);
mContainerView.setRefreshHeader(mRefreshHeader);
mContainerView.setOnChangeStateListener(new OnChangeStateListener() {
@Override
public void onChangeState(PullRefreshContainerView container, int state) {
switch (state) {
case PullRefreshContainerView.STATE_IDLE:
case PullRefreshContainerView.STATE_PULL:
mRefreshHeader.setText("Pull to refresh...");
break;
case PullRefreshContainerView.STATE_RELEASE:
mRefreshHeader.setText("Release to refresh...");
break;
case PullRefreshContainerView.STATE_LOADING:
mRefreshHeader.setText("Loading...");
final Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
UsageDemoActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
addStrings(1);
mContainerView.completeRefresh();
t.cancel();
}
});
}
}, 5000, 5000);
break;
}
}
});
mList = mContainerView.getList();
mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mStrings);
mList.setAdapter(mAdapter);
addStrings(3);
}
private void addStrings(int count) {
int curSize = mStrings.size();
for (int i = 0; i < count; ++i) {
mStrings.add("String " + (curSize + i));
}
mAdapter.notifyDataSetChanged();
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<com.dmobile.pulltorefresh.PullRefreshContainerView
android:id="@+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
更新以使用 GRIDVIEWPullRefreshContainerView.java
private void init(Context context) {
mState = STATE_IDLE; // Start out as idle.
float densityFactor = context.getResources().getDisplayMetrics().density;
REFRESH_VIEW_HEIGHT *= densityFactor;
// We don't want to see the fading edge on the container.
setVerticalFadingEdgeEnabled(false);
setVerticalScrollBarEnabled(false);
setOrientation(LinearLayout.VERTICAL);
// Set the default list and header.
mHeaderContainer = new LinearLayout(context);
addView(mHeaderContainer);
setRefreshViewHeight(1);
TextView headerView = new TextView(context);
headerView.setText("Default refresh header.");
setRefreshHeader(headerView);
GridView grid = new GridView(context);
setList(grid);
}
并在 setListMethod();
关于android - 在没有流行库的情况下在 Android 中拉动刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18609522/
我想知道是否有一个“标准”类(JDK、Guava、Apache *)可以帮助延迟初始化/计算模式? 我正在考虑这样的事情(现在让我们忽略同步): abstract class Lazy { T i
我要创建一个从 html 到某种格式的转换器。我正在考虑使用中间格式 XML(XSL-FO)。 我的问题:如果没有那么多应用程序渲染它,为什么 FO 格式很受欢迎? 最佳答案 我很清楚 CSS 和 X
我发现了 IDEF就在昨天,我立即想知道为什么它不比 UML 更流行。从documents来看,IDEF 至少与 UML 一样适用于软件建模,但与 UML 相比,它已经成熟和稳定了大约 30 年。 这
首先,对于版主来说,如果这不是发布此内容的正确位置,请不要生气:)。 我想知道是否有类似 TodoMVC 的东西适用于 Django、Rails、Symfony 等流行的 Web 框架。 如果没有这样
在我的应用程序中,我有一个 UIScrollView,其中包含 N 个可以向左或向右滑动的 ViewController 在每个 Controller 中,我希望能够推送新的 viewControll
我是一名优秀的程序员,十分优秀!