package com.baoy.demo.demoscrollrefreshlist.activity; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import com.baoy.demo.demoscrollrefreshlist.R; import com.baoy.demo.demoscrollrefreshlist.adapter.ProductAdapter; import com.baoy.demo.demoscrollrefreshlist.entity.Product; import com.baoy.demo.demoscrollrefreshlist.util.Config; import com.baoy.demo.demoscrollrefreshlist.view.ScrollRefreshListView; import com.baoy.demo.demoscrollrefreshlist.view.ScrollRefreshListView.onRefreshListener; public class ProductListActivity extends Activity implements OnClickListener, OnItemClickListener, onRefreshListener{ private ArrayList<Product> mDataList; private ProductAdapter mAdapter; private ScrollRefreshListView mListView; static int j = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Config.setContext(ProductListActivity.this); setContentView(R.layout.product_list); mDataList = new ArrayList<Product>(); mListView = (ScrollRefreshListView) this.findViewById(R.id.listView_product); mAdapter = new ProductAdapter(this, mDataList); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener( this ); mListView.setOnRefreshListener( this ); j =0; doHandle(0); // mListView.refreshSelf(); } private void doHandle(int a) { switch (a) { case 0: { mListView.refreshSelf(); for (int i = 0; i < 10; i++) { j += i; mDataList.add(new Product(null,"商品"+j,"商品内容"+j,new SimpleDateFormat("yyyy-mm-dd HH:MM:ss").format(new Date()),null)); } updateUIThread(0); } break; case 1: { j++; mDataList.add(new Product(null,"商品"+j,"商品内容"+j,new SimpleDateFormat("yyyy-mm-dd HH:MM:ss").format(new Date()),null)); updateUIThread(0); } break; case 2: { updateUIThread(1); } break; default: break; } } public void updateUIThread( final int type ) { new Thread( new Runnable() { @Override public void run() { mHandler.sendEmptyMessage( type ); } } ).start(); } Handler mHandler = new Handler(){ public void handleMessage( Message msg ) { switch (msg.what) { case 0: if (mDataList.size() == 0) { refreshEmptyView(); }else{ mListView.onRefreshComplete(); mListView.setLoadMoreComplete(); mAdapter.setDataList(mDataList); refreshEmptyView(); } break; case 1: mListView .removeListFooterView(ScrollRefreshListView.FOOTER_VIEW_NONE); mListView .removeListFooterView(ScrollRefreshListView.FOOTER_VIEW_MORE); break; default: break; } } }; @Override public void onRefresh() { doHandle(1); } @Override public void onLoadMore() { doHandle(2); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { } @Override public void onClick(View v) { } private void refreshEmptyView() { if (mAdapter.getCount() == 0) { mListView .setListFooterView(ScrollRefreshListView.FOOTER_VIEW_EMPTY); } else { mListView .removeListFooterView(ScrollRefreshListView.FOOTER_VIEW_NONE); mListView .setListFooterView(ScrollRefreshListView.FOOTER_VIEW_MORE); } } }
package com.baoy.demo.demoscrollrefreshlist.adapter; import java.util.ArrayList; import android.content.Context; import android.os.Handler; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.widget.BaseAdapter; /** * List view base adapter class Adapters that subclasses this base class will be * used in various kinds of list views including system default list view * control and the custom unrolled list view * * @author Neusoft.E3 * */ public abstract class ListBaseAdapter extends BaseAdapter { protected LayoutInflater mLayoutInflater; // layout inflater protected int mResource; // item layout resource protected ArrayList<?> mData; // list data protected Context mContext; // parent protected OnClickListener mClickListener; // item click listener, not used // in every case /** * Constructor * * @param aContext * parent * @param bf * @param aData * list data * @param aResource * item layout resource */ public ListBaseAdapter(Context aContext, ArrayList<?> aData) { mContext = aContext.getApplicationContext(); mData = aData; mLayoutInflater = (LayoutInflater) aContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public ListBaseAdapter(Context aContext, ArrayList<?> aData, Handler aHandler) { mContext = aContext; mData = aData; mLayoutInflater = (LayoutInflater) aContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getCount() { return mData.size(); } @Override public Object getItem(int position) { return mData.get(position); } @Override public long getItemId(int position) { return position; } @Override public abstract View getView(int position, View convertView, ViewGroup parent); /** * Set item click listener * * @param aListener */ public void setItemOnClickListener(OnClickListener aListener) { mClickListener = aListener; } public boolean cleanDatas() { if (mData != null) { mData.clear(); return true; } return false; } }
package com.baoy.demo.demoscrollrefreshlist.adapter; import java.util.ArrayList; import java.util.List; import com.baoy.demo.demoscrollrefreshlist.R; import com.baoy.demo.demoscrollrefreshlist.entity.Product; import android.content.Context; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; public class ProductAdapter extends ListBaseAdapter implements OnClickListener { private Context mContext; private LayoutInflater mInflater; private List<Product> mDataList; private static class ViewHolder { public ImageView productPhoto; public TextView productName; public TextView productContent; public TextView productUpdateTime; public ImageView productBuy; public ViewHolder(View baseView) { this.productPhoto = (ImageView) baseView.findViewById(R.id.iv_product_photo); this.productName = (TextView) baseView.findViewById(R.id.tv_product_name); this.productContent = (TextView) baseView.findViewById(R.id.tv_product_content); this.productUpdateTime = (TextView) baseView.findViewById(R.id.tv_product_time); this.productBuy = (ImageView) baseView.findViewById(R.id.iv_product_buy); } } public ProductAdapter(Context aContext, ArrayList<Product> aData) { super(aContext, aData); this.mContext = aContext; this.mInflater = LayoutInflater.from(aContext); } public void setDataList(List<Product> dataList) { mDataList = dataList; notifyDataSetChanged(); } public void addDataList(List<Product> dataList) { if (mDataList == null ) { mDataList = new ArrayList<Product>(); } mDataList.addAll(dataList); notifyDataSetChanged(); } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (convertView == null) { convertView = mInflater.inflate(R.layout.product_list_item, null); viewHolder = new ViewHolder(convertView); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } Product item = getItem(position); if( TextUtils.isEmpty(item.getProductUrl())){ viewHolder.productPhoto.setImageResource(R.drawable.ic_launcher); }else{ // ImageBank.getInstance().setImage(); viewHolder.productPhoto.setImageResource(R.drawable.ic_launcher); } viewHolder.productName.setText( item.getProductName()); viewHolder.productContent.setText(item.getProductContent()); viewHolder.productUpdateTime.setText(item.getProductUpdateTime()); if( TextUtils.isEmpty(item.getProductBuy())){ viewHolder.productBuy.setImageResource(R.drawable.ic_launcher); }else{ viewHolder.productBuy.setImageResource(R.drawable.ic_launcher); } return convertView; } @Override public void onClick(View v) { } @Override public int getCount() { if (mDataList == null) { return 0; } return mDataList.size(); } @Override public Product getItem(int position) { if (mDataList != null && position >= 0 && position < mDataList.size()) { return mDataList.get(position); } return null; } }
product_list_item.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" > <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="11dp" android:paddingLeft="11dp" android:paddingRight="11dp" android:paddingTop="11dp" > <ImageView android:id="@+id/iv_product_photo" android:layout_width="37dp" android:layout_height="37dp" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_marginTop="7dp" android:scaleType="centerCrop" android:src="@drawable/ic_launcher" /> <TextView android:id="@+id/tv_product_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="6dp" android:layout_marginLeft="7dp" android:layout_marginTop="4dp" android:layout_toRightOf="@+id/iv_product_photo" android:singleLine="true" android:text="商品名称" android:textColor="@color/black" android:textSize="13sp" /> <TextView android:id="@+id/tv_product_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/tv_product_name" android:layout_below="@+id/tv_product_name" android:layout_marginBottom="6dp" android:layout_toLeftOf="@+id/iv_product_buy" android:singleLine="true" android:text="商品详细内容商品详细内容商品详细内容商品详细内容商品详细内容商品详细内容商品详细内容" android:textColor="@color/black" android:textSize="13sp" /> <TextView android:id="@+id/tv_product_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/tv_product_name" android:layout_below="@+id/tv_product_content" android:textColor="@color/black" android:text="商品更新时间" android:textSize="11sp" /> <ImageView android:id="@+id/iv_product_buy" android:layout_width="55dp" android:layout_height="55dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="11dp" android:src="@drawable/ic_launcher"/> </RelativeLayout> <View android:layout_width="match_parent" android:layout_height="1px" android:layout_alignParentBottom="true" android:background="@color/black" /> </RelativeLayout>
product_list.xml
<?xml version="1.0" encoding="utf-8"?> <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" > <com.baoy.demo.demoscrollrefreshlist.view.ScrollRefreshListView android:id="@+id/listView_product" style="@style/listView_normal_style" android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="@color/transparent" android:dividerHeight="0dp" /> </RelativeLayout>
scroll_refresh_head.xml
<?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="wrap_content" android:background="@color/transparent" > <!-- 内容 --> <RelativeLayout android:id="@+id/head_contentLayout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="8dip" android:paddingLeft="30dp" > <!-- 箭头图像、进度条 --> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" > <!-- 箭头 --> <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" /> <!-- 进度条 --> <ProgressBar android:id="@+id/head_progressBar" style="?android:attr/progressBarStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:visibility="gone" /> </FrameLayout> <!-- 提示、最近更新 --> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="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/scroll_refresh_text" android:textSize="15dp" /> <!-- 最近更新 --> <TextView android:id="@+id/head_lastUpdatedTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/scroll_refresh_last_text" android:textSize="12dp" /> </LinearLayout> </RelativeLayout> </LinearLayout>
listfooter.xml
<?xml version="1.0" encoding="utf-8"?> <com.baoy.demo.demoscrollrefreshlist.view.AppendButton xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/appender" android:layout_width="fill_parent" android:layout_height="wrap_content"> </com.baoy.demo.demoscrollrefreshlist.view.AppendButton>
empty_content.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/txtEmptyText" android:layout_width="180dip" android:layout_height="150dip" android:layout_centerHorizontal="true" android:gravity="center_horizontal" android:text="@string/empty_text" android:textSize="14sp" android:linksClickable="true" android:paddingTop="50dip" android:textColor="@color/color_btn_bottom" android:layout_marginTop="50dip"/> </RelativeLayout>
appendbutton.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rlAppend" android:layout_width="fill_parent" android:layout_height="wrap_content" > <LinearLayout android:layout_width="fill_parent" android:layout_height="1dip" android:layout_alignParentTop="true" /> <Button android:id="@+id/btnAppend" android:layout_width="fill_parent" android:layout_height="60dip" android:layout_centerHorizontal="true" android:background="@null" android:text="@string/append_more" android:textSize="15dip" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" > <ProgressBar android:id="@+id/pbAppend" android:layout_width="15dip" android:layout_height="15dip" android:layout_marginLeft="210dip"/> </LinearLayout> </RelativeLayout>
package com.baoy.demo.demoscrollrefreshlist.util; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Locale; import android.text.TextUtils; /** * * @author Neusoft * */ public class TimeUtils { private static final String JUST_NOW = "刚刚"; private static final String MINUTE_AGO = "分钟前"; private static final String HOUR_AGO = "小时前"; private static final String TIME_TRANSFER_ERROR = "时间传输有误"; private static final String FORMAT_ERROR = ""; private static final String FORMAT_TODAY_TEXT = "今天"; private static final String FORMAT_YESTERDAY_TEXT = "昨天"; private static final String FORMAT_BEFORE_TEXT = "前天"; /** * 获取转换时间 * * @param updateTime * @return */ public static String getUpdateTime( long updateTime ) { String result = ""; try { long currentTimeSec = System.currentTimeMillis() / 1000; // long calTime = Long.parseLong(updateTime); long calTime = updateTime; long timeDif = currentTimeSec - calTime; if ( timeDif < 60 ) { result = JUST_NOW; } else if ( timeDif < 60 * 60 ) { result = ( timeDif / 60 ) + MINUTE_AGO; } else if ( timeDif < 60 * 60 * 24 ) { result = timeDif / 3600 + HOUR_AGO; } else { String strfullres = getDetailDate( String.valueOf( calTime ) ); result = strfullres.substring( 5, strfullres.length() - 3 ); } } catch ( Exception e ) { result = FORMAT_ERROR; } return result; } public static String getUpdateTime( String updateTime ) { String result = ""; try { long currentTimeSec = System.currentTimeMillis() / 1000; long calTime = Long.parseLong( updateTime ); // long calTime = updateTime; long timeDif = currentTimeSec - calTime; if ( timeDif < 60 ) { result = JUST_NOW; } else if ( timeDif < 60 * 60 ) { result = ( timeDif / 60 ) + MINUTE_AGO; } else if ( timeDif < 60 * 60 * 24 ) { result = timeDif / 3600 + HOUR_AGO; } else { String strfullres = getDetailDate( String.valueOf( calTime ) ); result = strfullres.substring( 5, strfullres.length() - 3 ); } } catch ( Exception e ) { result = FORMAT_ERROR; } return result; // return "09:45"; } /** * 获取转换时间 * * @param updateTime * @return */ public static String getUpdateTimeWithYear( String updateTime ) { String result = ""; try { long currentTimeSec = System.currentTimeMillis() / 1000; long calTime = Long.parseLong( updateTime ); long timeDif = currentTimeSec - calTime; if ( timeDif < 60 ) { result = JUST_NOW; } else if ( timeDif < 60 * 60 ) { result = ( timeDif / 60 ) + MINUTE_AGO; } else if ( timeDif < 60 * 60 * 24 ) { result = timeDif / 3600 + HOUR_AGO; } else { String strfullres = getDetailDate( String.valueOf( calTime ) ); result = strfullres.substring( 0, strfullres.length() - 3 ); } } catch ( Exception e ) { result = FORMAT_ERROR; } return result; } /** * 格式转化:yy-MM-dd * * @param timeSec * @return */ public static String getDate( Long timeSec ) { StringBuilder sb = new StringBuilder(); if ( timeSec == -1 ) { return ""; } Long time = timeSec * 1000; Calendar cal = Calendar.getInstance(); cal.setTimeInMillis( time ); sb.append( cal.get( Calendar.YEAR ) ).append( "-" ); sb.append( cal.get( Calendar.MONTH ) + 1 ).append( "-" ); sb.append( cal.get( Calendar.DATE ) ); return sb.toString(); } /** * 格式转化:yy-MM-dd * * @param timeSec * @return */ public static String getDate( String timeSec ) { StringBuilder sb = new StringBuilder(); if ( timeSec.equals( "-1" ) ) { return ""; } Long time = Long.parseLong( timeSec ) * 1000; Calendar cal = Calendar.getInstance(); cal.setTimeInMillis( time ); sb.append( cal.get( Calendar.YEAR ) ).append( "-" ); sb.append( cal.get( Calendar.MONTH ) + 1 ).append( "-" ); sb.append( cal.get( Calendar.DATE ) ); return sb.toString(); } /** * 格式转化:yy-MM-dd HH:mm * * @param timeSec * @return */ public static String getDateEndMinute( Long timeSec ) { StringBuilder sb = new StringBuilder(); if ( timeSec == -1 ) { return ""; } Long time = timeSec * 1000; Calendar cal = Calendar.getInstance(); cal.setTimeInMillis( time ); sb.append( cal.get( Calendar.YEAR ) ).append( "-" ); sb.append( cal.get( Calendar.MONTH ) + 1 ).append( "-" ); sb.append( cal.get( Calendar.DATE ) ); sb.append( " " ); // 小时 int hours = cal.get( Calendar.HOUR_OF_DAY ); if ( hours == 0 ) { sb.append( "00" ).append( ":" ); } else if ( hours < 10 ) { sb.append( "0" + hours ).append( ":" ); } else { sb.append( hours ).append( ":" ); } // 分钟 int minutes = cal.get( Calendar.MINUTE ); if ( minutes == 0 ) { sb.append( "00" ); } else if ( minutes < 10 ) { sb.append( "0" + minutes ); } else { sb.append( minutes ); } return sb.toString(); } /** * 格式转化:yy-MM-dd HH:mm:ss * * @param timeSec * 网络传输回来的时间(秒) * @return 详细时间 */ public static String getDetailDate( String timeSec ) { try { Long time = Long.parseLong( timeSec ) * 1000; Calendar cal = Calendar.getInstance(); cal.setTimeInMillis( time ); StringBuilder sb = new StringBuilder(); sb.append( cal.get( Calendar.YEAR ) ).append( "-" ); sb.append( cal.get( Calendar.MONTH ) + 1 ).append( "-" ); sb.append( cal.get( Calendar.DATE ) ).append( " " ); // 小时 int hours = cal.get( Calendar.HOUR_OF_DAY ); if ( hours == 0 ) { sb.append( "00" ).append( ":" ); } else if ( hours < 10 ) { sb.append( "0" + hours ).append( ":" ); } else { sb.append( hours ).append( ":" ); } // 分钟 int minutes = cal.get( Calendar.MINUTE ); if ( minutes == 0 ) { sb.append( "00" ).append( ":" ); } else if ( minutes < 10 ) { sb.append( "0" + minutes ).append( ":" ); } else { sb.append( minutes ).append( ":" ); } // 秒 int seconds = cal.get( Calendar.SECOND ); if ( seconds == 0 ) { sb.append( "00" ); } else if ( seconds < 10 ) { sb.append( "0" + seconds ); } else { sb.append( seconds ); } return sb.toString(); } catch ( Exception e ) { return TIME_TRANSFER_ERROR; } } /** * 得到字符串日期,格式为yyyy-MM-dd HH:mm 当前年份日期不显示年 * * @param date * @return */ public static String getFormatDate( Date date ) { String format = "MM-dd HH:mm"; if ( date.getYear() == ( new Date() ).getYear() ) { format = "yyyy-MM-dd HH:mm"; } SimpleDateFormat df = new SimpleDateFormat( format, Locale.getDefault() ); return df.format( date ); } /** * 得到字符串日期,格式为yyyy-MM-dd HH:mm 当前年份日期不显示年 * * @param date * @return */ public static String getFormatDate( String date ) { if ( TextUtils.isEmpty( date ) ) return null; String format = "yyyy-MM-dd HH:mm"; SimpleDateFormat df = new SimpleDateFormat( format, Locale.getDefault() ); Date d = null; try { d = df.parse( date ); } catch ( ParseException e ) { e.printStackTrace(); return date; } if ( d.getYear() != ( new Date() ).getYear() ) { format = "yyyy-MM-dd HH:mm"; } else { format = "MM-dd HH:mm"; } df = new SimpleDateFormat( format, Locale.getDefault() ); return df.format( d ); } public static String getCurrentDateTime() { SimpleDateFormat format = new SimpleDateFormat( "yyyy年MM月dd日 HH:mm" ); String date = format.format( new Date() ); return date; } public static String getCurrentDate() { SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd" ); String date = format.format( new Date() ); return date; } public static String getCurrentWeekOfDate( Date date ) { SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd" ); String dataString = format.format( date ); SimpleDateFormat dateFm = new SimpleDateFormat( "EEEE" ); String weekString = dateFm.format( date ); return dataString + " " + weekString; } public static String getDetailDateTime( long timeSec ) { SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ); Date date = new Date( timeSec ); return format.format( date ); } public static String getDateDay( long timeSec ) { SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd", Locale.CHINA ); Date date = new Date( timeSec ); return format.format( date ); } public static String getTimeOfDay( long timeSec ) { SimpleDateFormat format = new SimpleDateFormat( "HH:mm" ); Date date = new Date( timeSec ); return format.format( date ); } public static String getYearAndMonth( long timeSec ) { SimpleDateFormat format = new SimpleDateFormat( "yyyy年MM月" ); Date date = new Date( timeSec ); return format.format( date ); } public static String formatDateTime( long aTime ) { String ret = null; Date date = new Date( aTime * 1000 ); Calendar c = Calendar.getInstance(); c.setTime( date ); Date currentDate = new Date(); Calendar cc = Calendar.getInstance(); cc.setTime( currentDate ); if ( c.get( Calendar.YEAR ) == cc.get( Calendar.YEAR ) ) { int day = cc.get( Calendar.DAY_OF_YEAR ) - c.get( Calendar.DAY_OF_YEAR ); if ( day == 0 ) { ret = FORMAT_TODAY_TEXT; ret += " "; SimpleDateFormat format = new SimpleDateFormat( "HH:mm", Locale.CHINA ); ret += format.format( date ); } else if ( day == 1 ) { ret = FORMAT_YESTERDAY_TEXT; ret += " "; SimpleDateFormat format = new SimpleDateFormat( "HH:mm", Locale.CHINA ); ret += format.format( date ); } else if ( day == 2 ) { ret = FORMAT_BEFORE_TEXT; ret += " "; SimpleDateFormat format = new SimpleDateFormat( "HH:mm", Locale.CHINA ); ret += format.format( date ); } else { SimpleDateFormat format = new SimpleDateFormat( "MM-dd HH:mm", Locale.CHINA ); ret = format.format( date ); } } else { SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd HH:mm", Locale.CHINA ); ret = format.format( date ); } return ret; } public static String formatChatDataTime( long aTime ) { String ret = ""; Date date = new Date( aTime * 1000 ); Calendar c = Calendar.getInstance(); c.setTime( date ); Date currentDate = new Date(); Calendar cc = Calendar.getInstance(); cc.setTime( currentDate ); if ( c.get( Calendar.YEAR ) == cc.get( Calendar.YEAR ) ) { int day = cc.get( Calendar.DAY_OF_YEAR ) - c.get( Calendar.DAY_OF_YEAR ); if ( day == 0 ) { SimpleDateFormat format = new SimpleDateFormat( "HH:mm", Locale.CHINA ); ret = format.format( date ); } else if ( day == 1 ) { ret = FORMAT_YESTERDAY_TEXT; } else if ( day == 2 ) { ret = FORMAT_BEFORE_TEXT; } else { SimpleDateFormat format = new SimpleDateFormat( "MM-dd", Locale.CHINA ); ret = format.format( date ); } } else { SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd", Locale.CHINA ); ret = format.format( date ); } return ret; } public static long getCurrentTime() { Date currentDate = new Date(); Calendar cc = Calendar.getInstance(); cc.setTime( currentDate ); long time = cc.getTimeInMillis() / 1000; return time; } }
package com.baoy.demo.demoscrollrefreshlist.util; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; import android.content.Context; import android.util.DisplayMetrics; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.ListAdapter; import android.widget.ListView; public class Config { public static final String FILE_NAME = "settings.properties"; public static final int BASE_DISPLAY_WIDTH = 320; public static final int BASE_DISPLAY_HEIGHT = 480; public static final int LOADING_PROGRESS_SIZE = 15; public static final int LOADING_PROGRESS_MARGIN = 210; private static Context sContext; private static Properties sProperties; public static void setContext(Context aContext) { sContext = aContext.getApplicationContext(); sProperties = new Properties(); loadProperties(); } private static void loadProperties() { try { sProperties.load(sContext.openFileInput(FILE_NAME)); } catch (FileNotFoundException e) { } catch (IOException e) { e.printStackTrace(); } } public static int getViewPx(int aValue) { int ret = 0; int width = Config.getWindowWidth(); ret = (int) (width * aValue / Config.BASE_DISPLAY_WIDTH); return ret; } public static int getWindowWidth() { System.out.println("getWindowWidth: 开始:sContext:" + sContext); WindowManager windowManager = (WindowManager) sContext .getSystemService(Context.WINDOW_SERVICE); DisplayMetrics mMetric = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(mMetric); System.out.println("getWindowWidth: " + mMetric.widthPixels); return mMetric.widthPixels; } }
package com.baoy.demo.demoscrollrefreshlist.view; import com.baoy.demo.demoscrollrefreshlist.R; import com.baoy.demo.demoscrollrefreshlist.util.Config; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RelativeLayout; /** * Common appending button for all lists * * @author Neusoft.E3 * */ public class AppendButton extends LinearLayout { private Button mBtnAppend; private ProgressBar mPbLoading; private RelativeLayout mRlAppend; private int mNormalTextResource; private int mLoadingTextResource; private boolean misLoading = false; public AppendButton(Context context) { super(context); loadResources(); } public AppendButton(Context context, AttributeSet attrs) { super(context, attrs); loadResources(); } private void loadResources() { LayoutInflater inflater = (LayoutInflater) getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.appendbutton, this, true); mLoadingTextResource = R.string.append_loading; mNormalTextResource = R.string.append_more; mRlAppend = (RelativeLayout) findViewById(R.id.rlAppend); mBtnAppend = (Button) findViewById(R.id.btnAppend); mPbLoading = (ProgressBar) findViewById(R.id.pbAppend); mPbLoading.setVisibility(View.GONE); LayoutParams params = new LayoutParams( Config.getViewPx(Config.LOADING_PROGRESS_SIZE), Config.getViewPx(Config.LOADING_PROGRESS_SIZE)); params.setMargins(Config.getViewPx(Config.LOADING_PROGRESS_MARGIN), 0, 0, 0); mPbLoading.setLayoutParams(params); } @Override public void setOnClickListener(OnClickListener aListener) { mBtnAppend.setOnClickListener(aListener); } /** * Set whole item background * * @param aResourceId */ public void setBgColor(int aColorId) { mRlAppend.setBackgroundColor(aColorId); } /** * Set custom button bg resource id * * @param aResourceId */ public void setButtonBgResource(int aResourceId) { mBtnAppend.setBackgroundResource(aResourceId); } /** * Set custom button text color resource id * * @param aResourceId */ public void setTextColorResource(int aResourceId) { mBtnAppend.setTextColor(getContext().getResources().getColorStateList( aResourceId)); } /** * Set if loading state is enabled * * @param aLoading */ public void setLoading(boolean aLoading) { misLoading = aLoading; if (aLoading) { mBtnAppend.setText(mLoadingTextResource); mPbLoading.setVisibility(View.VISIBLE); } else { mBtnAppend.setText(mNormalTextResource); mPbLoading.setVisibility(View.GONE); } mBtnAppend.setEnabled(!aLoading); } public boolean isLoading() { return misLoading; } /** * Set text * * @param text */ public void setText(int aNormalResource, int aLoadingResource) { mNormalTextResource = aNormalResource; mLoadingTextResource = aLoadingResource; mBtnAppend.setText(mNormalTextResource); } }
package com.baoy.demo.demoscrollrefreshlist.view; import com.baoy.demo.demoscrollrefreshlist.R; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.widget.RelativeLayout; import android.widget.TextView; public class EmptyView extends RelativeLayout { private TextView mTxtEmpty; public EmptyView( Context context ) { super( context ); LayoutInflater layoutInflater = ( LayoutInflater ) getContext() .getSystemService( Context.LAYOUT_INFLATER_SERVICE ); View view = layoutInflater.inflate( R.layout.empty_content, this, true ); mTxtEmpty = ( TextView ) view.findViewById( R.id.txtEmptyText ); } public void setEmptyText( int aResId ) { mTxtEmpty.setText( aResId ); } public void setEmptyText( String aTxt ) { mTxtEmpty.setText( aTxt ); } }
package com.baoy.demo.demoscrollrefreshlist.view; //com.baoy.demo.demoscrollrefreshlist.view.ScrollRefreshListView import com.baoy.demo.demoscrollrefreshlist.R; import com.baoy.demo.demoscrollrefreshlist.util.TimeUtils; import android.content.Context; import android.os.SystemClock; 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.AbsListView.OnScrollListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; public class ScrollRefreshListView extends ListView implements OnScrollListener { public static final String id = "ScrollRefreshListView"; public static final int FOOTER_VIEW_NONE = 0; public static final int FOOTER_VIEW_MORE = 1; public static final int FOOTER_VIEW_EMPTY = 2; private final static int RELEASE_TO_REFRESH = 0; // 释放 private final static int PULL_TO_REFRESH = 1; // 下拉刷新 public final static int REFRESHING = 2; // 正在刷新 private final static int DONE = 3; // 按下 private final static int LOADING = 4; // 实际的padding的距离与界面上偏移距离的比例 private final static int RATIO = 3; private LayoutInflater mInflater; private LinearLayout mRefreshView; private TextView mTipsTextview; private TextView mLastUpdatedTextView; private ImageView mArrowImageView; private ProgressBar mProgressBar; private RotateAnimation mAnimation; private RotateAnimation mReverseAnimation; // 用于保证startY的值在一个完整的touch事件中只被记录一次 private boolean mIsRecored; private int mHeadContentWidth; private int mHeadContentHeight; private int mStartY; private int mFirstItemIndex; private int mState; private boolean mIsBack; private onRefreshListener mRefreshListener; private boolean mIsRefreshable; private Context mContext; private View mListFooter; private View mEmptyView; private AppendButton mBtnAppend; private OnResizeListener mOnResizeListener; public interface onRefreshListener { public void onRefresh(); public void onLoadMore(); } public interface OnResizeListener { void OnResize( int w, int h, int oldw, int oldh ); } public ScrollRefreshListView( Context context ) { super( context ); mContext = context; init( context ); } public ScrollRefreshListView( Context context, AttributeSet attrs ) { super( context, attrs ); mContext = context; init( context ); } private void init( Context context ) { mInflater = LayoutInflater.from( context ); // head 布局文件 mRefreshView = ( LinearLayout ) mInflater.inflate( R.layout.scroll_refresh_head, null ); // 下拉箭头 mArrowImageView = ( ImageView ) mRefreshView .findViewById( R.id.head_arrowImageView ); mArrowImageView.setMinimumWidth( 70 ); mArrowImageView.setMinimumHeight( 50 ); // 进度条 mProgressBar = ( ProgressBar ) mRefreshView .findViewById( R.id.head_progressBar ); // 下拉提示刷新 mTipsTextview = ( TextView ) mRefreshView .findViewById( R.id.head_tipsTextView ); // 最新一次刷新时间 mLastUpdatedTextView = ( TextView ) mRefreshView .findViewById( R.id.head_lastUpdatedTextView ); // 计算head的高宽 measureView( mRefreshView ); mHeadContentHeight = mRefreshView.getMeasuredHeight(); mHeadContentWidth = mRefreshView.getMeasuredWidth(); // 初始状态是 隐藏掉head 布局 mRefreshView.setPadding( 0, -1 * mHeadContentHeight, 0, 0 ); mRefreshView.invalidate(); Log.v( "size", "width:" + mHeadContentWidth + " height:" + mHeadContentHeight ); // list添加头文件 addHeaderView( mRefreshView, null, false ); setOnScrollListener( this ); // 下拉以及恢复动画 mAnimation = new RotateAnimation( 0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f ); mAnimation.setInterpolator( new LinearInterpolator() ); mAnimation.setDuration( 250 ); mAnimation.setFillAfter( true ); mReverseAnimation = new RotateAnimation( -180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f ); mReverseAnimation.setInterpolator( new LinearInterpolator() ); mReverseAnimation.setDuration( 200 ); mReverseAnimation.setFillAfter( true ); mState = DONE; mIsRefreshable = false; System.out.println( "mListFooter:" + mListFooter + ",,mListFooter:" + mListFooter ); mListFooter = mInflater.inflate( R.layout.listfooter, null ); mBtnAppend = ( AppendButton ) mListFooter.findViewById( R.id.appender ); mBtnAppend.setVisibility( View.GONE ); mEmptyView = new EmptyView( mContext ); addFooterView( mListFooter ); mBtnAppend.setOnClickListener( new OnClickListener() { @Override public void onClick( View v ) { mBtnAppend.setVisibility( View.VISIBLE ); mBtnAppend.setLoading( true ); mRefreshListener.onLoadMore(); } } ); } public void onScroll( AbsListView arg0, int firstVisiableItem, int arg2, int arg3 ) { mFirstItemIndex = firstVisiableItem; } public void onScrollStateChanged( AbsListView arg0, int scrollState ) { } public boolean onTouchEvent( MotionEvent event ) { if ( mIsRefreshable ) { switch ( event.getAction() ) { // 在down时候记录当前Y的位置 case MotionEvent.ACTION_DOWN: if ( mFirstItemIndex == 0 && !mIsRecored ) { mIsRecored = true; mStartY = ( int ) event.getY(); } break; case MotionEvent.ACTION_UP: if ( mState != REFRESHING && mState != LOADING ) { if ( mState == DONE ) { // 什么都不做 } // 由下拉刷新状态,到done状态 if ( mState == PULL_TO_REFRESH ) { mState = DONE; changeHeaderViewByState(); } if ( mState == RELEASE_TO_REFRESH ) { mState = REFRESHING; changeHeaderViewByState(); onRefresh(); } } mIsRecored = false; mIsBack = false; break; case MotionEvent.ACTION_MOVE: int tempY = ( int ) event.getY(); if ( !mIsRecored && mFirstItemIndex == 0 ) { mIsRecored = true; mStartY = tempY; } if ( mState != REFRESHING && mIsRecored && mState != LOADING ) { // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动 // 可以松手去刷新了 if ( mState == RELEASE_TO_REFRESH ) { setSelection( 0 ); // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步 if ( ( ( tempY - mStartY ) / RATIO < mHeadContentHeight ) && ( tempY - mStartY ) > 0 ) { mState = PULL_TO_REFRESH; changeHeaderViewByState(); } // 一下子推到顶了 else if ( tempY - mStartY <= 0 ) { mState = DONE; changeHeaderViewByState(); } // 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步 else { // 不用进行特别的操作,只用更新paddingTop的值就行了 } } // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态 if ( mState == PULL_TO_REFRESH ) { setSelection( 0 ); // 下拉到可以进入RELEASE_TO_REFRESH的状态 if ( ( tempY - mStartY ) / RATIO >= mHeadContentHeight ) { mState = RELEASE_TO_REFRESH; mIsBack = true; changeHeaderViewByState(); } // 上推到顶了 else if ( tempY - mStartY <= 0 ) { mState = DONE; changeHeaderViewByState(); } } // done状态下 if ( mState == DONE ) { if ( tempY - mStartY > 0 ) { mState = PULL_TO_REFRESH; changeHeaderViewByState(); } } // 更新headView的size if ( mState == PULL_TO_REFRESH ) { mRefreshView.setPadding( 0, -1 * mHeadContentHeight + ( tempY - mStartY ) / RATIO, 0, 0 ); } // 更新headView的paddingTop if ( mState == RELEASE_TO_REFRESH ) { mRefreshView.setPadding( 0, ( tempY - mStartY ) / RATIO - mHeadContentHeight, 0, 0 ); } } break; } } return super.onTouchEvent( event ); } public void changeHeaderViewByState() { switch ( mState ) { // 松开刷新状态 case RELEASE_TO_REFRESH: mArrowImageView.setVisibility( View.VISIBLE ); mProgressBar.setVisibility( View.GONE ); mTipsTextview.setVisibility( View.VISIBLE ); mLastUpdatedTextView.setVisibility( View.VISIBLE ); mArrowImageView.clearAnimation(); mArrowImageView.startAnimation( mAnimation ); mTipsTextview.setText( R.string.scroll_refresh_release_text ); break; // 下拉刷新 case PULL_TO_REFRESH: mProgressBar.setVisibility( View.GONE ); mTipsTextview.setVisibility( View.VISIBLE ); mLastUpdatedTextView.setVisibility( View.VISIBLE ); mArrowImageView.clearAnimation(); mArrowImageView.setVisibility( View.VISIBLE ); // 是由RELEASE_To_REFRESH状态转变来的 // 箭头反转向上 if ( mIsBack ) { mIsBack = false; mArrowImageView.clearAnimation(); mArrowImageView.startAnimation( mReverseAnimation ); mTipsTextview.setText( R.string.scroll_refresh_text ); } else { mTipsTextview.setText( R.string.scroll_refresh_text ); } break; // 刷新中 状态 case REFRESHING: mRefreshView.setPadding( 0, 0, 0, 0 ); mProgressBar.setVisibility( View.VISIBLE ); mArrowImageView.clearAnimation(); mArrowImageView.setVisibility( View.GONE ); mTipsTextview.setText( R.string.append_loading ); mLastUpdatedTextView.setVisibility( View.VISIBLE ); break; // 刷新完毕 case DONE: mRefreshView.setPadding( 0, -1 * mHeadContentHeight, 0, 0 ); mProgressBar.setVisibility( View.GONE ); mArrowImageView.clearAnimation(); mArrowImageView .setImageResource( R.drawable.ic_pulltorefresh_arrow ); mTipsTextview.setText( R.string.scroll_refresh_text ); mLastUpdatedTextView.setVisibility( View.VISIBLE ); break; } } public void setOnRefreshListener( onRefreshListener refreshListener ) { this.mRefreshListener = refreshListener; mIsRefreshable = true; } public void onRefreshComplete() { mState = DONE; mLastUpdatedTextView.setText( mContext .getString( R.string.last_update_text ) + TimeUtils.getCurrentDateTime() ); changeHeaderViewByState(); } private void onRefresh() { if ( mRefreshListener != null ) { mRefreshListener.onRefresh(); } } // 估计headView的width以及height private void measureView( View child ) { ViewGroup.LayoutParams p = child.getLayoutParams(); if ( p == null ) { p = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT ); } int childWidthSpec = ViewGroup.getChildMeasureSpec( 0, 0 + 0, p.width ); int lpHeight = p.height; int childHeightSpec; if ( lpHeight > 0 ) { childHeightSpec = MeasureSpec.makeMeasureSpec( lpHeight, MeasureSpec.EXACTLY ); } else { childHeightSpec = MeasureSpec.makeMeasureSpec( 0, MeasureSpec.UNSPECIFIED ); } child.measure( childWidthSpec, childHeightSpec ); } public void setAdapter( BaseAdapter aAdapter ) { mLastUpdatedTextView.setText( mContext .getString( R.string.scroll_refresh_last_text ) + TimeUtils.getCurrentDateTime() ); super.setAdapter( aAdapter ); } public void setState( int aState ) { mState = aState; } public void setOnResizeListener( OnResizeListener aListener ) { mOnResizeListener = aListener; } @Override protected void onSizeChanged( int w, int h, int oldw, int oldh ) { super.onSizeChanged( w, h, oldw, oldh ); if ( mOnResizeListener != null ) { mOnResizeListener.OnResize( w, h, oldw, oldh ); } } public void setListFooterView( int aView ) { removeFooterView( mEmptyView ); removeFooterView( mListFooter ); if ( aView == FOOTER_VIEW_MORE ) { addFooterView( mListFooter ); mBtnAppend.setVisibility( View.VISIBLE ); } else if ( aView == FOOTER_VIEW_EMPTY ) { addFooterView( mEmptyView ); } } public void removeListFooterView( int aView ) { removeFooterView( mEmptyView ); removeFooterView( mListFooter ); if ( aView == FOOTER_VIEW_EMPTY ) { addFooterView( mEmptyView ); } } public void setEmptyViewText( int resId ) { if ( mEmptyView != null ) { ( ( EmptyView ) mEmptyView ).setEmptyText( resId ); } } public void setLoadMoreComplete() { mBtnAppend.setLoading( false ); } public void setHeaderView( boolean aEnable ) { if ( aEnable ) { addHeaderView( mRefreshView, null, false ); } else { removeHeaderView( mRefreshView ); } } public void refreshSelf() { int tempStartY = 0; int tempY = tempStartY + mHeadContentHeight * RATIO + 200; long downTime = SystemClock.uptimeMillis(); MotionEvent downEvent = MotionEvent.obtain( downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, tempStartY, tempStartY, 0 ); MotionEvent moveEvent = MotionEvent.obtain( downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, tempStartY, tempY, 0 ); MotionEvent moveEvent2 = MotionEvent.obtain( downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, tempStartY, tempY + 10, 0 ); MotionEvent upEvent = MotionEvent.obtain( downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, tempStartY, tempY + 20, 0 ); onTouchEvent( downEvent ); onTouchEvent( moveEvent ); onTouchEvent( moveEvent2 ); onTouchEvent( upEvent ); downEvent.recycle(); moveEvent.recycle(); upEvent.recycle(); } }
package com.baoy.demo.demoscrollrefreshlist.view; import com.baoy.demo.demoscrollrefreshlist.R; import com.baoy.demo.demoscrollrefreshlist.util.TimeUtils; import android.content.Context; import android.os.SystemClock; 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.AbsListView.OnScrollListener; import android.widget.BaseAdapter; import android.widget.ExpandableListView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; public class ScrollRefreshExpandableListView extends ExpandableListView implements OnScrollListener { public static final String id = "ScrollRefreshListView"; public static final int FOOTER_VIEW_NONE = 0; public static final int FOOTER_VIEW_MORE = 1; public static final int FOOTER_VIEW_EMPTY = 2; private final static int RELEASE_TO_REFRESH = 0; // 释放 private final static int PULL_TO_REFRESH = 1; // 下拉刷新 public final static int REFRESHING = 2; // 正在刷新 private final static int DONE = 3; // 按下 private final static int LOADING = 4; // 实际的padding的距离与界面上偏移距离的比例 private final static int RATIO = 3; private LayoutInflater mInflater; private LinearLayout mRefreshView; private TextView mTipsTextview; private TextView mLastUpdatedTextView; private ImageView mArrowImageView; private ProgressBar mProgressBar; private RotateAnimation mAnimation; private RotateAnimation mReverseAnimation; // 用于保证startY的值在一个完整的touch事件中只被记录一次 private boolean mIsRecored; private int mHeadContentWidth; private int mHeadContentHeight; private int mStartY; private int mFirstItemIndex; private int mState; private boolean mIsBack; private onRefreshListener mRefreshListener; private boolean mIsRefreshable; private Context mContext; private View mListFooter; private View mEmptyView; private AppendButton mBtnAppend; private OnResizeListener mOnResizeListener; public interface onRefreshListener { public void onRefresh(); public void onLoadMore(); } public interface OnResizeListener { void OnResize(int w, int h, int oldw, int oldh); } public ScrollRefreshExpandableListView(Context context) { super(context); mContext = context; init(context); } public ScrollRefreshExpandableListView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; init(context); } private void init(Context context) { mInflater = LayoutInflater.from(context); // head 布局文件 mRefreshView = (LinearLayout) mInflater.inflate( R.layout.scroll_refresh_head, null); // 下拉箭头 mArrowImageView = (ImageView) mRefreshView .findViewById(R.id.head_arrowImageView); mArrowImageView.setMinimumWidth(70); mArrowImageView.setMinimumHeight(50); // 进度条 mProgressBar = (ProgressBar) mRefreshView .findViewById(R.id.head_progressBar); // 下拉提示刷新 mTipsTextview = (TextView) mRefreshView .findViewById(R.id.head_tipsTextView); // 最新一次刷新时间 mLastUpdatedTextView = (TextView) mRefreshView .findViewById(R.id.head_lastUpdatedTextView); // 计算head的高宽 measureView(mRefreshView); mHeadContentHeight = mRefreshView.getMeasuredHeight(); mHeadContentWidth = mRefreshView.getMeasuredWidth(); // 初始状态是 隐藏掉head 布局 mRefreshView.setPadding(0, -1 * mHeadContentHeight, 0, 0); mRefreshView.invalidate(); Log.v("size", "width:" + mHeadContentWidth + " height:" + mHeadContentHeight); // list添加头文件 addHeaderView(mRefreshView, null, false); setOnScrollListener(this); // 下拉以及恢复动画 mAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); mAnimation.setInterpolator(new LinearInterpolator()); mAnimation.setDuration(250); mAnimation.setFillAfter(true); mReverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); mReverseAnimation.setInterpolator(new LinearInterpolator()); mReverseAnimation.setDuration(200); mReverseAnimation.setFillAfter(true); mState = DONE; mIsRefreshable = false; System.out.println("mListFooter:" + mListFooter + ",,mListFooter:" + mListFooter); mListFooter = mInflater.inflate(R.layout.listfooter, null); System.out.println("mListFooter:" + mListFooter ); mBtnAppend = (AppendButton) mListFooter.findViewById(R.id.appender); mBtnAppend.setVisibility(View.GONE); mEmptyView = new EmptyView(mContext); addFooterView(mListFooter); mBtnAppend.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mBtnAppend.setVisibility(View.VISIBLE); mBtnAppend.setLoading(true); mRefreshListener.onLoadMore(); } }); } public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2, int arg3) { mFirstItemIndex = firstVisiableItem; } public void onScrollStateChanged(AbsListView arg0, int scrollState) { } public boolean onTouchEvent(MotionEvent event) { if (mIsRefreshable) { switch (event.getAction()) { // 在down时候记录当前Y的位置 case MotionEvent.ACTION_DOWN: if (mFirstItemIndex == 0 && !mIsRecored) { mIsRecored = true; mStartY = (int) event.getY(); } break; case MotionEvent.ACTION_UP: if (mState != REFRESHING && mState != LOADING) { if (mState == DONE) { // 什么都不做 } // 由下拉刷新状态,到done状态 if (mState == PULL_TO_REFRESH) { mState = DONE; changeHeaderViewByState(); } if (mState == RELEASE_TO_REFRESH) { mState = REFRESHING; changeHeaderViewByState(); onRefresh(); } } mIsRecored = false; mIsBack = false; break; case MotionEvent.ACTION_MOVE: int tempY = (int) event.getY(); if (!mIsRecored && mFirstItemIndex == 0) { mIsRecored = true; mStartY = tempY; } if (mState != REFRESHING && mIsRecored && mState != LOADING) { // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动 // 可以松手去刷新了 if (mState == RELEASE_TO_REFRESH) { setSelection(0); // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步 if (((tempY - mStartY) / RATIO < mHeadContentHeight) && (tempY - mStartY) > 0) { mState = PULL_TO_REFRESH; changeHeaderViewByState(); } // 一下子推到顶了 else if (tempY - mStartY <= 0) { mState = DONE; changeHeaderViewByState(); } // 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步 else { // 不用进行特别的操作,只用更新paddingTop的值就行了 } } // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态 if (mState == PULL_TO_REFRESH) { setSelection(0); // 下拉到可以进入RELEASE_TO_REFRESH的状态 if ((tempY - mStartY) / RATIO >= mHeadContentHeight) { mState = RELEASE_TO_REFRESH; mIsBack = true; changeHeaderViewByState(); } // 上推到顶了 else if (tempY - mStartY <= 0) { mState = DONE; changeHeaderViewByState(); } } // done状态下 if (mState == DONE) { if (tempY - mStartY > 0) { mState = PULL_TO_REFRESH; changeHeaderViewByState(); } } // 更新headView的size if (mState == PULL_TO_REFRESH) { mRefreshView.setPadding(0, -1 * mHeadContentHeight + (tempY - mStartY) / RATIO, 0, 0); } // 更新headView的paddingTop if (mState == RELEASE_TO_REFRESH) { mRefreshView.setPadding(0, (tempY - mStartY) / RATIO - mHeadContentHeight, 0, 0); } } break; } } return super.onTouchEvent(event); } public void changeHeaderViewByState() { switch (mState) { // 松开刷新状态 case RELEASE_TO_REFRESH: mArrowImageView.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.GONE); mTipsTextview.setVisibility(View.VISIBLE); mLastUpdatedTextView.setVisibility(View.VISIBLE); mArrowImageView.clearAnimation(); mArrowImageView.startAnimation(mAnimation); mTipsTextview.setText(R.string.scroll_refresh_release_text); break; // 下拉刷新 case PULL_TO_REFRESH: mProgressBar.setVisibility(View.GONE); mTipsTextview.setVisibility(View.VISIBLE); mLastUpdatedTextView.setVisibility(View.VISIBLE); mArrowImageView.clearAnimation(); mArrowImageView.setVisibility(View.VISIBLE); // 是由RELEASE_To_REFRESH状态转变来的 // 箭头反转向上 if (mIsBack) { mIsBack = false; mArrowImageView.clearAnimation(); mArrowImageView.startAnimation(mReverseAnimation); mTipsTextview.setText(R.string.scroll_refresh_text); } else { mTipsTextview.setText(R.string.scroll_refresh_text); } break; // 刷新中 状态 case REFRESHING: mRefreshView.setPadding(0, 0, 0, 0); mProgressBar.setVisibility(View.VISIBLE); mArrowImageView.clearAnimation(); mArrowImageView.setVisibility(View.GONE); mTipsTextview.setText(R.string.append_loading); mLastUpdatedTextView.setVisibility(View.VISIBLE); break; // 刷新完毕 case DONE: mRefreshView.setPadding(0, -1 * mHeadContentHeight, 0, 0); mProgressBar.setVisibility(View.GONE); mArrowImageView.clearAnimation(); mArrowImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow); mTipsTextview.setText(R.string.scroll_refresh_text); mLastUpdatedTextView.setVisibility(View.VISIBLE); break; } } public void setOnRefreshListener(onRefreshListener refreshListener) { this.mRefreshListener = refreshListener; mIsRefreshable = true; } public void onRefreshComplete() { mState = DONE; mLastUpdatedTextView.setText(mContext .getString(R.string.last_update_text) + TimeUtils.getCurrentDateTime()); changeHeaderViewByState(); } private void onRefresh() { if (mRefreshListener != null) { mRefreshListener.onRefresh(); } } // 估计headView的width以及height private void measureView(View child) { ViewGroup.LayoutParams p = child.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); int lpHeight = p.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } public void setAdapter(BaseAdapter aAdapter) { mLastUpdatedTextView.setText(mContext .getString(R.string.scroll_refresh_last_text) + TimeUtils.getCurrentDateTime()); super.setAdapter(aAdapter); } public void setState(int aState) { mState = aState; } public void setOnResizeListener(OnResizeListener aListener) { mOnResizeListener = aListener; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (mOnResizeListener != null) { mOnResizeListener.OnResize(w, h, oldw, oldh); } } public void setListFooterView(int aView) { removeFooterView(mEmptyView); removeFooterView(mListFooter); if (aView == FOOTER_VIEW_MORE) { addFooterView(mListFooter); mBtnAppend.setVisibility(View.VISIBLE); } else if (aView == FOOTER_VIEW_EMPTY) { addFooterView(mEmptyView); } } public void removeListFooterView(int aView){ removeFooterView(mListFooter); removeFooterView(mEmptyView); if (aView == FOOTER_VIEW_EMPTY) { addFooterView(mEmptyView); } } public void setLoadMoreComplete() { mBtnAppend.setLoading(false); } public void setHeaderView(boolean aEnable) { if (aEnable) { addHeaderView(mRefreshView, null, false); } else { removeHeaderView(mRefreshView); } } public void setEmptyViewText(int resId) { if (mEmptyView != null) { ((EmptyView) mEmptyView).setEmptyText(resId); } } public void setEmptyViewText(String text) { if (mEmptyView != null) { ((EmptyView) mEmptyView).setEmptyText(text); } } public void refreshSelf(){ int tempStartY = 0; int tempY = tempStartY + mHeadContentHeight * RATIO + 200; long downTime = SystemClock.uptimeMillis(); MotionEvent downEvent = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, tempStartY, tempStartY, 0); MotionEvent moveEvent = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, tempStartY, tempY, 0); MotionEvent moveEvent2 = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, tempStartY, tempY + 10, 0); MotionEvent upEvent = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, tempStartY, tempY + 20, 0); onTouchEvent(downEvent); onTouchEvent(moveEvent); onTouchEvent(moveEvent2); onTouchEvent(upEvent); downEvent.recycle(); moveEvent.recycle(); upEvent.recycle(); } }
捐助开发者
在兴趣的驱动下,写一个免费
的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。 当然,有钱捧个钱场(右上角的爱心标志,支持支付宝和PayPal捐助),没钱捧个人场,谢谢各位。
谢谢您的赞助,我会做的更好!