├── .classpath ├── .project ├── .settings └── org.eclipse.jdt.core.prefs ├── AndroidManifest.xml ├── README.md ├── ic_launcher-web.png ├── libs └── android-support-v4.jar ├── proguard-project.txt ├── project.properties ├── res ├── anim │ ├── reverse_anim.xml │ └── rotating.xml ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ ├── h.jpg │ ├── i.jpg │ ├── ic_launcher.png │ ├── j.jpg │ ├── k.jpg │ ├── l.jpg │ ├── load_failed.png │ ├── load_succeed.png │ ├── loading.png │ ├── m.jpg │ ├── pull_icon_big.png │ ├── pullup_icon_big.png │ ├── refresh_failed.png │ ├── refresh_succeed.png │ └── refreshing.png ├── drawable-xxhdpi │ └── ic_launcher.png ├── layout │ ├── activity_expandablelistview.xml │ ├── activity_gridview.xml │ ├── activity_imageview.xml │ ├── activity_listview.xml │ ├── activity_main.xml │ ├── activity_scrollview.xml │ ├── activity_textview.xml │ ├── activity_webview.xml │ ├── list_item_layout.xml │ ├── load_more.xml │ └── refresh_head.xml ├── values-sw600dp │ └── dimens.xml ├── values-sw720dp-land │ └── dimens.xml └── values │ ├── color.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── screenshots ├── ExpandableListView.gif ├── GridView.gif ├── ImageView.gif ├── ListView.gif ├── ScrollView.gif ├── TextView.gif ├── WebView.gif └── main.gif └── src └── com └── jingchen └── pulltorefresh ├── MainActivity.java ├── MyAdapter.java ├── MyListener.java ├── PullToRefreshLayout.java ├── activity ├── PullableExpandableListViewActivity.java ├── PullableGridViewActivity.java ├── PullableImageViewActivity.java ├── PullableListViewActivity.java ├── PullableScrollViewActivity.java ├── PullableTextViewActivity.java └── PullableWebViewActivity.java └── pullableview ├── Pullable.java ├── PullableExpandableListView.java ├── PullableGridView.java ├── PullableImageView.java ├── PullableListView.java ├── PullableScrollView.java ├── PullableTextView.java └── PullableWebView.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | PullToRefreshAndLoad 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 3 | org.eclipse.jdt.core.compiler.compliance=1.6 4 | org.eclipse.jdt.core.compiler.source=1.6 5 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PullToRefreshAndLoad 2 | ==================== 3 | 4 | Android下拉刷新上拉加载控件,对所有View通用! 5 | 这是一个演示如何使用通用的下拉刷新上拉加载控件demo,demo中已经实现了常见的需要上下拉功能的控件,其他控件如果需要加入这两个功能可自行扩展,实现Pullable接口即可, 6 | 具体的实现原理分析可以参见我的博客[http://blog.csdn.net/zhongkejingwang/article/details/38868463](http://blog.csdn.net/zhongkejingwang/article/details/38868463) 7 | ##demo截图 8 | ###demo首页也是一个可以上拉下拉的ListView 9 | ![demo首页](https://github.com/jingchenUSTC/PullToRefreshAndLoad/blob/master/screenshots/main.gif) 10 | ###ListView: 11 | ![ListView](https://github.com/jingchenUSTC/PullToRefreshAndLoad/blob/master/screenshots/ListView.gif) 12 | ###GridView: 13 | ![GridView](https://github.com/jingchenUSTC/PullToRefreshAndLoad/blob/master/screenshots/GridView.gif) 14 | ###ExpandableListView: 15 | ![ExpandableListView](https://github.com/jingchenUSTC/PullToRefreshAndLoad/blob/master/screenshots/ExpandableListView.gif) 16 | ###ScrollView: 17 | ![ScrollView](https://github.com/jingchenUSTC/PullToRefreshAndLoad/blob/master/screenshots/ScrollView.gif) 18 | ###WebView: 19 | ![WebView](https://github.com/jingchenUSTC/PullToRefreshAndLoad/blob/master/screenshots/WebView.gif) 20 | ###ImageView: 21 | ![ImageView](https://github.com/jingchenUSTC/PullToRefreshAndLoad/blob/master/screenshots/ImageView.gif) 22 | ###TextView: 23 | ![TextView](https://github.com/jingchenUSTC/PullToRefreshAndLoad/blob/master/screenshots/TextView.gif) 24 | -------------------------------------------------------------------------------- /ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/ic_launcher-web.png -------------------------------------------------------------------------------- /libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/libs/android-support-v4.jar -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-8 15 | -------------------------------------------------------------------------------- /res/anim/reverse_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | -------------------------------------------------------------------------------- /res/anim/rotating.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/h.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/h.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/i.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/i.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/j.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/j.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/k.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/k.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/l.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/l.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/load_failed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/load_failed.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/load_succeed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/load_succeed.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/loading.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/m.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/m.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/pull_icon_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/pull_icon_big.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/pullup_icon_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/pullup_icon_big.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/refresh_failed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/refresh_failed.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/refresh_succeed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/refresh_succeed.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/refreshing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xhdpi/refreshing.png -------------------------------------------------------------------------------- /res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/layout/activity_expandablelistview.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /res/layout/activity_gridview.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /res/layout/activity_imageview.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /res/layout/activity_listview.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 22 | 23 | 32 | 33 | 42 | 43 | 52 | 53 | 62 | 63 | 64 | 70 | 71 | 72 | 73 | 74 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /res/layout/activity_scrollview.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 16 | 17 | 23 | 24 | 28 | 29 | 33 | 34 | 38 | 42 | 46 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /res/layout/activity_textview.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /res/layout/activity_webview.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /res/layout/list_item_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | -------------------------------------------------------------------------------- /res/layout/load_more.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 19 | 20 | 27 | 28 | 36 | 37 | 45 | 46 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /res/layout/refresh_head.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 19 | 20 | 27 | 28 | 36 | 37 | 45 | 46 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/values-sw720dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 128dp 8 | 9 | 10 | -------------------------------------------------------------------------------- /res/values/color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | #000000 5 | #aaaaaa 6 | #6593cb 7 | 8 | -------------------------------------------------------------------------------- /res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 通用版下拉刷新上拉加载控件 5 | 这里是HeadView 6 | 下拉刷新 7 | 释放立即刷新 8 | 正在刷新... 9 | 刷新成功 10 | 刷新失败 11 | 上拉加载更多 12 | 释放立即加载 13 | 正在加载... 14 | 加载成功 15 | 加载失败 16 | 17 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /screenshots/ExpandableListView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/screenshots/ExpandableListView.gif -------------------------------------------------------------------------------- /screenshots/GridView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/screenshots/GridView.gif -------------------------------------------------------------------------------- /screenshots/ImageView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/screenshots/ImageView.gif -------------------------------------------------------------------------------- /screenshots/ListView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/screenshots/ListView.gif -------------------------------------------------------------------------------- /screenshots/ScrollView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/screenshots/ScrollView.gif -------------------------------------------------------------------------------- /screenshots/TextView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/screenshots/TextView.gif -------------------------------------------------------------------------------- /screenshots/WebView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/screenshots/WebView.gif -------------------------------------------------------------------------------- /screenshots/main.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jingchenUSTC/PullToRefreshAndLoad/5e3c283ae548155f18940708ed1042bc24e32723/screenshots/main.gif -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import android.app.Activity; 7 | import android.content.Intent; 8 | import android.os.Bundle; 9 | import android.view.View; 10 | import android.widget.AdapterView; 11 | import android.widget.AdapterView.OnItemClickListener; 12 | import android.widget.AdapterView.OnItemLongClickListener; 13 | import android.widget.ListView; 14 | import android.widget.Toast; 15 | 16 | import com.jingchen.pulltorefresh.activity.PullableExpandableListViewActivity; 17 | import com.jingchen.pulltorefresh.activity.PullableGridViewActivity; 18 | import com.jingchen.pulltorefresh.activity.PullableImageViewActivity; 19 | import com.jingchen.pulltorefresh.activity.PullableListViewActivity; 20 | import com.jingchen.pulltorefresh.activity.PullableScrollViewActivity; 21 | import com.jingchen.pulltorefresh.activity.PullableTextViewActivity; 22 | import com.jingchen.pulltorefresh.activity.PullableWebViewActivity; 23 | 24 | /** 25 | * 更多详解见博客http://blog.csdn.net/zhongkejingwang/article/details/38868463 26 | * 27 | * @author 陈靖 28 | * 29 | */ 30 | public class MainActivity extends Activity 31 | { 32 | private ListView listView; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) 36 | { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_main); 39 | ((PullToRefreshLayout) findViewById(R.id.refresh_view)) 40 | .setOnRefreshListener(new MyListener()); 41 | listView = (ListView) findViewById(R.id.content_view); 42 | initListView(); 43 | } 44 | 45 | /** 46 | * ListView初始化方法 47 | */ 48 | private void initListView() 49 | { 50 | List items = new ArrayList(); 51 | items.add("可下拉刷新上拉加载的ListView"); 52 | items.add("可下拉刷新上拉加载的GridView"); 53 | items.add("可下拉刷新上拉加载的ExpandableListView"); 54 | items.add("可下拉刷新上拉加载的SrcollView"); 55 | items.add("可下拉刷新上拉加载的WebView"); 56 | items.add("可下拉刷新上拉加载的ImageView"); 57 | items.add("可下拉刷新上拉加载的TextView"); 58 | MyAdapter adapter = new MyAdapter(this, items); 59 | listView.setAdapter(adapter); 60 | listView.setOnItemLongClickListener(new OnItemLongClickListener() 61 | { 62 | 63 | @Override 64 | public boolean onItemLongClick(AdapterView parent, View view, 65 | int position, long id) 66 | { 67 | Toast.makeText( 68 | MainActivity.this, 69 | " LongClick on " 70 | + parent.getAdapter().getItemId(position), 71 | Toast.LENGTH_SHORT).show(); 72 | return true; 73 | } 74 | }); 75 | listView.setOnItemClickListener(new OnItemClickListener() 76 | { 77 | 78 | @Override 79 | public void onItemClick(AdapterView parent, View view, 80 | int position, long id) 81 | { 82 | 83 | Intent it = new Intent(); 84 | switch (position) 85 | { 86 | case 0: 87 | it.setClass(MainActivity.this, 88 | PullableListViewActivity.class); 89 | break; 90 | case 1: 91 | it.setClass(MainActivity.this, 92 | PullableGridViewActivity.class); 93 | break; 94 | case 2: 95 | it.setClass(MainActivity.this, 96 | PullableExpandableListViewActivity.class); 97 | break; 98 | case 3: 99 | it.setClass(MainActivity.this, 100 | PullableScrollViewActivity.class); 101 | break; 102 | case 4: 103 | it.setClass(MainActivity.this, 104 | PullableWebViewActivity.class); 105 | break; 106 | case 5: 107 | it.setClass(MainActivity.this, 108 | PullableImageViewActivity.class); 109 | break; 110 | case 6: 111 | it.setClass(MainActivity.this, 112 | PullableTextViewActivity.class); 113 | break; 114 | 115 | default: 116 | break; 117 | } 118 | startActivity(it); 119 | } 120 | }); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/MyAdapter.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh; 2 | 3 | import java.util.List; 4 | 5 | import android.content.Context; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.BaseAdapter; 10 | import android.widget.TextView; 11 | 12 | public class MyAdapter extends BaseAdapter { 13 | List items; 14 | Context context; 15 | 16 | public MyAdapter(Context context, List items) { 17 | this.context = context; 18 | this.items = items; 19 | } 20 | 21 | @Override 22 | public int getCount() { 23 | return items.size(); 24 | } 25 | 26 | @Override 27 | public Object getItem(int position) { 28 | return items.get(position); 29 | } 30 | 31 | @Override 32 | public long getItemId(int position) { 33 | return position; 34 | } 35 | 36 | @Override 37 | public View getView(int position, View convertView, ViewGroup parent) { 38 | View view = LayoutInflater.from(context).inflate( 39 | R.layout.list_item_layout, null); 40 | TextView tv = (TextView) view.findViewById(R.id.tv); 41 | tv.setText(items.get(position)); 42 | return view; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/MyListener.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import com.jingchen.pulltorefresh.PullToRefreshLayout.OnRefreshListener; 7 | 8 | public class MyListener implements OnRefreshListener 9 | { 10 | 11 | @Override 12 | public void onRefresh(final PullToRefreshLayout pullToRefreshLayout) 13 | { 14 | // 下拉刷新操作 15 | new Handler() 16 | { 17 | @Override 18 | public void handleMessage(Message msg) 19 | { 20 | // 千万别忘了告诉控件刷新完毕了哦! 21 | pullToRefreshLayout.refreshFinish(PullToRefreshLayout.SUCCEED); 22 | } 23 | }.sendEmptyMessageDelayed(0, 5000); 24 | } 25 | 26 | @Override 27 | public void onLoadMore(final PullToRefreshLayout pullToRefreshLayout) 28 | { 29 | // 加载操作 30 | new Handler() 31 | { 32 | @Override 33 | public void handleMessage(Message msg) 34 | { 35 | // 千万别忘了告诉控件加载完毕了哦! 36 | pullToRefreshLayout.loadmoreFinish(PullToRefreshLayout.SUCCEED); 37 | } 38 | }.sendEmptyMessageDelayed(0, 5000); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/PullToRefreshLayout.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh; 2 | 3 | import java.util.Timer; 4 | import java.util.TimerTask; 5 | 6 | import android.app.Activity; 7 | import android.content.Context; 8 | import android.os.AsyncTask; 9 | import android.os.Handler; 10 | import android.os.Message; 11 | import android.util.AttributeSet; 12 | import android.util.Log; 13 | import android.view.MotionEvent; 14 | import android.view.View; 15 | import android.view.ViewGroup; 16 | import android.view.animation.AnimationUtils; 17 | import android.view.animation.LinearInterpolator; 18 | import android.view.animation.RotateAnimation; 19 | import android.widget.RelativeLayout; 20 | import android.widget.TextView; 21 | 22 | import com.jingchen.pulltorefresh.pullableview.Pullable; 23 | 24 | /** 25 | * 自定义的布局,用来管理三个子控件,其中一个是下拉头,一个是包含内容的pullableView(可以是实现Pullable接口的的任何View), 26 | * 还有一个上拉头,更多详解见博客http://blog.csdn.net/zhongkejingwang/article/details/38868463 27 | * 28 | * @author 陈靖 29 | */ 30 | public class PullToRefreshLayout extends RelativeLayout 31 | { 32 | public static final String TAG = "PullToRefreshLayout"; 33 | // 初始状态 34 | public static final int INIT = 0; 35 | // 释放刷新 36 | public static final int RELEASE_TO_REFRESH = 1; 37 | // 正在刷新 38 | public static final int REFRESHING = 2; 39 | // 释放加载 40 | public static final int RELEASE_TO_LOAD = 3; 41 | // 正在加载 42 | public static final int LOADING = 4; 43 | // 操作完毕 44 | public static final int DONE = 5; 45 | // 当前状态 46 | private int state = INIT; 47 | // 刷新回调接口 48 | private OnRefreshListener mListener; 49 | // 刷新成功 50 | public static final int SUCCEED = 0; 51 | // 刷新失败 52 | public static final int FAIL = 1; 53 | // 按下Y坐标,上一个事件点Y坐标 54 | private float downY, lastY; 55 | 56 | // 下拉的距离。注意:pullDownY和pullUpY不可能同时不为0 57 | public float pullDownY = 0; 58 | // 上拉的距离 59 | private float pullUpY = 0; 60 | 61 | // 释放刷新的距离 62 | private float refreshDist = 200; 63 | // 释放加载的距离 64 | private float loadmoreDist = 200; 65 | 66 | private MyTimer timer; 67 | // 回滚速度 68 | public float MOVE_SPEED = 8; 69 | // 第一次执行布局 70 | private boolean isLayout = false; 71 | // 在刷新过程中滑动操作 72 | private boolean isTouch = false; 73 | // 手指滑动距离与下拉头的滑动距离比,中间会随正切函数变化 74 | private float radio = 2; 75 | 76 | // 下拉箭头的转180°动画 77 | private RotateAnimation rotateAnimation; 78 | // 均匀旋转动画 79 | private RotateAnimation refreshingAnimation; 80 | 81 | // 下拉头 82 | private View refreshView; 83 | // 下拉的箭头 84 | private View pullView; 85 | // 正在刷新的图标 86 | private View refreshingView; 87 | // 刷新结果图标 88 | private View refreshStateImageView; 89 | // 刷新结果:成功或失败 90 | private TextView refreshStateTextView; 91 | 92 | // 上拉头 93 | private View loadmoreView; 94 | // 上拉的箭头 95 | private View pullUpView; 96 | // 正在加载的图标 97 | private View loadingView; 98 | // 加载结果图标 99 | private View loadStateImageView; 100 | // 加载结果:成功或失败 101 | private TextView loadStateTextView; 102 | 103 | // 实现了Pullable接口的View 104 | private View pullableView; 105 | // 过滤多点触碰 106 | private int mEvents; 107 | // 这两个变量用来控制pull的方向,如果不加控制,当情况满足可上拉又可下拉时没法下拉 108 | private boolean canPullDown = true; 109 | private boolean canPullUp = true; 110 | 111 | private Context mContext; 112 | 113 | /** 114 | * 执行自动回滚的handler 115 | */ 116 | Handler updateHandler = new Handler() 117 | { 118 | 119 | @Override 120 | public void handleMessage(Message msg) 121 | { 122 | // 回弹速度随下拉距离moveDeltaY增大而增大 123 | MOVE_SPEED = (float) (8 + 5 * Math.tan(Math.PI / 2 124 | / getMeasuredHeight() * (pullDownY + Math.abs(pullUpY)))); 125 | if (!isTouch) 126 | { 127 | // 正在刷新,且没有往上推的话则悬停,显示"正在刷新..." 128 | if (state == REFRESHING && pullDownY <= refreshDist) 129 | { 130 | pullDownY = refreshDist; 131 | timer.cancel(); 132 | } else if (state == LOADING && -pullUpY <= loadmoreDist) 133 | { 134 | pullUpY = -loadmoreDist; 135 | timer.cancel(); 136 | } 137 | 138 | } 139 | if (pullDownY > 0) 140 | pullDownY -= MOVE_SPEED; 141 | else if (pullUpY < 0) 142 | pullUpY += MOVE_SPEED; 143 | if (pullDownY < 0) 144 | { 145 | // 已完成回弹 146 | pullDownY = 0; 147 | pullView.clearAnimation(); 148 | // 隐藏下拉头时有可能还在刷新,只有当前状态不是正在刷新时才改变状态 149 | if (state != REFRESHING && state != LOADING) 150 | changeState(INIT); 151 | timer.cancel(); 152 | requestLayout(); 153 | } 154 | if (pullUpY > 0) 155 | { 156 | // 已完成回弹 157 | pullUpY = 0; 158 | pullUpView.clearAnimation(); 159 | // 隐藏上拉头时有可能还在刷新,只有当前状态不是正在刷新时才改变状态 160 | if (state != REFRESHING && state != LOADING) 161 | changeState(INIT); 162 | timer.cancel(); 163 | requestLayout(); 164 | } 165 | Log.d("handle", "handle"); 166 | // 刷新布局,会自动调用onLayout 167 | requestLayout(); 168 | // 没有拖拉或者回弹完成 169 | if (pullDownY + Math.abs(pullUpY) == 0) 170 | timer.cancel(); 171 | } 172 | 173 | }; 174 | 175 | public void setOnRefreshListener(OnRefreshListener listener) 176 | { 177 | mListener = listener; 178 | } 179 | 180 | public PullToRefreshLayout(Context context) 181 | { 182 | super(context); 183 | initView(context); 184 | } 185 | 186 | public PullToRefreshLayout(Context context, AttributeSet attrs) 187 | { 188 | super(context, attrs); 189 | initView(context); 190 | } 191 | 192 | public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyle) 193 | { 194 | super(context, attrs, defStyle); 195 | initView(context); 196 | } 197 | 198 | private void initView(Context context) 199 | { 200 | mContext = context; 201 | timer = new MyTimer(updateHandler); 202 | rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation( 203 | context, R.anim.reverse_anim); 204 | refreshingAnimation = (RotateAnimation) AnimationUtils.loadAnimation( 205 | context, R.anim.rotating); 206 | // 添加匀速转动动画 207 | LinearInterpolator lir = new LinearInterpolator(); 208 | rotateAnimation.setInterpolator(lir); 209 | refreshingAnimation.setInterpolator(lir); 210 | } 211 | 212 | private void hide() 213 | { 214 | timer.schedule(5); 215 | } 216 | 217 | /** 218 | * 完成刷新操作,显示刷新结果。注意:刷新完成后一定要调用这个方法 219 | */ 220 | /** 221 | * @param refreshResult 222 | * PullToRefreshLayout.SUCCEED代表成功,PullToRefreshLayout.FAIL代表失败 223 | */ 224 | public void refreshFinish(int refreshResult) 225 | { 226 | refreshingView.clearAnimation(); 227 | refreshingView.setVisibility(View.GONE); 228 | switch (refreshResult) 229 | { 230 | case SUCCEED: 231 | // 刷新成功 232 | refreshStateImageView.setVisibility(View.VISIBLE); 233 | refreshStateTextView.setText(R.string.refresh_succeed); 234 | refreshStateImageView 235 | .setBackgroundResource(R.drawable.refresh_succeed); 236 | break; 237 | case FAIL: 238 | default: 239 | // 刷新失败 240 | refreshStateImageView.setVisibility(View.VISIBLE); 241 | refreshStateTextView.setText(R.string.refresh_fail); 242 | refreshStateImageView 243 | .setBackgroundResource(R.drawable.refresh_failed); 244 | break; 245 | } 246 | if (pullDownY > 0) 247 | { 248 | // 刷新结果停留1秒 249 | new Handler() 250 | { 251 | @Override 252 | public void handleMessage(Message msg) 253 | { 254 | changeState(DONE); 255 | hide(); 256 | } 257 | }.sendEmptyMessageDelayed(0, 1000); 258 | } else 259 | { 260 | changeState(DONE); 261 | hide(); 262 | } 263 | } 264 | 265 | /** 266 | * 加载完毕,显示加载结果。注意:加载完成后一定要调用这个方法 267 | * 268 | * @param refreshResult 269 | * PullToRefreshLayout.SUCCEED代表成功,PullToRefreshLayout.FAIL代表失败 270 | */ 271 | public void loadmoreFinish(int refreshResult) 272 | { 273 | loadingView.clearAnimation(); 274 | loadingView.setVisibility(View.GONE); 275 | switch (refreshResult) 276 | { 277 | case SUCCEED: 278 | // 加载成功 279 | loadStateImageView.setVisibility(View.VISIBLE); 280 | loadStateTextView.setText(R.string.load_succeed); 281 | loadStateImageView.setBackgroundResource(R.drawable.load_succeed); 282 | break; 283 | case FAIL: 284 | default: 285 | // 加载失败 286 | loadStateImageView.setVisibility(View.VISIBLE); 287 | loadStateTextView.setText(R.string.load_fail); 288 | loadStateImageView.setBackgroundResource(R.drawable.load_failed); 289 | break; 290 | } 291 | if (pullUpY < 0) 292 | { 293 | // 刷新结果停留1秒 294 | new Handler() 295 | { 296 | @Override 297 | public void handleMessage(Message msg) 298 | { 299 | changeState(DONE); 300 | hide(); 301 | } 302 | }.sendEmptyMessageDelayed(0, 1000); 303 | } else 304 | { 305 | changeState(DONE); 306 | hide(); 307 | } 308 | } 309 | 310 | private void changeState(int to) 311 | { 312 | state = to; 313 | switch (state) 314 | { 315 | case INIT: 316 | // 下拉布局初始状态 317 | refreshStateImageView.setVisibility(View.GONE); 318 | refreshStateTextView.setText(R.string.pull_to_refresh); 319 | pullView.clearAnimation(); 320 | pullView.setVisibility(View.VISIBLE); 321 | // 上拉布局初始状态 322 | loadStateImageView.setVisibility(View.GONE); 323 | loadStateTextView.setText(R.string.pullup_to_load); 324 | pullUpView.clearAnimation(); 325 | pullUpView.setVisibility(View.VISIBLE); 326 | break; 327 | case RELEASE_TO_REFRESH: 328 | // 释放刷新状态 329 | refreshStateTextView.setText(R.string.release_to_refresh); 330 | pullView.startAnimation(rotateAnimation); 331 | break; 332 | case REFRESHING: 333 | // 正在刷新状态 334 | pullView.clearAnimation(); 335 | refreshingView.setVisibility(View.VISIBLE); 336 | pullView.setVisibility(View.INVISIBLE); 337 | refreshingView.startAnimation(refreshingAnimation); 338 | refreshStateTextView.setText(R.string.refreshing); 339 | break; 340 | case RELEASE_TO_LOAD: 341 | // 释放加载状态 342 | loadStateTextView.setText(R.string.release_to_load); 343 | pullUpView.startAnimation(rotateAnimation); 344 | break; 345 | case LOADING: 346 | // 正在加载状态 347 | pullUpView.clearAnimation(); 348 | loadingView.setVisibility(View.VISIBLE); 349 | pullUpView.setVisibility(View.INVISIBLE); 350 | loadingView.startAnimation(refreshingAnimation); 351 | loadStateTextView.setText(R.string.loading); 352 | break; 353 | case DONE: 354 | // 刷新或加载完毕,啥都不做 355 | break; 356 | } 357 | } 358 | 359 | /** 360 | * 不限制上拉或下拉 361 | */ 362 | private void releasePull() 363 | { 364 | canPullDown = true; 365 | canPullUp = true; 366 | } 367 | 368 | /* 369 | * (非 Javadoc)由父控件决定是否分发事件,防止事件冲突 370 | * 371 | * @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent) 372 | */ 373 | @Override 374 | public boolean dispatchTouchEvent(MotionEvent ev) 375 | { 376 | switch (ev.getActionMasked()) 377 | { 378 | case MotionEvent.ACTION_DOWN: 379 | downY = ev.getY(); 380 | lastY = downY; 381 | timer.cancel(); 382 | mEvents = 0; 383 | releasePull(); 384 | break; 385 | case MotionEvent.ACTION_POINTER_DOWN: 386 | case MotionEvent.ACTION_POINTER_UP: 387 | // 过滤多点触碰 388 | mEvents = -1; 389 | break; 390 | case MotionEvent.ACTION_MOVE: 391 | if (mEvents == 0) 392 | { 393 | if (pullDownY > 0 394 | || (((Pullable) pullableView).canPullDown() 395 | && canPullDown && state != LOADING)) 396 | { 397 | // 可以下拉,正在加载时不能下拉 398 | // 对实际滑动距离做缩小,造成用力拉的感觉 399 | pullDownY = pullDownY + (ev.getY() - lastY) / radio; 400 | if (pullDownY < 0) 401 | { 402 | pullDownY = 0; 403 | canPullDown = false; 404 | canPullUp = true; 405 | } 406 | if (pullDownY > getMeasuredHeight()) 407 | pullDownY = getMeasuredHeight(); 408 | if (state == REFRESHING) 409 | { 410 | // 正在刷新的时候触摸移动 411 | isTouch = true; 412 | } 413 | } else if (pullUpY < 0 414 | || (((Pullable) pullableView).canPullUp() && canPullUp && state != REFRESHING)) 415 | { 416 | // 可以上拉,正在刷新时不能上拉 417 | pullUpY = pullUpY + (ev.getY() - lastY) / radio; 418 | if (pullUpY > 0) 419 | { 420 | pullUpY = 0; 421 | canPullDown = true; 422 | canPullUp = false; 423 | } 424 | if (pullUpY < -getMeasuredHeight()) 425 | pullUpY = -getMeasuredHeight(); 426 | if (state == LOADING) 427 | { 428 | // 正在加载的时候触摸移动 429 | isTouch = true; 430 | } 431 | } else 432 | releasePull(); 433 | } else 434 | mEvents = 0; 435 | lastY = ev.getY(); 436 | // 根据下拉距离改变比例 437 | radio = (float) (2 + 2 * Math.tan(Math.PI / 2 / getMeasuredHeight() 438 | * (pullDownY + Math.abs(pullUpY)))); 439 | if (pullDownY > 0 || pullUpY < 0) 440 | requestLayout(); 441 | if (pullDownY > 0) 442 | { 443 | if (pullDownY <= refreshDist 444 | && (state == RELEASE_TO_REFRESH || state == DONE)) 445 | { 446 | // 如果下拉距离没达到刷新的距离且当前状态是释放刷新,改变状态为下拉刷新 447 | changeState(INIT); 448 | } 449 | if (pullDownY >= refreshDist && state == INIT) 450 | { 451 | // 如果下拉距离达到刷新的距离且当前状态是初始状态刷新,改变状态为释放刷新 452 | changeState(RELEASE_TO_REFRESH); 453 | } 454 | } else if (pullUpY < 0) 455 | { 456 | // 下面是判断上拉加载的,同上,注意pullUpY是负值 457 | if (-pullUpY <= loadmoreDist 458 | && (state == RELEASE_TO_LOAD || state == DONE)) 459 | { 460 | changeState(INIT); 461 | } 462 | // 上拉操作 463 | if (-pullUpY >= loadmoreDist && state == INIT) 464 | { 465 | changeState(RELEASE_TO_LOAD); 466 | } 467 | 468 | } 469 | // 因为刷新和加载操作不能同时进行,所以pullDownY和pullUpY不会同时不为0,因此这里用(pullDownY + 470 | // Math.abs(pullUpY))就可以不对当前状态作区分了 471 | if ((pullDownY + Math.abs(pullUpY)) > 8) 472 | { 473 | // 防止下拉过程中误触发长按事件和点击事件 474 | ev.setAction(MotionEvent.ACTION_CANCEL); 475 | } 476 | break; 477 | case MotionEvent.ACTION_UP: 478 | if (pullDownY > refreshDist || -pullUpY > loadmoreDist) 479 | // 正在刷新时往下拉(正在加载时往上拉),释放后下拉头(上拉头)不隐藏 480 | { 481 | isTouch = false; 482 | } 483 | if (state == RELEASE_TO_REFRESH) 484 | { 485 | changeState(REFRESHING); 486 | // 刷新操作 487 | if (mListener != null) 488 | mListener.onRefresh(this); 489 | } else if (state == RELEASE_TO_LOAD) 490 | { 491 | changeState(LOADING); 492 | // 加载操作 493 | if (mListener != null) 494 | mListener.onLoadMore(this); 495 | } 496 | hide(); 497 | default: 498 | break; 499 | } 500 | // 事件分发交给父类 501 | super.dispatchTouchEvent(ev); 502 | return true; 503 | } 504 | 505 | /** 506 | * @author chenjing 自动模拟手指滑动的task 507 | * 508 | */ 509 | private class AutoRefreshAndLoadTask extends 510 | AsyncTask 511 | { 512 | 513 | @Override 514 | protected String doInBackground(Integer... params) 515 | { 516 | while (pullDownY < 4 / 3 * refreshDist) 517 | { 518 | pullDownY += MOVE_SPEED; 519 | publishProgress(pullDownY); 520 | try 521 | { 522 | Thread.sleep(params[0]); 523 | } catch (InterruptedException e) 524 | { 525 | e.printStackTrace(); 526 | } 527 | } 528 | return null; 529 | } 530 | 531 | @Override 532 | protected void onPostExecute(String result) 533 | { 534 | changeState(REFRESHING); 535 | // 刷新操作 536 | if (mListener != null) 537 | mListener.onRefresh(PullToRefreshLayout.this); 538 | hide(); 539 | } 540 | 541 | @Override 542 | protected void onProgressUpdate(Float... values) 543 | { 544 | if (pullDownY > refreshDist) 545 | changeState(RELEASE_TO_REFRESH); 546 | requestLayout(); 547 | } 548 | 549 | } 550 | 551 | /** 552 | * 自动刷新 553 | */ 554 | public void autoRefresh() 555 | { 556 | AutoRefreshAndLoadTask task = new AutoRefreshAndLoadTask(); 557 | task.execute(20); 558 | } 559 | 560 | /** 561 | * 自动加载 562 | */ 563 | public void autoLoad() 564 | { 565 | pullUpY = -loadmoreDist; 566 | requestLayout(); 567 | changeState(LOADING); 568 | // 加载操作 569 | if (mListener != null) 570 | mListener.onLoadMore(this); 571 | } 572 | 573 | private void initView() 574 | { 575 | // 初始化下拉布局 576 | pullView = refreshView.findViewById(R.id.pull_icon); 577 | refreshStateTextView = (TextView) refreshView 578 | .findViewById(R.id.state_tv); 579 | refreshingView = refreshView.findViewById(R.id.refreshing_icon); 580 | refreshStateImageView = refreshView.findViewById(R.id.state_iv); 581 | // 初始化上拉布局 582 | pullUpView = loadmoreView.findViewById(R.id.pullup_icon); 583 | loadStateTextView = (TextView) loadmoreView 584 | .findViewById(R.id.loadstate_tv); 585 | loadingView = loadmoreView.findViewById(R.id.loading_icon); 586 | loadStateImageView = loadmoreView.findViewById(R.id.loadstate_iv); 587 | } 588 | 589 | @Override 590 | protected void onLayout(boolean changed, int l, int t, int r, int b) 591 | { 592 | Log.d("Test", "Test"); 593 | if (!isLayout) 594 | { 595 | // 这里是第一次进来的时候做一些初始化 596 | refreshView = getChildAt(0); 597 | pullableView = getChildAt(1); 598 | loadmoreView = getChildAt(2); 599 | isLayout = true; 600 | initView(); 601 | refreshDist = ((ViewGroup) refreshView).getChildAt(0) 602 | .getMeasuredHeight(); 603 | loadmoreDist = ((ViewGroup) loadmoreView).getChildAt(0) 604 | .getMeasuredHeight(); 605 | } 606 | // 改变子控件的布局,这里直接用(pullDownY + pullUpY)作为偏移量,这样就可以不对当前状态作区分 607 | refreshView.layout(0, 608 | (int) (pullDownY + pullUpY) - refreshView.getMeasuredHeight(), 609 | refreshView.getMeasuredWidth(), (int) (pullDownY + pullUpY)); 610 | pullableView.layout(0, (int) (pullDownY + pullUpY), 611 | pullableView.getMeasuredWidth(), (int) (pullDownY + pullUpY) 612 | + pullableView.getMeasuredHeight()); 613 | loadmoreView.layout(0, 614 | (int) (pullDownY + pullUpY) + pullableView.getMeasuredHeight(), 615 | loadmoreView.getMeasuredWidth(), 616 | (int) (pullDownY + pullUpY) + pullableView.getMeasuredHeight() 617 | + loadmoreView.getMeasuredHeight()); 618 | } 619 | 620 | class MyTimer 621 | { 622 | private Handler handler; 623 | private Timer timer; 624 | private MyTask mTask; 625 | 626 | public MyTimer(Handler handler) 627 | { 628 | this.handler = handler; 629 | timer = new Timer(); 630 | } 631 | 632 | public void schedule(long period) 633 | { 634 | if (mTask != null) 635 | { 636 | mTask.cancel(); 637 | mTask = null; 638 | } 639 | mTask = new MyTask(handler); 640 | timer.schedule(mTask, 0, period); 641 | } 642 | 643 | public void cancel() 644 | { 645 | if (mTask != null) 646 | { 647 | mTask.cancel(); 648 | mTask = null; 649 | } 650 | } 651 | 652 | class MyTask extends TimerTask 653 | { 654 | private Handler handler; 655 | 656 | public MyTask(Handler handler) 657 | { 658 | this.handler = handler; 659 | } 660 | 661 | @Override 662 | public void run() 663 | { 664 | handler.obtainMessage().sendToTarget(); 665 | } 666 | 667 | } 668 | } 669 | 670 | /** 671 | * 刷新加载回调接口 672 | * 673 | * @author chenjing 674 | * 675 | */ 676 | public interface OnRefreshListener 677 | { 678 | /** 679 | * 刷新操作 680 | */ 681 | void onRefresh(PullToRefreshLayout pullToRefreshLayout); 682 | 683 | /** 684 | * 加载操作 685 | */ 686 | void onLoadMore(PullToRefreshLayout pullToRefreshLayout); 687 | } 688 | 689 | } 690 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/activity/PullableExpandableListViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.activity; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.AdapterView; 10 | import android.widget.AdapterView.OnItemLongClickListener; 11 | import android.widget.BaseExpandableListAdapter; 12 | import android.widget.ExpandableListView; 13 | import android.widget.ExpandableListView.OnChildClickListener; 14 | import android.widget.ExpandableListView.OnGroupClickListener; 15 | import android.widget.TextView; 16 | import android.widget.Toast; 17 | 18 | import com.jingchen.pulltorefresh.MyListener; 19 | import com.jingchen.pulltorefresh.PullToRefreshLayout; 20 | import com.jingchen.pulltorefresh.R; 21 | 22 | public class PullableExpandableListViewActivity extends Activity 23 | { 24 | ExpandableListView expandableListView; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) 28 | { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_expandablelistview); 31 | ((PullToRefreshLayout) findViewById(R.id.refresh_view)) 32 | .setOnRefreshListener(new MyListener()); 33 | expandableListView = (ExpandableListView) findViewById(R.id.content_view); 34 | initExpandableListView(); 35 | } 36 | 37 | /** 38 | * ExpandableListView初始化方法 39 | */ 40 | private void initExpandableListView() 41 | { 42 | expandableListView.setAdapter(new ExpandableListAdapter(this)); 43 | expandableListView.setOnChildClickListener(new OnChildClickListener() 44 | { 45 | 46 | @Override 47 | public boolean onChildClick(ExpandableListView parent, View v, 48 | int groupPosition, int childPosition, long id) 49 | { 50 | Toast.makeText( 51 | PullableExpandableListViewActivity.this, 52 | " Click on group " + groupPosition + " item " 53 | + childPosition, Toast.LENGTH_SHORT).show(); 54 | return true; 55 | } 56 | }); 57 | expandableListView 58 | .setOnItemLongClickListener(new OnItemLongClickListener() 59 | { 60 | 61 | @Override 62 | public boolean onItemLongClick(AdapterView parent, 63 | View view, int position, long id) 64 | { 65 | Toast.makeText( 66 | PullableExpandableListViewActivity.this, 67 | "LongClick on " 68 | + parent.getAdapter().getItemId( 69 | position), Toast.LENGTH_SHORT) 70 | .show(); 71 | return true; 72 | } 73 | }); 74 | expandableListView.setOnGroupClickListener(new OnGroupClickListener() 75 | { 76 | 77 | @Override 78 | public boolean onGroupClick(ExpandableListView parent, View v, 79 | int groupPosition, long id) 80 | { 81 | if (parent.isGroupExpanded(groupPosition)) 82 | { 83 | // 如果展开则关闭 84 | parent.collapseGroup(groupPosition); 85 | } else 86 | { 87 | // 如果关闭则打开,注意这里是手动打开不要默认滚动否则会有bug 88 | parent.expandGroup(groupPosition); 89 | } 90 | return true; 91 | } 92 | }); 93 | } 94 | 95 | class ExpandableListAdapter extends BaseExpandableListAdapter 96 | { 97 | private String[] groupsStrings;// = new String[] { "这里是group 0", 98 | // "这里是group 1", "这里是group 2" }; 99 | private String[][] groupItems; 100 | private Context context; 101 | 102 | public ExpandableListAdapter(Context context) 103 | { 104 | this.context = context; 105 | groupsStrings = new String[8]; 106 | for (int i = 0; i < groupsStrings.length; i++) 107 | { 108 | groupsStrings[i] = new String("这里是group " + i); 109 | } 110 | groupItems = new String[8][8]; 111 | for (int i = 0; i < groupItems.length; i++) 112 | for (int j = 0; j < groupItems[i].length; j++) 113 | { 114 | groupItems[i][j] = new String("这里是group " + i + "里的item " 115 | + j); 116 | } 117 | } 118 | 119 | @Override 120 | public int getGroupCount() 121 | { 122 | return groupsStrings.length; 123 | } 124 | 125 | @Override 126 | public int getChildrenCount(int groupPosition) 127 | { 128 | return groupItems[groupPosition].length; 129 | } 130 | 131 | @Override 132 | public Object getGroup(int groupPosition) 133 | { 134 | return groupsStrings[groupPosition]; 135 | } 136 | 137 | @Override 138 | public Object getChild(int groupPosition, int childPosition) 139 | { 140 | return groupItems[groupPosition][childPosition]; 141 | } 142 | 143 | @Override 144 | public long getGroupId(int groupPosition) 145 | { 146 | return groupPosition; 147 | } 148 | 149 | @Override 150 | public long getChildId(int groupPosition, int childPosition) 151 | { 152 | return childPosition; 153 | } 154 | 155 | @Override 156 | public boolean hasStableIds() 157 | { 158 | return true; 159 | } 160 | 161 | @Override 162 | public View getGroupView(int groupPosition, boolean isExpanded, 163 | View convertView, ViewGroup parent) 164 | { 165 | View view = LayoutInflater.from(context).inflate( 166 | R.layout.list_item_layout, null); 167 | TextView tv = (TextView) view.findViewById(R.id.tv); 168 | tv.setText(groupsStrings[groupPosition]); 169 | return view; 170 | } 171 | 172 | @Override 173 | public View getChildView(int groupPosition, int childPosition, 174 | boolean isLastChild, View convertView, ViewGroup parent) 175 | { 176 | View view = LayoutInflater.from(context).inflate( 177 | R.layout.list_item_layout, null); 178 | TextView tv = (TextView) view.findViewById(R.id.tv); 179 | tv.setText(groupItems[groupPosition][childPosition]); 180 | return view; 181 | } 182 | 183 | @Override 184 | public boolean isChildSelectable(int groupPosition, int childPosition) 185 | { 186 | return true; 187 | } 188 | 189 | } 190 | 191 | } 192 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/activity/PullableGridViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.activity; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import android.app.Activity; 7 | import android.os.Bundle; 8 | import android.view.View; 9 | import android.widget.AdapterView; 10 | import android.widget.AdapterView.OnItemClickListener; 11 | import android.widget.AdapterView.OnItemLongClickListener; 12 | import android.widget.GridView; 13 | import android.widget.Toast; 14 | 15 | import com.jingchen.pulltorefresh.MyAdapter; 16 | import com.jingchen.pulltorefresh.MyListener; 17 | import com.jingchen.pulltorefresh.PullToRefreshLayout; 18 | import com.jingchen.pulltorefresh.R; 19 | 20 | public class PullableGridViewActivity extends Activity 21 | { 22 | GridView gridView; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) 26 | { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_gridview); 29 | ((PullToRefreshLayout) findViewById(R.id.refresh_view)) 30 | .setOnRefreshListener(new MyListener()); 31 | gridView = (GridView) findViewById(R.id.content_view); 32 | initGridView(); 33 | } 34 | 35 | /** 36 | * GridView初始化方法 37 | */ 38 | private void initGridView() 39 | { 40 | List items = new ArrayList(); 41 | for (int i = 0; i < 30; i++) 42 | { 43 | items.add("这里是item " + i); 44 | } 45 | MyAdapter adapter = new MyAdapter(this, items); 46 | gridView.setAdapter(adapter); 47 | gridView.setOnItemLongClickListener(new OnItemLongClickListener() 48 | { 49 | 50 | @Override 51 | public boolean onItemLongClick(AdapterView parent, View view, 52 | int position, long id) 53 | { 54 | Toast.makeText( 55 | PullableGridViewActivity.this, 56 | "LongClick on " 57 | + parent.getAdapter().getItemId(position), 58 | Toast.LENGTH_SHORT).show(); 59 | return true; 60 | } 61 | }); 62 | gridView.setOnItemClickListener(new OnItemClickListener() 63 | { 64 | 65 | @Override 66 | public void onItemClick(AdapterView parent, View view, 67 | int position, long id) 68 | { 69 | Toast.makeText(PullableGridViewActivity.this, 70 | " Click on " + parent.getAdapter().getItemId(position), 71 | Toast.LENGTH_SHORT).show(); 72 | } 73 | }); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/activity/PullableImageViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.activity; 2 | 3 | import com.jingchen.pulltorefresh.MyListener; 4 | import com.jingchen.pulltorefresh.PullToRefreshLayout; 5 | import com.jingchen.pulltorefresh.R; 6 | 7 | import android.app.Activity; 8 | import android.os.Bundle; 9 | 10 | public class PullableImageViewActivity extends Activity 11 | { 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) 14 | { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_imageview); 17 | ((PullToRefreshLayout) findViewById(R.id.refresh_view)) 18 | .setOnRefreshListener(new MyListener()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/activity/PullableListViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.activity; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import android.app.Activity; 7 | import android.os.Bundle; 8 | import android.view.View; 9 | import android.widget.AdapterView; 10 | import android.widget.AdapterView.OnItemClickListener; 11 | import android.widget.AdapterView.OnItemLongClickListener; 12 | import android.widget.ListView; 13 | import android.widget.Toast; 14 | 15 | import com.jingchen.pulltorefresh.MyAdapter; 16 | import com.jingchen.pulltorefresh.MyListener; 17 | import com.jingchen.pulltorefresh.PullToRefreshLayout; 18 | import com.jingchen.pulltorefresh.R; 19 | 20 | public class PullableListViewActivity extends Activity 21 | { 22 | private ListView listView; 23 | private PullToRefreshLayout ptrl; 24 | private boolean isFirstIn = true; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) 28 | { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_listview); 31 | ptrl = ((PullToRefreshLayout) findViewById(R.id.refresh_view)); 32 | ptrl.setOnRefreshListener(new MyListener()); 33 | listView = (ListView) findViewById(R.id.content_view); 34 | initListView(); 35 | } 36 | 37 | @Override 38 | public void onWindowFocusChanged(boolean hasFocus) 39 | { 40 | super.onWindowFocusChanged(hasFocus); 41 | // 第一次进入自动刷新 42 | if (isFirstIn) 43 | { 44 | ptrl.autoRefresh(); 45 | isFirstIn = false; 46 | } 47 | } 48 | 49 | /** 50 | * ListView初始化方法 51 | */ 52 | private void initListView() 53 | { 54 | List items = new ArrayList(); 55 | for (int i = 0; i < 30; i++) 56 | { 57 | items.add("这里是item " + i); 58 | } 59 | MyAdapter adapter = new MyAdapter(this, items); 60 | listView.setAdapter(adapter); 61 | listView.setOnItemLongClickListener(new OnItemLongClickListener() 62 | { 63 | 64 | @Override 65 | public boolean onItemLongClick(AdapterView parent, View view, 66 | int position, long id) 67 | { 68 | Toast.makeText( 69 | PullableListViewActivity.this, 70 | "LongClick on " 71 | + parent.getAdapter().getItemId(position), 72 | Toast.LENGTH_SHORT).show(); 73 | return true; 74 | } 75 | }); 76 | listView.setOnItemClickListener(new OnItemClickListener() 77 | { 78 | 79 | @Override 80 | public void onItemClick(AdapterView parent, View view, 81 | int position, long id) 82 | { 83 | Toast.makeText(PullableListViewActivity.this, 84 | " Click on " + parent.getAdapter().getItemId(position), 85 | Toast.LENGTH_SHORT).show(); 86 | } 87 | }); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/activity/PullableScrollViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.activity; 2 | 3 | import com.jingchen.pulltorefresh.MyListener; 4 | import com.jingchen.pulltorefresh.PullToRefreshLayout; 5 | import com.jingchen.pulltorefresh.R; 6 | 7 | import android.app.Activity; 8 | import android.os.Bundle; 9 | 10 | public class PullableScrollViewActivity extends Activity 11 | { 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) 14 | { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_scrollview); 17 | ((PullToRefreshLayout) findViewById(R.id.refresh_view)) 18 | .setOnRefreshListener(new MyListener()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/activity/PullableTextViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.activity; 2 | 3 | import com.jingchen.pulltorefresh.MyListener; 4 | import com.jingchen.pulltorefresh.PullToRefreshLayout; 5 | import com.jingchen.pulltorefresh.R; 6 | 7 | import android.app.Activity; 8 | import android.os.Bundle; 9 | 10 | public class PullableTextViewActivity extends Activity 11 | { 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) 14 | { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_textview); 17 | ((PullToRefreshLayout) findViewById(R.id.refresh_view)) 18 | .setOnRefreshListener(new MyListener()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/activity/PullableWebViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.activity; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.webkit.WebView; 6 | 7 | import com.jingchen.pulltorefresh.MyListener; 8 | import com.jingchen.pulltorefresh.PullToRefreshLayout; 9 | import com.jingchen.pulltorefresh.R; 10 | 11 | public class PullableWebViewActivity extends Activity 12 | { 13 | WebView webView; 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) 17 | { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_webview); 20 | ((PullToRefreshLayout) findViewById(R.id.refresh_view)) 21 | .setOnRefreshListener(new MyListener()); 22 | webView = (WebView) findViewById(R.id.content_view); 23 | webView.loadUrl("http://blog.csdn.net/zhongkejingwang"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/pullableview/Pullable.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.pullableview; 2 | 3 | public interface Pullable 4 | { 5 | /** 6 | * 判断是否可以下拉,如果不需要下拉功能可以直接return false 7 | * 8 | * @return true如果可以下拉否则返回false 9 | */ 10 | boolean canPullDown(); 11 | 12 | /** 13 | * 判断是否可以上拉,如果不需要上拉功能可以直接return false 14 | * 15 | * @return true如果可以上拉否则返回false 16 | */ 17 | boolean canPullUp(); 18 | } 19 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/pullableview/PullableExpandableListView.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.pullableview; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ExpandableListView; 6 | 7 | public class PullableExpandableListView extends ExpandableListView implements 8 | Pullable 9 | { 10 | 11 | public PullableExpandableListView(Context context) 12 | { 13 | super(context); 14 | } 15 | 16 | public PullableExpandableListView(Context context, AttributeSet attrs) 17 | { 18 | super(context, attrs); 19 | } 20 | 21 | public PullableExpandableListView(Context context, AttributeSet attrs, 22 | int defStyle) 23 | { 24 | super(context, attrs, defStyle); 25 | } 26 | 27 | @Override 28 | public boolean canPullDown() 29 | { 30 | if (getCount() == 0) 31 | { 32 | // 没有item的时候也可以下拉刷新 33 | return true; 34 | } else if (getFirstVisiblePosition() == 0 35 | && getChildAt(0).getTop() >= 0) 36 | { 37 | // 滑到顶部了 38 | return true; 39 | } else 40 | return false; 41 | } 42 | 43 | @Override 44 | public boolean canPullUp() 45 | { 46 | if (getCount() == 0) 47 | { 48 | // 没有item的时候也可以上拉加载 49 | return true; 50 | } else if (getLastVisiblePosition() == (getCount() - 1)) 51 | { 52 | // 滑到底部了 53 | if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null 54 | && getChildAt( 55 | getLastVisiblePosition() 56 | - getFirstVisiblePosition()).getBottom() <= getMeasuredHeight()) 57 | return true; 58 | } 59 | return false; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/pullableview/PullableGridView.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.pullableview; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.GridView; 6 | 7 | public class PullableGridView extends GridView implements Pullable 8 | { 9 | 10 | public PullableGridView(Context context) 11 | { 12 | super(context); 13 | } 14 | 15 | public PullableGridView(Context context, AttributeSet attrs) 16 | { 17 | super(context, attrs); 18 | } 19 | 20 | public PullableGridView(Context context, AttributeSet attrs, int defStyle) 21 | { 22 | super(context, attrs, defStyle); 23 | } 24 | 25 | @Override 26 | public boolean canPullDown() 27 | { 28 | if (getCount() == 0) 29 | { 30 | // 没有item的时候也可以下拉刷新 31 | return true; 32 | } else if (getFirstVisiblePosition() == 0 33 | && getChildAt(0).getTop() >= 0) 34 | { 35 | // 滑到顶部了 36 | return true; 37 | } else 38 | return false; 39 | } 40 | 41 | @Override 42 | public boolean canPullUp() 43 | { 44 | if (getCount() == 0) 45 | { 46 | // 没有item的时候也可以上拉加载 47 | return true; 48 | } else if (getLastVisiblePosition() == (getCount() - 1)) 49 | { 50 | // 滑到底部了 51 | if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null 52 | && getChildAt( 53 | getLastVisiblePosition() 54 | - getFirstVisiblePosition()).getBottom() <= getMeasuredHeight()) 55 | return true; 56 | } 57 | return false; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/pullableview/PullableImageView.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.pullableview; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ImageView; 6 | 7 | 8 | public class PullableImageView extends ImageView implements Pullable 9 | { 10 | 11 | public PullableImageView(Context context) 12 | { 13 | super(context); 14 | } 15 | 16 | public PullableImageView(Context context, AttributeSet attrs) 17 | { 18 | super(context, attrs); 19 | } 20 | 21 | public PullableImageView(Context context, AttributeSet attrs, int defStyle) 22 | { 23 | super(context, attrs, defStyle); 24 | } 25 | 26 | @Override 27 | public boolean canPullDown() 28 | { 29 | return true; 30 | } 31 | 32 | @Override 33 | public boolean canPullUp() 34 | { 35 | return true; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/pullableview/PullableListView.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.pullableview; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.util.Log; 6 | import android.widget.ListView; 7 | 8 | public class PullableListView extends ListView implements Pullable 9 | { 10 | 11 | public PullableListView(Context context) 12 | { 13 | super(context); 14 | } 15 | 16 | public PullableListView(Context context, AttributeSet attrs) 17 | { 18 | super(context, attrs); 19 | } 20 | 21 | public PullableListView(Context context, AttributeSet attrs, int defStyle) 22 | { 23 | super(context, attrs, defStyle); 24 | } 25 | 26 | @Override 27 | public boolean canPullDown() 28 | { 29 | if (getCount() == 0) 30 | { 31 | // 没有item的时候也可以下拉刷新 32 | return true; 33 | } else if (getFirstVisiblePosition() == 0 34 | && getChildAt(0).getTop() >= 0) 35 | { 36 | // 滑到ListView的顶部了 37 | return true; 38 | } else 39 | return false; 40 | } 41 | 42 | @Override 43 | public boolean canPullUp() 44 | { 45 | if (getCount() == 0) 46 | { 47 | // 没有item的时候也可以上拉加载 48 | return true; 49 | } else if (getLastVisiblePosition() == (getCount() - 1)) 50 | { 51 | // 滑到底部了 52 | if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null 53 | && getChildAt( 54 | getLastVisiblePosition() 55 | - getFirstVisiblePosition()).getBottom() <= getMeasuredHeight()) 56 | return true; 57 | } 58 | return false; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/pullableview/PullableScrollView.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.pullableview; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ScrollView; 6 | 7 | public class PullableScrollView extends ScrollView implements Pullable 8 | { 9 | 10 | public PullableScrollView(Context context) 11 | { 12 | super(context); 13 | } 14 | 15 | public PullableScrollView(Context context, AttributeSet attrs) 16 | { 17 | super(context, attrs); 18 | } 19 | 20 | public PullableScrollView(Context context, AttributeSet attrs, int defStyle) 21 | { 22 | super(context, attrs, defStyle); 23 | } 24 | 25 | @Override 26 | public boolean canPullDown() 27 | { 28 | if (getScrollY() == 0) 29 | return true; 30 | else 31 | return false; 32 | } 33 | 34 | @Override 35 | public boolean canPullUp() 36 | { 37 | if (getScrollY() >= (getChildAt(0).getHeight() - getMeasuredHeight())) 38 | return true; 39 | else 40 | return false; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/pullableview/PullableTextView.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.pullableview; 2 | 3 | 4 | import android.content.Context; 5 | import android.util.AttributeSet; 6 | import android.widget.TextView; 7 | 8 | public class PullableTextView extends TextView implements Pullable 9 | { 10 | 11 | public PullableTextView(Context context) 12 | { 13 | super(context); 14 | } 15 | 16 | public PullableTextView(Context context, AttributeSet attrs) 17 | { 18 | super(context, attrs); 19 | } 20 | 21 | public PullableTextView(Context context, AttributeSet attrs, int defStyle) 22 | { 23 | super(context, attrs, defStyle); 24 | } 25 | 26 | @Override 27 | public boolean canPullDown() 28 | { 29 | return true; 30 | } 31 | 32 | @Override 33 | public boolean canPullUp() 34 | { 35 | return true; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/com/jingchen/pulltorefresh/pullableview/PullableWebView.java: -------------------------------------------------------------------------------- 1 | package com.jingchen.pulltorefresh.pullableview; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.webkit.WebView; 6 | 7 | public class PullableWebView extends WebView implements Pullable 8 | { 9 | 10 | public PullableWebView(Context context) 11 | { 12 | super(context); 13 | } 14 | 15 | public PullableWebView(Context context, AttributeSet attrs) 16 | { 17 | super(context, attrs); 18 | } 19 | 20 | public PullableWebView(Context context, AttributeSet attrs, int defStyle) 21 | { 22 | super(context, attrs, defStyle); 23 | } 24 | 25 | @Override 26 | public boolean canPullDown() 27 | { 28 | if (getScrollY() == 0) 29 | return true; 30 | else 31 | return false; 32 | } 33 | 34 | @Override 35 | public boolean canPullUp() 36 | { 37 | if (getScrollY() >= getContentHeight() * getScale() 38 | - getMeasuredHeight()) 39 | return true; 40 | else 41 | return false; 42 | } 43 | } 44 | --------------------------------------------------------------------------------