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捐助),没钱捧个人场,谢谢各位。
谢谢您的赞助,我会做的更好!
相关推荐
在Android开发中,串口通信(Serial Port Communication)是一种重要的技术,它允许设备之间通过串行接口进行数据交换。在Android Studio环境下实现串口通信,开发者可以构建与硬件设备交互的应用,例如读取传感器...
在现代的移动应用开发中,JavaScript与原生平台之间的交互变得越来越常见,特别是在使用Android的WebView组件时。本文将深入探讨如何使用JavaScript调用Android的方法,并传递JSON数据,以实现两者之间的高效通信。 ...
【Android扫雷游戏开发详解】 在移动开发领域,Android Studio是Google推出的官方集成开发环境(IDE),用于构建Android应用程序。本项目"Android扫雷游戏"就是利用Android Studio进行开发的一个实例,旨在帮助初学...
在Android开发中,为UI元素添加虚线、圆角和渐变效果是常见的需求,可以提升应用的视觉吸引力。下面将详细讲解如何实现这些效果。 ### 一、虚线(Dashed Line) 在Android中,我们可以使用`Shape Drawable`来创建...
# mv /opt/android-sdk/platforms/android-25/android-7.1.1/* /opt/android-sdk/platforms/android-25/ # rm -rf /opt/android-sdk/platforms/android-25/android-7.1.1 官网下载地址:...
在Android开发领域,初学者经常会面临许多挑战,如理解Android应用程序的基本架构、学习XML布局、掌握Java或Kotlin编程语言,以及如何与设备硬件交互等。"Android开发入门60个小案例+源代码"这个资源提供了丰富的...
源码里面有Bluetooth4_3/BLEDemo/Android_Lightblue.apk三个.前两个是BLE的demo。BLEDemo这个功能较Bluetooth4_3多一些,有兴趣的可以都看下。Android_Lightblue.apk是Android版的lightblue,在进行ble开发的时候用...
Android SipDemo是一个示例应用,它展示了如何在Android平台上实现网络电话功能,特别是针对Android 2.3(Gingerbread)及以上版本。这个项目基于Android的SIP(Session Initiation Protocol)API,这是一种用于...
第2篇为应用开发篇,通过实例介绍了Android UI布局、Android人机界面、手机硬件设备的使用、Android本地存储系统、Android中的数据库、多线程设计、Android传感器、Android游戏开发基础、Android与Internet,以及...
在Android平台上,即时通讯(Instant Messaging,简称IM)已经成为移动应用不可或缺的一部分,而结合视频通信功能则让用户体验更上一层楼。本项目“Android之基于RTP/RTSP即时通讯-Android源码”正是这样的一个解决...
《Android Studio项目源码解析与学习指南》 在Android应用开发的世界中,Android Studio作为官方推荐的集成开发环境(IDE),已经成为开发者们的首选工具。本文将深入探讨"50款Android studio项目源码.zip"这一资源...
Android SDK是Android应用程序开发不可或缺的一部分,它为开发者提供了构建、测试和调试应用所需的各种工具。在本场景中,我们关注的是Android SDK的27版本,这对应于Android 8.1.0,也称为Oreo。这个版本的SDK包含...
在Android系统中,检测U盘(USB存储设备)的热插拔事件是一项常见的需求,尤其在开发与USB设备交互的应用时。"android检测U盘插拔事件"这个标题揭示了我们要探讨的核心技术点:如何在Android应用中监听并处理U盘的...
在Android应用开发中,抽屉菜单(Drawer Menu)是一种常见的设计模式,用于提供导航功能,让用户可以从屏幕边缘滑出一个包含多个选项的列表。这种设计通常遵循Material Design指南,是Google推荐的Android应用界面...
在Android开发领域,Android Studio是谷歌官方推荐的集成开发环境(IDE),用于构建高质量的Android应用。本小案例将深入探讨如何使用Android Studio进行实际项目开发。以下将详细介绍Android Studio的一些核心功能和...
《VB for Android12.12:VB语言在Android开发中的新里程碑》 VB(Visual Basic)是微软公司推出的一种面向对象的编程语言,以其易学易用的特点深受程序员喜爱。随着移动应用市场的繁荣,VB也开始拓展到Android平台...
在Android平台上,开发一款“一键清理后台”应用可以帮助用户快速释放设备内存,提高系统运行速度。这个功能通常包括清理正在运行的应用程序、终止不必要的服务以及管理后台进程。下面将详细介绍如何在Android 4.4...
使用: export ANDROID_HOME="/opt/android-...# mv /opt/android-sdk/platforms/android-8.0.0 /opt/android-sdk/platforms/android-26 官网下载地址:https://dl.google.com/android/repository/platform-26_r01.zip
在Android平台上实现WebRTC,首先需要理解其核心组件和工作流程。WebRTC的架构包括以下关键部分: 1. **信令层**:这是WebRTC系统中用于建立和管理连接的部分。它处理会话邀请、媒体协商以及传输控制协议(如SIP或...
《Android点餐系统项目》是一门深度探讨如何在Android平台上构建无线点餐系统的视频教程,旨在教授学员如何利用Android技术实现一个完整的点餐系统,包括客户端和服务端的开发。这门课程涵盖了移动应用开发的多个...