import com.reacnn.android.R;
import com.reacnn.android.utils.DateOperation;
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.Scroller;
import android.widget.TextView;
public class XScrollView extends LinearLayout {
enum Status {
NORMAL, DRAGGING, REFRESHING,
}
private Status status = Status.NORMAL;
private final static float MIN_MOVE_DISTANCE = 5.0f;// 最小移动距离,用于判断是否在下拉,设置为0则touch事件的判断会过于平凡。具体值可以根据自己来设定
private Scroller scroller;
private View mHeaderView;
private ImageView mArrowImageView;
private int mHeaderViewHeight = -60;
private ImageView bar;
private TextView downTextView;
private TextView mHeaderTimeView;
private IXScrollViewListener refreshListener;// 刷新监听器
private int lastY;
private Context mContext;
private Animation mRotateUpAnim;
private Animation mRotateDownAnim;
private final int ROTATE_ANIM_DURATION = 180;
@Override
public void onWindowFocusChanged(boolean hasFocus) {
try {
AnimationDrawable ad = (AnimationDrawable) bar.getBackground();
ad.start();
} catch (Exception e) {
}
super.onWindowFocusChanged(hasFocus);
}
public XScrollView(Context context) {
super(context);
mContext = context;
init();
}
public XScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
}
/**
* 初始化
*
* @MethodDescription init
* @exception
* @since 1.0.0
*/
private void init() {
mHeaderViewHeight = getPixelByDip(mContext, mHeaderViewHeight);
scroller = new Scroller(mContext);
mHeaderView = LayoutInflater.from(mContext).inflate(
R.layout.control_xlistview_header, null);
mArrowImageView = (ImageView) mHeaderView
.findViewById(R.id.xlistview_header_arrow);
bar = (ImageView) mHeaderView
.findViewById(R.id.xlistview_header_progressbar);
downTextView = (TextView) mHeaderView
.findViewById(R.id.xlistview_header_hint_textview);
mHeaderTimeView = (TextView) mHeaderView
.findViewById(R.id.xlistview_header_time);
LayoutParams lp = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, -mHeaderViewHeight);
lp.topMargin = mHeaderViewHeight;
lp.gravity = Gravity.CENTER;
addView(mHeaderView, lp);
mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
mRotateUpAnim.setFillAfter(true);
mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
mRotateDownAnim.setFillAfter(true);
}
private String mtime = "";
/**
* set last refresh time
*
* @param time
*/
public void setRefreshTime(String time) {
this.mtime = time;
mHeaderTimeView.setText(time);
}
public String GetRefreshTime() {
return this.mtime;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (status == Status.REFRESHING)
return false;
int y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int m = y - lastY;
doMovement(m);
this.lastY = y;
break;
case MotionEvent.ACTION_UP:
fling();
break;
}
return true;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
int action = e.getAction();
int y = (int) e.getRawY();
switch (action) {
case MotionEvent.ACTION_DOWN:
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int m = y - lastY;
this.lastY = y;
if (m > MIN_MOVE_DISTANCE && canScroll()) {
return true;
}
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return false;
}
/**
* up事件处理
*/
private void fling() {
LinearLayout.LayoutParams lp = (LayoutParams) mHeaderView
.getLayoutParams();
if (lp.topMargin > 0) {
status = Status.REFRESHING;
refresh();
} else {
status = Status.NORMAL;
returnInitState();
}
}
private void returnInitState() {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mHeaderView
.getLayoutParams();
int i = lp.topMargin;
scroller.startScroll(0, i, 0, mHeaderViewHeight);
invalidate();
}
/**
* 执行刷新
*
* @MethodDescription refresh
* @exception
* @since 1.0.0
*/
private void refresh() {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mHeaderView
.getLayoutParams();
int i = lp.topMargin;
mArrowImageView.clearAnimation();
mArrowImageView.setVisibility(View.INVISIBLE);
bar.setVisibility(View.VISIBLE);
downTextView.setText(R.string.xlistview_header_hint_loading);
scroller.startScroll(0, i, 0, 0 - i);
invalidate();
if (refreshListener != null) {
refreshListener.onRefresh();
}
}
/**
*
*/
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
int i = this.scroller.getCurrY();
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.mHeaderView
.getLayoutParams();
int k = Math.max(i, mHeaderViewHeight);
lp.topMargin = k;
this.mHeaderView.setLayoutParams(lp);
postInvalidate();
}
}
/**
* 下拉move事件处理
*
* @param moveY
*/
private void doMovement(int moveY) {
status = Status.DRAGGING;
LinearLayout.LayoutParams lp = (LayoutParams) mHeaderView
.getLayoutParams();
float f1 = lp.topMargin;
float f2 = moveY * 0.3F;
int i = (int) (f1 + f2);
lp.topMargin = i;
mHeaderView.setLayoutParams(lp);
mHeaderView.invalidate();
invalidate();
mHeaderTimeView.setVisibility(View.VISIBLE);
downTextView.setVisibility(View.VISIBLE);
mArrowImageView.setVisibility(View.VISIBLE);
bar.setVisibility(View.GONE);
if (lp.topMargin > 0) {
mArrowImageView.clearAnimation();
mArrowImageView.startAnimation(mRotateUpAnim);
downTextView.setText(R.string.xlistview_header_hint_ready);
} else {
mArrowImageView.startAnimation(mRotateDownAnim);
downTextView.setText(R.string.xlistview_header_hint_normal);
}
}
/**
* 设置监听
*
* @MethodDescription setRefreshListener
* @param listener
* @exception
* @since 1.0.0
*/
public void setIXScrollViewListener(IXScrollViewListener listener) {
this.refreshListener = listener;
}
/**
* 结束刷新事件
*/
public void finishRefresh() {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.mHeaderView
.getLayoutParams();
int i = lp.topMargin;
mArrowImageView.setVisibility(View.VISIBLE);
mHeaderTimeView.setVisibility(View.VISIBLE);
downTextView.setVisibility(VISIBLE);
bar.setVisibility(GONE);
setRefreshTime(DateOperation.GetSysCurrentTime());
scroller.startScroll(0, i, 0, mHeaderViewHeight);
invalidate();
status = Status.NORMAL;
}
/**
* 此方法兼容两种子布局的判断,listview,scrollview 主要作用是判断两个子View是否滚动到了最上面,若是,则表示此次touch
* move事件截取然后让layout来处理,来移动下拉视图,反之则不然
*
* @MethodDescription canScroll
* @return
* @exception
* @since 1.0.0
*/
private boolean canScroll() {
View childView;
if (getChildCount() > 1) {
childView = this.getChildAt(1);
if (childView instanceof ListView) {
int top = ((ListView) childView).getChildAt(0).getTop();
int pad = ((ListView) childView).getListPaddingTop();
if ((Math.abs(top - pad)) < 3
&& ((ListView) childView).getFirstVisiblePosition() == 0) {
return true;
} else {
return false;
}
} else if (childView instanceof ScrollView) {
if (((ScrollView) childView).getScrollY() == 0) {
return true;
} else {
return false;
}
}
}
return false;
}
public static int getPixelByDip(Context c, int pix) {
float f1 = c.getResources().getDisplayMetrics().density;
float f2 = pix;
return (int) (f1 * f2 + 0.5F);
}
/**
* 刷新监听接口
*
* @author Nono
*
*/
public interface IXScrollViewListener {
public void onRefresh();
}
}
调用:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.reacnn.android.view.listview.XScrollView
android:id="@+id/xScrollView1"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:orientation="vertical" >
<ScrollView
android:id="@+id/scrollView1"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
</ScrollView>
</com.reacnn.android.view.listview.XScrollView>
</LinearLayout>
import com.reacnn.android.R;
import com.reacnn.android.view.listview.XScrollView;
import com.reacnn.android.view.listview.XScrollView.IXScrollViewListener;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;
public class FrmAScrollViewTestActivity extends Activity implements
IXScrollViewListener {
private XScrollView mScrollView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_activity);
mScrollView = (XScrollView) findViewById(R.id.xScrollView1);
mScrollView.setIXScrollViewListener(this);
}
@SuppressLint("HandlerLeak")
Handler handler = new Handler() {
public void handleMessage(Message message) {
super.handleMessage(message);
mScrollView.finishRefresh();
Toast.makeText(FrmAScrollViewTestActivity.this, "刷新完成",
Toast.LENGTH_SHORT).show();
};
};
@Override
public void onRefresh() {
handler.sendEmptyMessageDelayed(1, 2000);
}
}
headview的相关内容见前面的下拉刷新的LIstView