r7爆屏加触摸屏坏了怎么办要多少钱修

Android常用控件之下拉刷新Wifi列表
> Android常用控件之下拉刷新Wifi列表
Android常用控件之下拉刷新Wifi列表
本文引用地址:界面
关键代码下拉列表类package com.example.dropdownrefresh.import java.text.SimpleDateFimport java.util.Dimport com.example.dropdownrefresh.R;import android.content.Cimport android.util.AttributeSimport android.util.Limport android.view.LayoutIimport android.view.MotionEimport android.view.Vimport android.view.ViewGimport android.view.animation.LinearIimport android.view.animation.RotateAimport android.widget.AbsListVimport android.widget.AbsListView.OnScrollLimport android.widget.BaseAimport android.widget.ImageVimport android.widget.LinearLimport android.widget.ListVimport android.widget.ProgressBimport android.widget.TextV/*** 下拉列表类* @author Administrator**/public class DropdownListView extends ListView implements OnScrollListener
{private static final String TAG =private final static int RELEASE_To_REFRESH = 0;private final static int PULL_To_REFRESH = 1;private 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 LayoutIprivate LinearLayout headVprivate TextView tipsTprivate TextView lastUpdatedTextVprivate ImageView arrowImageVprivate ProgressBar progressBprivate RotateAprivate RotateAnimation reverseA// 用于保证startY的值在一个完整的touch事件中只被记录一次private boolean isRprivate int headContentWprivate int headContentHprivate int startY;private int firstItemIprivate boolean isBprivate OnRefreshListener refreshLprivate boolean isRpublic DropdownListView(Context context) {super(context);// TODO Auto-generated constructor stubinit(context);}public DropdownListView(Context context, AttributeSet attrs) {super(context, attrs);init(context);}private void init(Context context) {setCacheColorHint(context.getResources().getColor(R.color.transparent));inflater = LayoutInflater.from(context);headView = (LinearLayout) inflater.inflate(R.layout.head, null);arrowImageView = (ImageView) headView.findViewById(R.id.head_arrowImageView);arrowImageView.setMinimumWidth(70);arrowImageView.setMinimumHeight(50);progressBar = (ProgressBar) headView.findViewById(R.id.head_progressBar);tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);lastUpdatedTextView = (TextView) headView.findViewById(R.id.head_lastUpdatedTextView);measureView(headView);headContentHeight = headView.getMeasuredHeight();headContentWidth = headView.getMeasuredWidth();headView.setPadding(0, -1 * headContentHeight, 0, 0);headView.invalidate();Log.v(size, width: + headContentWidth + height:+ headContentHeight);addHeaderView(headView, null, false);setOnScrollListener(this);animation = new RotateAnimation(0, -180,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);animation.setInterpolator(new LinearInterpolator());animation.setDuration(250);animation.setFillAfter(true);reverseAnimation = new RotateAnimation(-180, 0,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);reverseAnimation.setInterpolator(new LinearInterpolator());reverseAnimation.setDuration(200);reverseAnimation.setFillAfter(true);state = DONE;
分享给小伙伴们:
我来说两句……
最新技术贴
微信公众号二
微信公众号一RecyclerView+SwipeRefreshLayout实现三种布局上拉加载下拉刷新【android开发吧】_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:116,329贴子:
RecyclerView+SwipeRefreshLayout实现三种布局上拉加载下拉刷新收藏
一楼留给大神,致敬。。。
先介绍一下RecyclerView,这个控件我一年之前就听说过了,但一直没去用过,还是跟之前一样,listview,gridview那样去用,直到最近才去真真的了解了一下这个谷歌所谓的不比ListView复杂,反而更灵活好用,它将数据、排列方式、数据的展示方式都分割开来,因此可定制型,自定义的形式也非常多,非常灵活的组件
第一步 androidStudio 导入RecyclerView导入之后大家就可以直接用了
要写 那肯定是先要搞清楚怎么去定义这个组件总不能想咱们写listview一样,直接写,那肯定不行的,像这样就可以了,同时我上面也定义了一层swipeRefresgLayout,是用来添加下拉刷新的
好了 布局定义好之后我们就是寻找组件了,这时候就有了一个关键的东西LayoutManager,这个东西就是关系到你是想让列表listview展示还是gridview展示,或者是瀑布流StaggeredGridLayout展示了,先来看listview展示
public class MainActivity extends Activity {
private RecyclerView recyclerV//一个可以替代listview
gridview的控件
private RecyclerView.LayoutManager layoutM//必须实例化layoutManager
使用它来区分是瀑布流还是listview还是gridview
private RecyclerviewA
//适配器也会发生改变具体请看适配器内容
private List&String&
private ItemTouchHelper mItemTouchH
private LinearLayoutManager
linearLayoutM
//是否正在上拉数据
private boolean loading =
private SwipeRefreshLayout
refreshL//谷歌官方提供的刷新控件下面已做具体注释
private Handler handler=new Handler(){
public void handleMessage(Message msg) {
super.handleMessage(msg);
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
private void initView() {
refreshLayout= (SwipeRefreshLayout) findViewById(R.id.refresh_layout);
recyclerView= (RecyclerView) findViewById(R.id.recyclerview_view);
recyclerView.setHasFixedSize(true);
//关联ItemTouchHelper和RecyclerView
linearLayoutManager = new LinearLayoutManager(MainActivity.this);
layoutManager=linearLayoutM
recyclerView.setLayoutManager(layoutManager);
//给recyclerview设置分割线
recyclerView.addItemDecoration(new
DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
private void initData(){
list=new ArrayList&&();
for(int i=1;i&=20;i++){
list.add(&&+i);
//refreshLayout.setColorScheme();//这个方法设置进度条颜色已经弃用
refreshLayout.setColorSchemeResources(R.color.red);//使用新方法来设置它的进度条颜色,最多可设置四种颜色
// refreshLayout.setRefreshing(true);//设置是否隐藏刷新动作
true表示显示,false表示隐藏,默认为true
adapter=new RecyclerviewAdapter(list,MainActivity.this);
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
public void onRefresh() {
handler.postDelayed(new Runnable() {
public void run() {
adapter.addll(list);
refreshLayout.setRefreshing(false);//设置收起刷新状态
//这里等同于网络数据加载
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(recyclerView);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int lastVisibleItemPosition =linearLayoutManager.findLastVisibleItemPosition();
if (lastVisibleItemPosition + 1 == adapter.getItemCount()) {
Log.d(&test&, &loading executed&);
boolean isRefreshing = refreshLayout.isRefreshing();
if (isRefreshing) {
adapter.notifyItemRemoved(adapter.getItemCount());
if (!loading) {
setFooterView(recyclerView);
handler.postDelayed(new Runnable() {
public void run() {
adapter.addll(list);
//这里等同于网络操作
Log.d(&test&, &load more completed&);
recyclerView.setAdapter(adapter);
setHeader(recyclerView);
private void setHeader(RecyclerView view) {
View header = LayoutInflater.from(this).inflate(R.layout.layout_header, view, false);
adapter.setHeaderView(header);
private void setFooterView(RecyclerView view) {
View header = LayoutInflater.from(this).inflate(R.layout.layout_foot, view, false);
adapter.setFooterView(header);
上面是设置成listview样式的RecyclerView并且增加了头部和底部视图,和上拉加载
现在是时候看一波适配器代码了,我让listviewg和gridview用一个适配器,然后把瀑布流单独了一个适配器
package com.aykj.import android.content.Cimport android.support.v7.widget.RecyclerVimport android.view.LayoutIimport android.view.Vimport android.view.ViewGimport android.widget.ImageVimport android.widget.TextVimport java.util.Cimport java.util.L/** * 这个就是适配器的代码了.*/public class RecyclerviewAdapter extends RecyclerView.Adapter&RecyclerviewAdapter.MyViewHodler& implements
onMoveAndSwipedListener{
private LayoutI
private List&String&
private View mHeaderV
// 底部控件
private View mFooterV
private boolean isHasHeader =
private boolean isHasFooter =
private int
private int
public static final int TYPE_HEADER = 0;
public static final int TYPE_NORMAL = 1;
public static final int TYPE_FOOTER = 2;
public RecyclerviewAdapter(List&String& list, Context context) {
this.context =
this.list =
inflater = LayoutInflater.from(context);
public MyViewHodler onCreateViewHolder(ViewGroup parent, int viewType) {
//listview中的 getView方法 用于view的复用
View view = inflater.inflate(R.layout.activity_listview, parent, false);
MyViewHodler holder = new MyViewHodler(view);
if (viewType == TYPE_FOOTER) {
// 如果是底部类型,返回底部视图
return new MyViewHodler(mFooterView);
if (viewType == TYPE_HEADER) {
return new MyViewHodler(mHeaderView);
public void onBindViewHolder(MyViewHodler holder, int position) {
//相当于listview适配器中的getitem()方法;
if (isHasHeader && isHasFooter) {
// 有头布局和底部时,向前便宜一个,且最后一个不能绑定数据
if (position == 0 || position == list.size() + 1) {
final int pos = getRealPosition(holder);
String data =list.get(pos);
if (holder instanceof MyViewHodler) {
holder.textView.setText(data);
public int getRealPosition(RecyclerView.ViewHolder holder) {
if (isHasHeader = true) {
int position = holder.getLayoutPosition();
return mHeaderView == null ? position : position - 1;
if (isHasFooter = true) {
int position = holder.getLayoutPosition();
return mFooterView == null ? position : position + 1;
void addll(List&String& data){
this.list.addAll(data);
notifyDataSetChanged();
protected boolean isHeadher(int
position){
header!=0 && position &
protected boolean isFooter(int
position){
foot!=0 && position &=getItemCount()-1;
public int getItemCount() {
int size = list.size();
if (isHasFooter)
if (isHasHeader)
public void setHeaderView(View headerView) {
mHeaderView = headerV
isHasHeader =
notifyItemInserted(0);
* 添加底部视图
public void setFooterView(View footer) {
mFooterView =
isHasFooter =
notifyDataSetChanged();
public int getItemViewType(int position) {
if(isHasHeader&&position==0){
TYPE_HEADER;
if(isHasFooter&&isHasHeader&&position==list.size()+1){
TYPE_FOOTER;
return TYPE_NORMAL;
public boolean onItemMove(int fromPosition, int toPosition) {
if(fromPosition&=list.size()){
//交换mItems数据的位置
Collections.swap(list,fromPosition-1,toPosition-1);
//交换RecyclerView列表中item的位置
notifyItemMoved(fromPosition,toPosition);
public void onItemDismiss(int position) {
if(position&=list.size()) {
//删除mItems数据
list.remove(position - 1);
//删除RecyclerView列表对应item
notifyItemRemoved(position);
class MyViewHodler extends RecyclerView.ViewHolder{
public MyViewHodler(View itemView) {
super(itemView);
textView= (TextView) itemView.findViewById(R.id.text_recyclerlistview);
imageView= (ImageView) itemView.findViewById(R.id.recyclerview_imag);
listview和gridview的样式的列表已经完成了,有头部有底部,有上拉加载,有下拉刷新
现在看一下瀑布流样式的列表,当时在写这个的时候碰到一个问题,就是在滑动的过程中itme会移动甚至会出现自己换位置,很多人可能会写这个瀑布流的时候会使用瀑布流中自己适应itme的高度等等,我是写了两套布局,让item用两套不同的布局展现,你甚至可以再多写点,展示层次不同的瀑布流样式
package com.aykj.import android.content.Cimport android.support.v7.widget.RecyclerVimport android.support.v7.widget.StaggeredGridLayoutMimport android.view.LayoutIimport android.view.Vimport android.view.ViewGimport android.widget.ImageVimport android.widget.TextVimport java.util.Cimport java.util.L/** *这个是瀑布流形式的适配器 */public class StaggergridAdapter extends RecyclerView.Adapter&StaggergridAdapter.MyViewHodler& implements
onMoveAndSwipedListener{
private LayoutI
private List&String&
private View mHeaderV
private View
// 底部控件
private View mFooterV
private boolean isHasHeader =
private boolean isHasFooter =
public static final int TYPE_HEADER = 0;
public static final int TYPE_FOOTER = 1;
public static final int TYPE_LEFT = 2;
public static final int TYPE_RIGHT= 3;
public StaggergridAdapter(List&String& list, Context context) {
this.context =
this.list =
inflater = LayoutInflater.from(context);
public StaggergridAdapter.MyViewHodler onCreateViewHolder(ViewGroup parent, int viewType) {
//listview中的 getView方法 用于view的复用
viewTypeLayout = inflater.inflate(R.layout.activity_listview, parent, false);
StaggergridAdapter.MyViewHodler holder = new StaggergridAdapter.MyViewHodler(viewTypeLayout);
if (viewType == TYPE_FOOTER) {
// 如果是底部类型,返回底部视图
StaggeredGridLayoutManager.LayoutParams clp = (StaggeredGridLayoutManager.LayoutParams) mFooterView.getLayoutParams();
clp.setFullSpan(true);
return new StaggergridAdapter.MyViewHodler(mFooterView);
if (viewType == TYPE_HEADER) {
//头部视图
StaggeredGridLayoutManager.LayoutParams clp = (StaggeredGridLayoutManager.LayoutParams) mHeaderView.getLayoutParams();
clp.setFullSpan(true);
return new StaggergridAdapter.MyViewHodler(mHeaderView);
}if(viewType==TYPE_LEFT){
viewTypeLayout=inflater.inflate(R.layout.activity_layoutgrid,parent,false);
return new StaggergridAdapter.MyViewHodler(viewTypeLayout);
}if(viewType==TYPE_RIGHT){
viewTypeLayout=inflater.inflate(R.layout.activity_listview,parent,false);
return new StaggergridAdapter.MyViewHodler(viewTypeLayout);
public void onBindViewHolder(MyViewHodler holder, int position) {
//相当于listview适配器中的getitem()方法;
if (isHasHeader && isHasFooter) {
// 有头布局和底部时,向前便宜一个,且最后一个不能绑定数据
if (position == 0 || position == list.size() + 1) {
int pos = getRealPosition(holder);
String data =list.get(pos);
if (holder instanceof MyViewHodler) {
holder.textView.setText(data);
public int getRealPosition(RecyclerView.ViewHolder holder) {
if (isHasHeader = true) {
int position = holder.getLayoutPosition();
return mHeaderView == null ? position : position - 1;
if (isHasFooter = true) {
int position = holder.getLayoutPosition();
return mFooterView == null ? position : position + 1;
void addll(List&String& data){
this.list.addAll(data);
notifyDataSetChanged();
public int getItemCount() {
int size = list.size();
if (isHasFooter)
if (isHasHeader)
public void setHeaderView(View headerView) {
mHeaderView = headerV
isHasHeader =
notifyItemInserted(0);
* 添加底部视图
public void setFooterView(View footer) {
mFooterView =
isHasFooter =
notifyDataSetChanged();
public int getItemViewType(int position) {
if(isHasHeader&&position==0){
TYPE_HEADER;
if(isHasFooter&&isHasHeader&&position==list.size()+1){
TYPE_FOOTER;
}if(position%2==0){
//position取余,就是让itme使用不同的布局
TYPE_LEFT;
TYPE_RIGHT;
public boolean onItemMove(int fromPosition, int toPosition) {
if(fromPosition&=list.size()){
//交换mItems数据的位置
Collections.swap(list,fromPosition-1,toPosition-1);
//交换RecyclerView列表中item的位置
notifyItemMoved(fromPosition,toPosition);
public void onItemDismiss(int position) {
if(position&=list.size()) {
//删除mItems数据
list.remove(position - 1);
//删除RecyclerView列表对应item
notifyItemRemoved(position);
class MyViewHodler extends RecyclerView.ViewHolder{
TextView textV
ImageView imageV
public MyViewHodler(View itemView) {
super(itemView);
textView= (TextView) itemView.findViewById(R.id.text_recyclerlistview);
imageView= (ImageView) itemView.findViewById(R.id.recyclerview_imag);
三种样式的recyclerview已经全部实现了,是带有头部底部和上拉加载,下拉刷新的功能,不知道有没有人看到我里面实现了一个onMoveAndSwipedListener接口,这个是一个自定义接口里面有两个方法,是用来实现itme的拖拽和删除功能的,这个也是使用提供好的一个工具类ItemTouchHelper.Callback,直接继承就行package com.aykj.import android.support.v7.widget.LinearLayoutMimport android.support.v7.widget.RecyclerVimport android.support.v7.widget.helper.ItemTouchH/** * Created by Administrator on . */public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
private onMoveAndSwipedListener
moveAndSwipedL
public SimpleItemTouchHelperCallback(onMoveAndSwipedListener
Listener){
moveAndSwipedListener=L
/**这个方法是用来设置我们拖动的方向以及侧滑的方向的*/
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (viewHolder.getItemViewType()==RecyclerviewAdapter.TYPE_HEADER||viewHolder.getItemViewType()==RecyclerviewAdapter.TYPE_FOOTER){//头部和底部视图不允许拖动
return viewHolder.getAdapterPosition();
//如果是ListView样式的RecyclerView
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager){
//设置拖拽方向为上下
final int dragFlags = ItemTouchHelper.UP|ItemTouchHelper.DOWN;
//设置侧滑方向为从左到右和从右到左都可以
final int swipeFlags = ItemTouchHelper.START|ItemTouchHelper.END;
//将方向参数设置进去
return makeMovementFlags(dragFlags,swipeFlags);
}else{//如果是GridView样式的RecyclerView
//设置拖拽方向为上下左右
final int dragFlags = ItemTouchHelper.UP|ItemTouchHelper.DOWN|
ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT;
//不支持侧滑
final int swipeFlags = 0;
return makeMovementFlags(dragFlags,swipeFlags);
/**当我们拖动item时会回调此方法*/
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//如果两个item不是一个类型的,我们让他不可以拖拽
if (viewHolder.getItemViewType() != target.getItemViewType()){
//头部和底部视图不允许拖动
moveAndSwipedListener.onItemMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());
/**当我们侧滑item时会回调此方法*/
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//回调adapter中的onItemDismiss方法
moveAndSwipedListener.onItemDismiss(viewHolder.getAdapterPosition());
基本上就算完成了,Reclerview+SwipeRefreshLayout+头部底部+itme侧滑删除+长按互换位置等这几个功能大家有兴趣的可以试试
总结,使用完之后的感觉就是确实是比listview等等实现的方法更灵活,更加好用,相比于listview的适配器,reclerview的适配更加的灵活,底部封装了ViewHodler让我们省去了很多步骤,比如getview的复用,我自己这几天的学习就这样,如果有哪里说的不对的,请大家指正,互相学习,最后,致敬大神
我没有添加itme点击方法的,如果大家想要去实现,那就都自己写,因为reclerview并没有提供,多多学习,android的路很长,我们需要虚心学习
顶层,致敬大神,希望以后我也可以成为一名高级软件开发工程师或者一名资深架构师,想想不犯法吧!哈哈
楼主可以的
登录百度帐号推荐应用方便实用的下拉刷新控件,支持ScrollView、AbsListView -
- ITeye博客
博客分类:
最近要做一个下拉刷新的功能,网上找了很多例子,也看了一些开源的下拉刷新项目,但是小例子比较简单,效果和稳定性都差强人意,而开源的项目又太庞大,看起来耗时费劲,所以只好综合一下各处的代码掌握其原理,自己实现一套下拉刷新功能。
该控件特点:
1.子控件必须是一个ScrollView或ListView;
2.支持自定义下拉布局;
3.自定义下拉布局可以不用处理下拉的各种状态(只需要实现几个接口即可),也可以自己处理各种下拉的状态。
先来看看效果图:
首先看如何使用:
1.使用的布局:
&LinearLayout xmlns:android="/apk/res/android"
xmlns:tools="/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" &
&com.example.pulldown.PullDownScrollView
android:id="@+id/refresh_root"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:background="#161616"
android:orientation="vertical" &
&ScrollView
android:id="@+id/scrollview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="none" &
&LinearLayout
android:id="@+id/mainView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#1f1f1f"
android:orientation="vertical" &
&!-- 自已的布局 --&
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:gravity="center"
android:text="@string/hello_world"
android:textColor="@android:color/white"
android:textSize="18sp" /&
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:gravity="center"
android:text="@string/hello_world"
android:textColor="@android:color/white"
android:textSize="18sp" /&
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:gravity="center"
android:text="@string/hello_world"
android:textColor="@android:color/white"
android:textSize="18sp" /&
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:gravity="center"
android:text="@string/hello_world"
android:textColor="@android:color/white"
android:textSize="18sp" /&
&/LinearLayout&
&/ScrollView&
&/com.example.pulldown.PullDownScrollView&
&/LinearLayout&
2.UI使用:
首先,Activity实现接口:
implements RefreshListener
部分代码如下:
package com.example.
import com.example.pulldown.PullDownScrollView.RefreshL
import android.os.B
import android.os.H
import android.app.A
import android.view.M
public class MainActivity extends Activity implements RefreshListener{
private PullDownScrollView mPullDownScrollV
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPullDownScrollView = (PullDownScrollView) findViewById(R.id.refresh_root);
mPullDownScrollView.setRefreshListener(this);
mPullDownScrollView.setPullDownElastic(new PullDownElasticImp(this));
public void onRefresh(PullDownScrollView view) {
new Handler().postDelayed(new Runnable() {
public void run() {
// TODO Auto-generated method stub
mPullDownScrollView.finishRefresh("上次刷新时间:12:23");
public boolean onCreateOptionsMenu(Menu menu) {
// I this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
3.再来看看控件代码:
import android.content.C
import android.util.AttributeS
import android.view.MotionE
import android.view.V
import android.view.animation.LinearI
import android.view.animation.RotateA
import android.widget.AbsListV
import android.widget.LinearL
import android.widget.ScrollV
public class PullDownScrollView extends LinearLayout {
private static final String TAG = "PullDownScrollView";
private int refreshTargetTop = -60;
private int headContentH
private RefreshListener refreshL
private RotateA
private RotateAnimation reverseA
private final static int RATIO = 2;
private int preY = 0;
private boolean isElastic =
private int startY;
private String note_release_to_refresh = "松开更新";
private String note_pull_to_refresh = "下拉刷新";
private String note_refreshing = "正在更新...";
private IPullDownElastic mE
public PullDownScrollView(Context context) {
super(context);
public PullDownScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
private void init() {
animation = new RotateAnimation(0, -180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
animation.setInterpolator(new LinearInterpolator());
animation.setDuration(250);
animation.setFillAfter(true);
reverseAnimation = new RotateAnimation(-180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
reverseAnimation.setInterpolator(new LinearInterpolator());
reverseAnimation.setDuration(200);
reverseAnimation.setFillAfter(true);
* 刷新监听
* @param listener
public void setRefreshListener(RefreshListener listener) {
this.refreshListener =
* 下拉布局
* @param elastic
public void setPullDownElastic(IPullDownElastic elastic) {
mElastic =
headContentHeight = mElastic.getElasticHeight();
refreshTargetTop = - headContentH
LayoutParams lp = new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, headContentHeight);
lp.topMargin = refreshTargetT
addView(mElastic.getElasticLayout(), 0, lp);
* 设置更新提示语
* @param pullToRefresh 下拉刷新提示语
* @param releaseToRefresh 松开刷新提示语
* @param refreshing 正在刷新提示语
public void setRefreshTips(String pullToRefresh, String releaseToRefresh, String refreshing) {
note_pull_to_refresh = pullToR
note_release_to_refresh = releaseToR
note_refreshing =
* 该方法一般和ontouchEvent 一起用 (non-Javadoc)
* android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)
public boolean onInterceptTouchEvent(MotionEvent ev) {
Logger.d(TAG, "onInterceptTouchEvent");
printMotionEvent(ev);
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
preY = (int) ev.getY();
if (ev.getAction() == MotionEvent.ACTION_MOVE) {
Logger.d(TAG, "isElastic:" + isElastic + " canScroll:"+ canScroll() + " ev.getY() - preY:"+(ev.getY() - preY));
if (!isElastic && canScroll()
&& (int) ev.getY() - preY &= headContentHeight / (3*RATIO)
&& refreshListener != null && mElastic != null) {
isElastic =
startY = (int) ev.getY();
Logger.i(TAG, "在move时候记录下位置startY:" + startY);
return super.onInterceptTouchEvent(ev);
public boolean onTouchEvent(MotionEvent event) {
Logger.d(TAG, "onTouchEvent");
printMotionEvent(event);
handleHeadElastic(event);
return super.onTouchEvent(event);
private void handleHeadElastic(MotionEvent event) {
if (refreshListener != null && mElastic != null) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Logger.i(TAG, "down");
case MotionEvent.ACTION_UP:
Logger.i(TAG, "up");
if (state != IPullDownElastic.REFRESHING && isElastic) {
if (state == IPullDownElastic.DONE) {
// 什么都不做
setMargin(refreshTargetTop);
if (state == IPullDownElastic.PULL_To_REFRESH) {
state = IPullDownElastic.DONE;
setMargin(refreshTargetTop);
changeHeaderViewByState(state, false);
Logger.i(TAG, "由下拉刷新状态,到done状态");
if (state == IPullDownElastic.RELEASE_To_REFRESH) {
state = IPullDownElastic.REFRESHING;
setMargin(0);
changeHeaderViewByState(state, false);
onRefresh();
Logger.i(TAG, "由松开刷新状态,到done状态");
isElastic =
case MotionEvent.ACTION_MOVE:
Logger.i(TAG, "move");
int tempY = (int) event.getY();
if (state != IPullDownElastic.REFRESHING && isElastic) {
// 可以松手去刷新了
if (state == IPullDownElastic.RELEASE_To_REFRESH) {
if (((tempY - startY) / RATIO & headContentHeight)
&& (tempY - startY) & 0) {
state = IPullDownElastic.PULL_To_REFRESH;
changeHeaderViewByState(state, true);
Logger.i(TAG, "由松开刷新状态转变到下拉刷新状态");
} else if (tempY - startY &= 0) {
state = IPullDownElastic.DONE;
changeHeaderViewByState(state, false);
Logger.i(TAG, "由松开刷新状态转变到done状态");
if (state == IPullDownElastic.DONE) {
if (tempY - startY & 0) {
state = IPullDownElastic.PULL_To_REFRESH;
changeHeaderViewByState(state, false);
if (state == IPullDownElastic.PULL_To_REFRESH) {
// 下拉到可以进入RELEASE_TO_REFRESH的状态
if ((tempY - startY) / RATIO &= headContentHeight) {
state = IPullDownElastic.RELEASE_To_REFRESH;
changeHeaderViewByState(state, false);
Logger.i(TAG, "由done或者下拉刷新状态转变到松开刷新");
} else if (tempY - startY &= 0) {
state = IPullDownElastic.DONE;
changeHeaderViewByState(state, false);
Logger.i(TAG, "由DOne或者下拉刷新状态转变到done状态");
if (tempY - startY & 0) {
setMargin((tempY - startY)/2 + refreshTargetTop);
private void setMargin(int top) {
LinearLayout.LayoutParams lp = (LayoutParams) mElastic.getElasticLayout()
.getLayoutParams();
lp.topMargin =
// 修改后刷新
mElastic.getElasticLayout().setLayoutParams(lp);
mElastic.getElasticLayout().invalidate();
private void changeHeaderViewByState(int state, boolean isBack) {
mElastic.changeElasticState(state, isBack);
switch (state) {
case IPullDownElastic.RELEASE_To_REFRESH:
mElastic.showArrow(View.VISIBLE);
mElastic.showProgressBar(View.GONE);
mElastic.showLastUpdate(View.VISIBLE);
mElastic.setTips(note_release_to_refresh);
mElastic.clearAnimation();
mElastic.startAnimation(animation);
Logger.i(TAG, "当前状态,松开刷新");
case IPullDownElastic.PULL_To_REFRESH:
mElastic.showArrow(View.VISIBLE);
mElastic.showProgressBar(View.GONE);
mElastic.showLastUpdate(View.VISIBLE);
mElastic.setTips(note_pull_to_refresh);
mElastic.clearAnimation();
// 是由RELEASE_To_REFRESH状态转变来的
if (isBack) {
mElastic.startAnimation(reverseAnimation);
Logger.i(TAG, "当前状态,下拉刷新");
case IPullDownElastic.REFRESHING:
mElastic.showArrow(View.GONE);
mElastic.showProgressBar(View.VISIBLE);
mElastic.showLastUpdate(View.GONE);
mElastic.setTips(note_refreshing);
mElastic.clearAnimation();
Logger.i(TAG, "当前状态,正在刷新...");
case IPullDownElastic.DONE:
mElastic.showProgressBar(View.GONE);
mElastic.clearAnimation();
arrowImageView.setImageResource(R.drawable.goicon);
// tipsTextview.setText("下拉刷新");
// lastUpdatedTextView.setVisibility(View.VISIBLE);
Logger.i(TAG, "当前状态,done");
private void onRefresh() {
// downTextView.setVisibility(View.GONE);
scroller.startScroll(0, i, 0, 0 - i);
invalidate();
if (refreshListener != null) {
refreshListener.onRefresh(this);
public void computeScroll() {
if (puteScrollOffset()) {
int i = this.scroller.getCurrY();
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.refreshView
.getLayoutParams();
int k = Math.max(i, refreshTargetTop);
lp.topMargin =
this.refreshView.setLayoutParams(lp);
this.refreshView.invalidate();
invalidate();
* 结束刷新事件,UI刷新完成后必须回调此方法
* @param text 一般传入:“上次更新时间:12:23”
public void finishRefresh(String text) {
if (mElastic == null) {
Logger.d(TAG, "finishRefresh mElastic:" + mElastic);
state = IPullDownElastic.DONE;
mElastic.setLastUpdateText(text);
changeHeaderViewByState(state,false);
Logger.i(TAG, "执行了=====finishRefresh");
mElastic.showArrow(View.VISIBLE);
mElastic.showLastUpdate(View.VISIBLE);
setMargin(refreshTargetTop);
scroller.startScroll(0, i, 0, refreshTargetTop);
invalidate();
private boolean canScroll() {
View childV
if (getChildCount() & 1) {
childView = this.getChildAt(1);
if (childView instanceof AbsListView) {
int top = ((AbsListView) childView).getChildAt(0).getTop();
int pad = ((AbsListView) childView).getListPaddingTop();
if ((Math.abs(top - pad)) & 3
&& ((AbsListView) childView).getFirstVisiblePosition() == 0) {
} else if (childView instanceof ScrollView) {
if (((ScrollView) childView).getScrollY() == 0) {
return canScroll(this);
* 子类重写此方法可以兼容其它的子控件,目前只兼容AbsListView和ScrollView
* @param view
public boolean canScroll(PullDownScrollView view) {
private void printMotionEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Logger.d(TAG, "down");
case MotionEvent.ACTION_MOVE:
Logger.d(TAG, "move");
case MotionEvent.ACTION_UP:
Logger.d(TAG, "up");
* 刷新监听接口
public interface RefreshListener {
public void onRefresh(PullDownScrollView view);
import android.view.V
import android.view.animation.A
* 下拉控件接口
public interface IPullDownElastic {
public final static int RELEASE_To_REFRESH = 0;
public final static int PULL_To_REFRESH = 1;
public final static int REFRESHING = 2;
public final static int DONE = 3;
public View getElasticLayout();
public int getElasticHeight();
public void showArrow(int visibility);
public void startAnimation(Animation animation);
public void clearAnimation();
public void showProgressBar(int visibility);
public void setTips(String tips);
public void showLastUpdate(int visibility);
public void setLastUpdateText(String text);
* 可以不用实现此方法,PullDownScrollView会处理ElasticLayout布局中的状态
* 如果需要特殊处理,可以实现此方法进行处理
* @param state
@see RELEASE_To_REFRESH
* @param isBack 是否是松开回退
public void changeElasticState(int state, boolean isBack);
5.默认实现:
import android.content.C
import android.view.LayoutI
import android.view.V
import android.view.animation.A
import android.widget.ImageV
import android.widget.ProgressB
import android.widget.TextV
* 默认下拉控件布局实现
public class PullDownElasticImp implements IPullDownElastic {
private View refreshV
private ImageView arrowImageV
private int headContentH
private ProgressBar progressB
private TextView tipsT
private TextView lastUpdatedTextV
private Context mC
public PullDownElasticImp(Context context) {
mContext =
private void init() {
// 刷新视图顶端的的view
refreshView = LayoutInflater.from(mContext).inflate(
R.layout.refresh_top_item, null);
// 指示器view
arrowImageView = (ImageView) refreshView
.findViewById(R.id.head_arrowImageView);
// 刷新bar
progressBar = (ProgressBar) refreshView
.findViewById(R.id.head_progressBar);
// 下拉显示text
tipsTextview = (TextView) refreshView.findViewById(R.id.refresh_hint);
// 下来显示时间
lastUpdatedTextView = (TextView) refreshView
.findViewById(R.id.refresh_time);
headContentHeight = Utils.dip2px(mContext, 50);
public View getElasticLayout() {
return refreshV
public int getElasticHeight() {
return headContentH
* @param show
public void showArrow(int visibility) {
arrowImageView.setVisibility(visibility);
* @param animation
public void startAnimation(Animation animation) {
arrowImageView.startAnimation(animation);
public void clearAnimation() {
arrowImageView.clearAnimation();
* @param show
public void showProgressBar(int visibility) {
progressBar.setVisibility(visibility);
* @param tips
public void setTips(String tips) {
tipsTextview.setText(tips);
* @param show
public void showLastUpdate(int visibility) {
lastUpdatedTextView.setVisibility(visibility);
* @param text
public void setLastUpdateText(String text) {
lastUpdatedTextView.setText(text);
* @param state
* @param isBack
public void changeElasticState(int state, boolean isBack) {
// TODO Auto-generated method stub
6.默认实现的布局:
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="-50.0dip"
android:orientation="vertical" &
&LinearLayout
android:layout_width="fill_parent"
android:layout_height="0.0dip"
android:layout_weight="1.0"
android:gravity="center"
android:orientation="horizontal" &
&!-- 箭头图像、进度条 --&
&FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="30dip" &
&!-- 箭头 --&
&ImageView
android:id="@+id/head_arrowImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/goicon" /&
&!-- 进度条 --&
&ProgressBar
android:id="@+id/head_progressBar"
style="@android:style/Widget.ProgressBar.Small.Inverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" /&
&/FrameLayout&
&LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical" &
&!-- 提示 --&
android:id="@+id/refresh_hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"
android:textColor="#f2f2f2"
android:textSize="16sp" /&
&!-- 最近更新 --&
android:id="@+id/refresh_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上次更新"
android:textColor="#b89766"
android:textSize="10sp" /&
&/LinearLayout&
&/LinearLayout&
&/LinearLayout&
6.图片资源:
@drawable/goicon
修改:从原工程中独立出来,并附上简单的工程,见附件。
(958.1 KB)
下载次数: 1080
浏览 17499
浏览: 91078 次
来自: 鄂州
写的很好,谢谢分享
在Fragment中使用布局怎么显示不出来
Mybeautiful 写道显然有问题,return Bitm ...
显然有问题,return BitmapFactory.deco ...
加入我工程的时候有个诡异的bug,下拉刷新布局就会覆盖主Vie ...}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信