編輯:關於Android編程
package siso.refreshablev;
import android.app.Activity;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import refreshableview.RefreshableView;
import refreshableview.refreshablehelper.RefreshableHelper;
public class MainActivity extends Activity implements View.OnClickListener {
private static final String TAG = MainActivity.class.getSimpleName();
private RefreshableView refreshableView;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.main_tv).setOnClickListener(this);
refreshableView = (RefreshableView) findViewById(R.id.main_refresh_view);
refreshableView.setRefreshableHelper(new RefreshableHelper() {
@Override
public View onInitRefreshHeaderView() {
return LayoutInflater.from(MainActivity.this).inflate(R.layout.refresh_head, null);
}
@Override
public boolean onInitRefreshHeight(int originRefreshHeight) {
refreshableView.setRefreshNormalHeight(refreshableView.getOriginRefreshHeight() / 3);
refreshableView.setRefreshingHeight(refreshableView.getOriginRefreshHeight());
refreshableView.setRefreshArrivedStateHeight(refreshableView.getOriginRefreshHeight());
return false;
}
@Override
public void onRefreshStateChanged(View refreshView, int refreshState) {
TextView tv = (TextView) refreshView.findViewById(R.id.refresh_head_tv);
switch (refreshState) {
case RefreshableView.STATE_REFRESH_NORMAL:
tv.setText("正常狀態");
break;
case RefreshableView.STATE_REFRESH_NOT_ARRIVED:
tv.setText("往下拉可以刷新");
break;
case RefreshableView.STATE_REFRESH_ARRIVED:
tv.setText("放手可以刷新");
break;
case RefreshableView.STATE_REFRESHING:
tv.setText("正在刷新");
new Thread(
new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000l);
runOnUiThread(new Runnable() {
@Override
public void run() {
refreshableView.onCompleteRefresh();
}
});
} catch (InterruptedException e) {
Log.e(TAG, "_", e);
}
}
}
).start();
break;
}
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.main_tv:
Log.d(TAG, "content clicked");
startActivity(new Intent(this, RefreshableListActivity.class));
break;
}
}
}
package siso.refreshablev;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import refreshableview.RefreshableListView;
import refreshableview.RefreshableView;
import refreshableview.refreshablehelper.RefreshableHelper;
public class RefreshableListActivity extends Activity {
private static final String TAG = RefreshableListActivity.class.getSimpleName();
RefreshableListView lv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.refreshable_list);
lv = (RefreshableListView) findViewById(R.id.refreshable_lv);
lv.setRefreshableHelper(new RefreshableHelper() {
@Override
public View onInitRefreshHeaderView() {
return LayoutInflater.from(RefreshableListActivity.this).inflate(R.layout.refresh_head, null);
}
@Override
public boolean onInitRefreshHeight(int originRefreshHeight) {
lv.setRefreshNormalHeight(lv.getOriginRefreshHeight() / 3);
lv.setRefreshingHeight(lv.getOriginRefreshHeight());
lv.setRefreshArrivedStateHeight(lv.getOriginRefreshHeight());
return false;
}
@Override
public void onRefreshStateChanged(View refreshView, int refreshState) {
TextView tv = (TextView) refreshView.findViewById(R.id.refresh_head_tv);
switch (refreshState) {
case RefreshableView.STATE_REFRESH_NORMAL:
tv.setText("正常狀態");
break;
case RefreshableView.STATE_REFRESH_NOT_ARRIVED:
tv.setText("往下拉可以刷新");
break;
case RefreshableView.STATE_REFRESH_ARRIVED:
tv.setText("放手可以刷新");
break;
case RefreshableView.STATE_REFRESHING:
tv.setText("正在刷新");
new Thread(
new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000l);
runOnUiThread(new Runnable() {
@Override
public void run() {
lv.onCompleteRefresh();
}
});
} catch (InterruptedException e) {
Log.e(TAG, "_", e);
}
}
}
).start();
break;
}
}
});
List data = new ArrayList();
for (int i = 0; i < 30; i++) {
data.add("item_" + i);
}
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, data);
lv.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
package refreshableview;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewParent;
import android.widget.ScrollView;
public class NestScrollView extends ScrollView {
private static final String TAG = NestScrollView.class.getSimpleName();
public NestScrollView(Context context) {
super(context);
}
public NestScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NestScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d(TAG, "___[dispatchTouchEvent]ev action: " + ev.getAction());
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
super.onInterceptTouchEvent(ev);
Log.d(TAG, "___[onInterceptTouchEvent]ev action: " + ev.getAction());
if (MotionEvent.ACTION_MOVE == ev.getAction()) {
return true;
}
return false;
}
float lastDownY;
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastDownY = event.getY();
parentRequestDisallowInterceptTouchEvent(true); // 保證事件可往下傳遞
Log.d(TAG, "___Down");
return true;
// break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "___move, this.getScrollY(): " + this.getScrollY());
boolean isTop = event.getY() - lastDownY > 0 && this.getScrollY() == 0;
if (isTop) { // 允許父控件攔截,即不允許父控件攔截設為false
parentRequestDisallowInterceptTouchEvent(false);
return false;
} else { // 不允許父控件攔截,即不允許父控件攔截設為true
parentRequestDisallowInterceptTouchEvent(true);
return true;
}
// break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "___up, this.getScrollY(): " + this.getScrollY());
parentRequestDisallowInterceptTouchEvent(true); // 保證事件可往下傳遞
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "___cancel");
break;
}
return false;
}
/**
* 是否允許父控件攔截事件
* @param disallowIntercept
*/
private void parentRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
ViewParent vp = getParent();
if (null == vp) {
return;
}
vp.requestDisallowInterceptTouchEvent(disallowIntercept);
}
}
package refreshableview;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.widget.ListAdapter;
import android.widget.ListView;
import refreshableview.refreshablehelper.RefreshableHelper;
public class RefreshableListView extends ListView {
private static final String TAG = RefreshableListView.class.getSimpleName();
public RefreshableListView(Context context) {
super(context);
init(context);
}
public RefreshableListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public RefreshableListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
/**
* 刷新狀態
*/
public static final int STATE_REFRESH_NORMAL = 0x21;
public static final int STATE_REFRESH_NOT_ARRIVED = 0x22;
public static final int STATE_REFRESH_ARRIVED = 0x23;
public static final int STATE_REFRESHING = 0x24;
private int refreshState;
// 刷新狀態監聽
private RefreshableHelper refreshableHelper;
/**
* 刷新的view
*/
private View refreshHeaderView;
/**
* 刷新的view的真實高度
*/
private int originRefreshHeight;
/**
* 有效下拉刷新需要達到的高度
*/
private int refreshArrivedStateHeight;
/**
* 刷新時顯示的高度
*/
private int refreshingHeight;
/**
* 正常未刷新高度
*/
private int refreshNormalHeight;
public void setRefreshableHelper(RefreshableHelper refreshableHelper) {
this.refreshableHelper = refreshableHelper;
}
private Context context;
private void init(Context context) {
this.context = context;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Log.d(TAG, "[onSizeChanged]w: " + w + ", h: " + h);
Log.d(TAG, "[onSizeChanged]oldw: " + oldw + ", oldh: " + oldh);
Log.d(TAG, "[onSizeChanged]child counts: " + this.getChildCount());
}
@Override
public void setAdapter(ListAdapter adapter) {
if (null == refreshHeaderView) {
addHeaderView();
}
super.setAdapter(adapter);
}
private void addHeaderView() {
if (null != refreshableHelper) {
refreshHeaderView = refreshableHelper.onInitRefreshHeaderView();
}
if (null == refreshHeaderView) {
Log.e(TAG, "refreshHeaderView is null!");
return;
}
this.addHeaderView(refreshHeaderView);
// 計算refreshHeadView尺寸
int width = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
refreshHeaderView.measure(width, expandSpec);
originRefreshHeight = refreshHeaderView.getMeasuredHeight();
boolean isUseDefault = true;
if (null != refreshableHelper) {
isUseDefault = refreshableHelper.onInitRefreshHeight(originRefreshHeight);
}
// 初始化各個高度
if (isUseDefault) {
refreshArrivedStateHeight = originRefreshHeight;
refreshingHeight = originRefreshHeight;
refreshNormalHeight = 0;
}
Log.d(TAG, "[onSizeChanged]refreshHeaderView origin height: " + originRefreshHeight);
changeViewHeight(refreshHeaderView, refreshNormalHeight);
// 初始化為正常狀態
setRefreshState(STATE_REFRESH_NORMAL);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
super.dispatchTouchEvent(ev);
// if(MotionEvent.ACTION_MOVE == ev.getAction()){
// return true;
// }
// return false;
return true;
}
private float lastDownY = Float.MAX_VALUE;
@Override
public boolean onTouchEvent(MotionEvent ev) {
// super.onTouchEvent(ev);
Log.d(TAG, "[onTouchEvent]ev action: " + ev.getAction());
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
super.onTouchEvent(ev);
lastDownY = ev.getY();
Log.d(TAG, "Down --> lastDownY: " + lastDownY);
break;
case MotionEvent.ACTION_MOVE:
float curY = ev.getY();
float deltaY = curY - lastDownY;
Log.d(TAG, "Move --> deltaY(curY - downY): " + deltaY);
int curHeight = refreshHeaderView.getMeasuredHeight();
int exceptHeight = curHeight + (int) (deltaY / 2);
// boolean isTop = this.getScrollY() == 0;
boolean isTop = 0 == this.getChildAt(0).getTop();
boolean isDropDown = curY - lastDownY > 0;
Log.d(TAG, "isTop: " + isTop + ", getTop(): " + this.getChildAt(0).getTop());
if (isTop) {
if (refreshState == STATE_REFRESH_NORMAL && !isDropDown) { // 正常狀態,手指往上(列表往下滾動)
super.onTouchEvent(ev);
} else {
// 如果當前沒有處在正在刷新狀態,則更新刷新狀態
if (STATE_REFRESHING != refreshState) {
if (curHeight >= refreshArrivedStateHeight) { // 達到可刷新狀態
setRefreshState(STATE_REFRESH_ARRIVED);
} else if (curHeight == refreshNormalHeight) { // 正常狀態
setRefreshState(STATE_REFRESH_NORMAL);
} else { // 未達到可刷新狀態
setRefreshState(STATE_REFRESH_NOT_ARRIVED);
}
changeViewHeight(refreshHeaderView, Math.max(refreshNormalHeight, exceptHeight));
} else {
super.onTouchEvent(ev);
}
}
} else {
super.onTouchEvent(ev);
}
lastDownY = curY;
break;
case MotionEvent.ACTION_UP:
super.onTouchEvent(ev);
lastDownY = Float.MAX_VALUE;
Log.d(TAG, "Up --> lastDownY: " + lastDownY);
// 如果是達到刷新狀態,則設置正在刷新狀態的高度
if (STATE_REFRESH_ARRIVED == refreshState) { // 達到了刷新的狀態
startHeightAnimation(refreshHeaderView, refreshHeaderView.getMeasuredHeight(), refreshingHeight);
setRefreshState(STATE_REFRESHING);
} else if (STATE_REFRESHING == refreshState) { // 正在刷新的狀態
startHeightAnimation(refreshHeaderView, refreshHeaderView.getMeasuredHeight(), refreshingHeight);
} else {
// 執行動畫後回歸正常狀態
startHeightAnimation(refreshHeaderView, refreshHeaderView.getMeasuredHeight(), refreshNormalHeight, normalAnimatorListener);
}
break;
}
return true;
}
/**
* 刷新完畢後調用此方法
*/
public void onCompleteRefresh() {
if (STATE_REFRESHING == refreshState) {
setRefreshState(STATE_REFRESH_NORMAL);
startHeightAnimation(refreshHeaderView, refreshHeaderView.getMeasuredHeight(), refreshNormalHeight);
}
}
/**
* 修改當前的刷新狀態
*
* @param expectRefreshState
*/
private void setRefreshState(int expectRefreshState) {
if (expectRefreshState != refreshState) {
refreshState = expectRefreshState;
if (null != refreshableHelper) {
refreshableHelper.onRefreshStateChanged(refreshHeaderView, refreshState);
}
}
}
/**
* 改變某控件的高度
*
* @param view
* @param height
*/
private void changeViewHeight(View view, int height) {
Log.d(TAG, "[changeViewHeight]change Height: " + height);
ViewGroup.LayoutParams lp = view.getLayoutParams();
if (null == lp) {
lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
}
lp.height = height;
view.setLayoutParams(lp);
}
/**
* 改變某控件的高度動畫
*
* @param view
* @param fromHeight
* @param toHeight
*/
private void startHeightAnimation(final View view, int fromHeight, int toHeight) {
startHeightAnimation(view, fromHeight, toHeight, null);
}
private void startHeightAnimation(final View view, int fromHeight, int toHeight, Animator.AnimatorListener animatorListener) {
if (toHeight == view.getMeasuredHeight()) {
return;
}
ValueAnimator heightAnimator = ValueAnimator.ofInt(fromHeight, toHeight);
heightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Integer value = (Integer) valueAnimator.getAnimatedValue();
if (null == value) return;
changeViewHeight(view, value);
}
});
if (null != animatorListener) {
heightAnimator.addListener(animatorListener);
}
heightAnimator.setInterpolator(new LinearInterpolator());
heightAnimator.setDuration(300/*ms*/);
heightAnimator.start();
}
AnimatorListenerAdapter normalAnimatorListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
setRefreshState(STATE_REFRESH_NORMAL); // 回歸正常狀態
}
};
public void setRefreshArrivedStateHeight(int refreshArrivedStateHeight) {
this.refreshArrivedStateHeight = refreshArrivedStateHeight;
}
public void setRefreshingHeight(int refreshingHeight) {
this.refreshingHeight = refreshingHeight;
}
public void setRefreshNormalHeight(int refreshNormalHeight) {
this.refreshNormalHeight = refreshNormalHeight;
}
public int getOriginRefreshHeight() {
return originRefreshHeight;
}
}
package refreshableview;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
import refreshableview.refreshablehelper.RefreshableHelper;
import siso.refreshablev.R;
public class RefreshableView extends LinearLayout {
private static final String TAG = RefreshableView.class.getSimpleName();
public RefreshableView(Context context) {
super(context);
init(context);
}
public RefreshableView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.refreshableView);
for (int i = 0, len = a.length(); i < len; i++) {
int attrIndex = a.getIndex(i);
switch (attrIndex) {
case R.styleable.refreshableView_interceptAllMoveEvents:
interceptAllMoveEvents = a.getBoolean(i, false);
break;
}
}
a.recycle();
init(context);
}
public RefreshableView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
/**
* 刷新狀態
*/
public static final int STATE_REFRESH_NORMAL = 0x21;
public static final int STATE_REFRESH_NOT_ARRIVED = 0x22;
public static final int STATE_REFRESH_ARRIVED = 0x23;
public static final int STATE_REFRESHING = 0x24;
private int refreshState;
// 刷新狀態監聽
private RefreshableHelper refreshableHelper;
public void setRefreshableHelper(RefreshableHelper refreshableHelper) {
this.refreshableHelper = refreshableHelper;
}
private Context context;
/**
* 刷新的view
*/
private View refreshHeaderView;
/**
* 刷新的view的真實高度
*/
private int originRefreshHeight;
/**
* 有效下拉刷新需要達到的高度
*/
private int refreshArrivedStateHeight;
/**
* 刷新時顯示的高度
*/
private int refreshingHeight;
/**
* 正常未刷新高度
*/
private int refreshNormalHeight;
/**
* 默認不允許攔截(即,往子view傳遞事件),該屬性只有在interceptAllMoveEvents為false的時候才有效
*/
private boolean disallowIntercept = true;
/**
* xml中可設置它的值為false,表示不把移動的事件傳遞給子控件
*/
private boolean interceptAllMoveEvents;
private void init(Context context) {
this.context = context;
this.setOrientation(VERTICAL);
// Log.d(TAG, "[init]originRefreshHeight: " + refreshHeaderView.getMeasuredHeight());
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (null != refreshableHelper) {
refreshHeaderView = refreshableHelper.onInitRefreshHeaderView();
}
// refreshHeaderView = LayoutInflater.from(context).inflate(R.layout.refresh_head, null);
if (null == refreshHeaderView) {
Log.e(TAG, "refreshHeaderView is null!");
return;
}
this.removeView(refreshHeaderView);
this.addView(refreshHeaderView, 0);
// 計算refreshHeadView尺寸
int width = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
refreshHeaderView.measure(width, expandSpec);
Log.d(TAG, "[onSizeChanged]w: " + w + ", h: " + h);
Log.d(TAG, "[onSizeChanged]oldw: " + oldw + ", oldh: " + oldh);
Log.d(TAG, "[onSizeChanged]child counts: " + this.getChildCount());
originRefreshHeight = refreshHeaderView.getMeasuredHeight();
boolean isUseDefault = true;
if (null != refreshableHelper) {
isUseDefault = refreshableHelper.onInitRefreshHeight(originRefreshHeight);
}
// 初始化各個高度
if (isUseDefault) {
refreshArrivedStateHeight = originRefreshHeight;
refreshingHeight = originRefreshHeight;
refreshNormalHeight = 0;
}
Log.d(TAG, "[onSizeChanged]refreshHeaderView origin height: " + originRefreshHeight);
changeViewHeight(refreshHeaderView, refreshNormalHeight);
// 初始化為正常狀態
setRefreshState(STATE_REFRESH_NORMAL);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d(TAG, "[dispatchTouchEvent]ev action: " + ev.getAction());
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d(TAG, "[onInterceptTouchEvent]ev action: " + ev.getAction());
if (!interceptAllMoveEvents) {
return !disallowIntercept;
}
// 如果設置了攔截所有move事件,即interceptAllMoveEvents為true
if (MotionEvent.ACTION_MOVE == ev.getAction()) {
return true;
}
return false;
}
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
if (this.disallowIntercept == disallowIntercept) {
return;
}
this.disallowIntercept = disallowIntercept;
super.requestDisallowInterceptTouchEvent(disallowIntercept);
}
private float downY = Float.MAX_VALUE;
@Override
public boolean onTouchEvent(MotionEvent event) {
// super.onTouchEvent(event);
Log.d(TAG, "[onTouchEvent]ev action: " + event.getAction());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = event.getY();
Log.d(TAG, "Down --> downY: " + downY);
requestDisallowInterceptTouchEvent(true); // 保證事件可往下傳遞
break;
case MotionEvent.ACTION_MOVE:
float curY = event.getY();
float deltaY = curY - downY;
// 是否是有效的往下拖動事件(則需要顯示加載header)
boolean isDropDownValidate = Float.MAX_VALUE != downY;
/**
* 修改攔截設置
* 如果是有效往下拖動事件,則事件需要在本ViewGroup中處理,所以需要攔截不往子控件傳遞,即不允許攔截設為false
* 如果不是有效往下拖動事件,則事件傳遞給子控件處理,所以不需要攔截,並往子控件傳遞,即不允許攔截設為true
*/
requestDisallowInterceptTouchEvent(!isDropDownValidate);
downY = curY;
Log.d(TAG, "Move --> deltaY(curY - downY): " + deltaY);
int curHeight = refreshHeaderView.getMeasuredHeight();
int exceptHeight = curHeight + (int) (deltaY / 2);
// 如果當前沒有處在正在刷新狀態,則更新刷新狀態
if (STATE_REFRESHING != refreshState) {
if (curHeight >= refreshArrivedStateHeight) { // 達到可刷新狀態
setRefreshState(STATE_REFRESH_ARRIVED);
} else { // 未達到可刷新狀態
setRefreshState(STATE_REFRESH_NOT_ARRIVED);
}
}
if (isDropDownValidate) {
changeViewHeight(refreshHeaderView, Math.max(refreshNormalHeight, exceptHeight));
} else { // 防止從子控件修改攔截後引發的downY為Float.MAX_VALUE的問題
changeViewHeight(refreshHeaderView, Math.max(curHeight, exceptHeight));
}
break;
case MotionEvent.ACTION_UP:
downY = Float.MAX_VALUE;
Log.d(TAG, "Up --> downY: " + downY);
requestDisallowInterceptTouchEvent(true); // 保證事件可往下傳遞
// 如果是達到刷新狀態,則設置正在刷新狀態的高度
if (STATE_REFRESH_ARRIVED == refreshState) { // 達到了刷新的狀態
startHeightAnimation(refreshHeaderView, refreshHeaderView.getMeasuredHeight(), refreshingHeight);
setRefreshState(STATE_REFRESHING);
} else if (STATE_REFRESHING == refreshState) { // 正在刷新的狀態
startHeightAnimation(refreshHeaderView, refreshHeaderView.getMeasuredHeight(), refreshingHeight);
} else {
// 執行動畫後回歸正常狀態
startHeightAnimation(refreshHeaderView, refreshHeaderView.getMeasuredHeight(), refreshNormalHeight, normalAnimatorListener);
}
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "cancel");
break;
}
return true;
}
/**
* 刷新完畢後調用此方法
*/
public void onCompleteRefresh() {
if (STATE_REFRESHING == refreshState) {
setRefreshState(STATE_REFRESH_NORMAL);
startHeightAnimation(refreshHeaderView, refreshHeaderView.getMeasuredHeight(), refreshNormalHeight);
}
}
/**
* 修改當前的刷新狀態
*
* @param expectRefreshState
*/
private void setRefreshState(int expectRefreshState) {
if (expectRefreshState != refreshState) {
refreshState = expectRefreshState;
if (null != refreshableHelper) {
refreshableHelper.onRefreshStateChanged(refreshHeaderView, refreshState);
}
}
}
/**
* 改變某控件的高度
*
* @param view
* @param height
*/
private void changeViewHeight(View view, int height) {
Log.d(TAG, "[changeViewHeight]change Height: " + height);
ViewGroup.LayoutParams lp = view.getLayoutParams();
lp.height = height;
view.setLayoutParams(lp);
}
/**
* 改變某控件的高度動畫
*
* @param view
* @param fromHeight
* @param toHeight
*/
private void startHeightAnimation(final View view, int fromHeight, int toHeight) {
startHeightAnimation(view, fromHeight, toHeight, null);
}
private void startHeightAnimation(final View view, int fromHeight, int toHeight, Animator.AnimatorListener animatorListener) {
if (toHeight == view.getMeasuredHeight()) {
return;
}
ValueAnimator heightAnimator = ValueAnimator.ofInt(fromHeight, toHeight);
heightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Integer value = (Integer) valueAnimator.getAnimatedValue();
if (null == value) return;
changeViewHeight(view, value);
}
});
if (null != animatorListener) {
heightAnimator.addListener(animatorListener);
}
heightAnimator.setInterpolator(new LinearInterpolator());
heightAnimator.setDuration(300/*ms*/);
heightAnimator.start();
}
AnimatorListenerAdapter normalAnimatorListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
setRefreshState(STATE_REFRESH_NORMAL); // 回歸正常狀態
}
};
public void setRefreshArrivedStateHeight(int refreshArrivedStateHeight) {
this.refreshArrivedStateHeight = refreshArrivedStateHeight;
}
public void setRefreshingHeight(int refreshingHeight) {
this.refreshingHeight = refreshingHeight;
}
public void setRefreshNormalHeight(int refreshNormalHeight) {
this.refreshNormalHeight = refreshNormalHeight;
}
public int getOriginRefreshHeight() {
return originRefreshHeight;
}
}
package refreshableview.refreshablehelper;
import android.view.View;
public interface RefreshableHelper {
/**
* 初始化刷新View
*
* @return
*/
View onInitRefreshHeaderView();
/**
* 初始化各個尺寸高度
*
* @param originRefreshHeight
* @return
*/
boolean onInitRefreshHeight(int originRefreshHeight);
/**
* 刷新狀態改變
*
* @param refreshView
* @param refreshState
*/
void onRefreshStateChanged(View refreshView, int refreshState);
}



Android M新控件之AppBarLayout,NavigationView,CoordinatorLayout,CollapsingToolbarLayout的使用
compile 'com.android.support:design:22.2.0'AppBarLayout效果圖是這樣的AppBarLay
Android ndk開發swig編譯jni接口
相信越來越多Android程序員需要用到Android ndk開發swig編譯jni接口,因為這設計到底層編程,如果開發的項目是有硬件產品的話,那更要熟悉這方面的編程。我
Android照片牆應用實現 再多的圖片也不怕崩潰
照片牆這種功能現在應該算是挺常見了,在很多應用中你都可以經常看到照片牆的身影。它的設計思路其實也非常簡單,用一個GridView控件當作“牆”,然後隨著GridView的
深入淺出學習Android ListView基礎
ListView 簡介ListView 是安卓裡常用的控件, 本文介紹一下常用用法,以及優化等方法1、改寫activity_main.xml<LinearLayou