开源中国的APP做得还是挺玄的,并且发布了源码,有兴趣的朋友可以到百度上搜索下载研究。
因项目需要,特地研究了开源中国的自定义下拉组件,对它也有了一定的了解。代码中我做了详细的注释,它只是个控件,
非要看效果的话需要建议下载它的APP进行研究。这个Demo实例下载地址见:
package com.example.myui.widget; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.LinearInterpolator; import android.view.animation.RotateAnimation; import android.widget.AbsListView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.AbsListView.OnScrollListener; import android.widget.ListView; import android.widget.ProgressBar; import com.example.myui.R; /** * RefreshListView.java * 工程:MyUI * 功能:下拉刷新/上拉加载 * * author date time * ───────────────────────────────────────────── * fengwh 2014-11-6 下午下午2:53:08 * * Copyright (c) 2014, KEYTOP All Rights Reserved. */ public class RefreshListView extends ListView implements OnScrollListener{ private final static String TAG = "PullToRefreshListView"; // 下拉刷新标志 private final static int PULL_To_REFRESH = 0; // 松开刷新标志 private final static int RELEASE_To_REFRESH = 1; // 正在刷新标志 private final static int REFRESHING = 2; // 刷新完成标志 private final static int DONE = 3; //状态标志 private int state; private RotateAnimation mAnimation; //旋转动画 private RotateAnimation reverseAnimation; //反旋转动画 //填充器 private LayoutInflater inflater; //加载头文件界面 private LinearLayout headView;
//箭头图标 private ImageView arrowImage; //arrow image //正在加载进度条 private ProgressBar mProgressBar; //提示语 private TextView tipsTextview; //更新时间 private TextView lastUpdatedTextView; //最大高度 private int headContentHeight; //保存高度 private int headContentOriginalTopPadding; //第一项Index private int firstItemIndex; //当前滑动条状态 private int currentScrollState; //开始高度 private int startY; //是否返回 private boolean isBack; //刷新监听器 public OnRefreshListener refreshListener; //是否记录过 private boolean isRecored; //初始化 public RefreshListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } //初始化 public RefreshListView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } //监听滑动状态 @Override public void onScrollStateChanged(AbsListView view, int scrollState) { currentScrollState = scrollState; } //显示的第一条记录索引号 @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { firstItemIndex=firstVisibleItem; } /** * 初始化控件 * @param context */ private void init(Context context){ //动画 mAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); mAnimation.setInterpolator(new LinearInterpolator()); //匀速变动 mAnimation.setFillAfter(true); mAnimation.setDuration(100); reverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); reverseAnimation.setInterpolator(new LinearInterpolator()); //匀速变动 reverseAnimation.setFillAfter(true); //顺时针转动画 reverseAnimation.setDuration(100); //----------------------Separator--------------- inflater = LayoutInflater.from(context); headView=(LinearLayout) inflater.inflate(R.layout.pull_to_refresh_head, null); arrowImage = (ImageView) headView.findViewById(R.id.head_arrowImageView); mProgressBar = (ProgressBar) headView.findViewById(R.id.head_progressBar); tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView); lastUpdatedTextView=(TextView) headView.findViewById(R.id.head_lastUpdatedTextView); headContentOriginalTopPadding = headView.getPaddingTop(); measureView(headView); //计算显示headView宽高 headContentHeight = headView.getMeasuredHeight(); headView.setPadding(headView.getPaddingLeft(), -1*headContentOriginalTopPadding, headView.getPaddingRight(), headView.getPaddingBottom()); headView.invalidate(); //无效化 addHeaderView(headView); this.setOnScrollListener(this); } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: //手势向下滑动 if (0==firstItemIndex&&!isRecored) { startY=(int) ev.getY(); //鼠标点击的Y值 isRecored=true; //是否已经记录过 System.out.println("记录首次点击的Y值="+startY); } break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: //手势抬起 if (state!=REFRESHING) { if (state==DONE) { // System.out.println("?-->Done"); }else if (state==PULL_To_REFRESH) {//向下可刷新-->已经完成 state=DONE; changeHeaderViewByState(); System.out.println("向下可刷新-->已经完成"); }else if (state==RELEASE_To_REFRESH) { //松开刷新-->刷新 state=REFRESHING; changeHeaderViewByState(); onRefresh(); System.out.println("松开刷新-->刷新"); } } isRecored=false; isBack = false; break; case MotionEvent.ACTION_MOVE: int tempY = (int) ev.getY(); //滑动的Y值 System.out.println("滑动的Y值为="+tempY); if (!isRecored&&0==firstItemIndex) { isRecored=true; startY=tempY; System.out.println("记录StartY=tempY="+startY); } //如果当前状态不是 “刷新” if (state!=REFRESHING&&isRecored) { if (state==RELEASE_To_REFRESH) { //松开刷新 if ((tempY-startY<headContentHeight+20)&&tempY>startY) { state = PULL_To_REFRESH; changeHeaderViewByState(); System.out.println("Move:松开刷新状态-->下拉刷新状态"); }else if (tempY-startY<=0) { //往上推到顶 state = DONE; changeHeaderViewByState(); System.out.println("松开刷新状态-->done状态"); }else { System.out.println("往下拉,或者还没有上推到屏幕顶部掩盖head"); } }else if (state==PULL_To_REFRESH) { //change state pull_ro_refresh-->release_to_refresh if ((tempY-startY>=headContentHeight+20) && currentScrollState == SCROLL_STATE_TOUCH_SCROLL) { state=RELEASE_To_REFRESH; changeHeaderViewByState(); System.out.println("由done或者下拉刷新状态转-->松开刷新"); }else if (tempY-startY<=0) { //推到顶 state=DONE; changeHeaderViewByState(); System.out.println("下拉刷新状态转-->Done刷新"); } }else if (state == DONE) { if (tempY-startY>0) { state=PULL_To_REFRESH; changeHeaderViewByState(); System.out.println("Move:由done状态-->下拉刷新状态"); } } //update headView state if (state==PULL_To_REFRESH) { int topPadding = (int)((-1 * headContentHeight + (tempY - startY))); headView.setPadding(headView.getPaddingLeft(), topPadding, headView.getPaddingRight(), headView.getPaddingBottom()); headView.invalidate(); System.out.println("下拉刷新-TopPadding:"+topPadding); } if (state==RELEASE_To_REFRESH) { int topPadding = (int)((tempY - startY - headContentHeight)); headView.setPadding(headView.getPaddingLeft(), topPadding, headView.getPaddingRight(), headView.getPaddingBottom()); headView.invalidate(); System.out.println("释放刷新-TopPadding:"+topPadding); } } break; default: break; } return super.onTouchEvent(ev); } //点击刷新 public void clickRefresh() { setSelection(0); state = REFRESHING; changeHeaderViewByState(); onRefresh(); } //个性化刷新:重新显示数据 private void onRefresh() { if (refreshListener != null) { refreshListener.onRefresh(); } } // 当状态改变时候,调用该方法,以更新界面 private void changeHeaderViewByState() { switch (state) { case RELEASE_To_REFRESH: arrowImage.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.GONE); tipsTextview.setVisibility(View.VISIBLE); lastUpdatedTextView.setVisibility(View.VISIBLE); arrowImage.clearAnimation(); arrowImage.startAnimation(mAnimation); tipsTextview.setText(R.string.pull_to_refresh_release_label); Log.v(TAG, "当前状态,松开刷新"); break; case PULL_To_REFRESH: mProgressBar.setVisibility(View.GONE); tipsTextview.setVisibility(View.VISIBLE); lastUpdatedTextView.setVisibility(View.VISIBLE); arrowImage.clearAnimation(); arrowImage.setVisibility(View.VISIBLE); if (isBack) { isBack = false; arrowImage.clearAnimation(); arrowImage.startAnimation(reverseAnimation); } tipsTextview.setText(R.string.pull_to_refresh_pull_label); Log.v(TAG, "当前状态,下拉刷新"); break; case REFRESHING: System.out.println("刷新REFRESHING-TopPad:"+headContentOriginalTopPadding); headView.setPadding(headView.getPaddingLeft(), headContentOriginalTopPadding, headView.getPaddingRight(), headView.getPaddingBottom()); headView.invalidate(); mProgressBar.setVisibility(View.VISIBLE); arrowImage.clearAnimation(); arrowImage.setVisibility(View.GONE); tipsTextview.setText(R.string.pull_to_refresh_refreshing_label); lastUpdatedTextView.setVisibility(View.GONE); Log.v(TAG, "当前状态,正在刷新..."); break; case DONE: System.out.println("完成DONE-TopPad:"+(-1 * headContentHeight)); headView.setPadding(headView.getPaddingLeft(), -1 * headContentHeight, headView.getPaddingRight(), headView.getPaddingBottom()); headView.invalidate(); mProgressBar.setVisibility(View.GONE); arrowImage.clearAnimation(); // 此处更换图标 arrowImage.setImageResource(R.drawable.ic_pulltorefresh_arrow); tipsTextview.setText(R.string.pull_to_refresh_pull_label); lastUpdatedTextView.setVisibility(View.VISIBLE); Log.v(TAG, "Done..."); break; } } /** * 回调函数 * @param refreshListener */ public void setOnRefreshListener(OnRefreshListener refreshListener) { this.refreshListener = refreshListener; } public interface OnRefreshListener { public void onRefresh(); } /** * 主要在handler中进行调用 松开刷新-->DONE * @param update */ public void onRefreshComplete(String update) { lastUpdatedTextView.setText(update); onRefreshComplete(); } public void onRefreshComplete() { state = DONE; changeHeaderViewByState(); } /** * 计算headView的宽高 * @param child */ private void measureView(View child){ ViewGroup.LayoutParams lp = child.getLayoutParams(); if (null==lp) { lp = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); } int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0+0, lp.width); int lpHeight = lp.height; int childHeightSpec; if (lpHeight>0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); }else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } }
headView的布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <RelativeLayout android:id="@+id/head_contentLayout" android:layout_width="fill_parent" android:layout_height="fill_parent" android:paddingTop="10dip" android:paddingBottom="15dip"> <FrameLayout android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:layout_marginLeft="30dip" android:layout_marginRight="20dip"> <ImageView android:id="@+id/head_arrowImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/ic_pulltorefresh_arrow" /> </FrameLayout> <FrameLayout android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:paddingTop="10dip" android:paddingBottom="15dip" android:layout_marginLeft="100dip" android:layout_marginRight="10dip"> <ProgressBar android:id="@+id/head_progressBar" style="@style/loading_small" android:visibility="gone"/> </FrameLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:gravity="center_horizontal" android:orientation="vertical"> <TextView android:id="@+id/head_tipsTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/pull_to_refresh_pull_label" android:textColor="@color/black"/> <TextView android:id="@+id/head_lastUpdatedTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/black" android:textSize="10sp" /> </LinearLayout> </RelativeLayout> </LinearLayout>
loading文件加载:需要相应的文件资源
<?xml version="1.0" encoding="utf-8"?> <animation-list android:oneshot="false" xmlns:android="http://schemas.android.com/apk/res/android" > <item android:duration="100" android:drawable="@drawable/loading_0" /> <item android:duration="100" android:drawable="@drawable/loading_1" /> <item android:duration="100" android:drawable="@drawable/loading_2" /> <item android:duration="100" android:drawable="@drawable/loading_3" /> <item android:duration="100" android:drawable="@drawable/loading_4" /> <item android:duration="100" android:drawable="@drawable/loading_5" /> <item android:duration="100" android:drawable="@drawable/loading_6" /> <item android:duration="100" android:drawable="@drawable/loading_7" /> </animation-list>