Android基于GridView实现自定义上拉更多和下拉刷新

合集下载

Android通过代码控制ListView上下滚动的方法

Android通过代码控制ListView上下滚动的方法

Android通过代码控制ListView上下滚动的⽅法本⽂将介绍⼀种通过代码控制ListView上下滚动的⽅法。

先上图:按下按钮会触发ListView滚动或停⽌。

实现该功能并不难,下⾯给出主要代码MainActivity.javapackage cn.guet.levide;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.ListView;public class MainActivity extends Activity implements OnClickListener {private Button btn_up, btn_down, btn_stop; // 三个按钮private ListView listview;private Adapter adapter;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.main);findBy();init();}private void init() {btn_up.setOnClickListener(this);btn_down.setOnClickListener(this);btn_stop.setOnClickListener(this);adapter = new Adapter(this);listview.setAdapter(adapter);}private void findBy() {btn_up = (Button) findViewById(R.id.btn_scroll_up);btn_down = (Button) findViewById(R.id.btn_scroll_down);btn_stop = (Button) findViewById(R.id.btn_scroll_stop);listview = (ListView) findViewById(R.id.listview);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_scroll_down:listScrollDown();break;case R.id.btn_scroll_up:listScrollUp();break;case R.id.btn_scroll_stop:listScrollOff();break;}}Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {handler.removeCallbacks(run_scroll_down);handler.removeCallbacks(run_scroll_up);}};/*** 向上滚动*/public void listScrollUp() {listScrollOff();handler.postDelayed(run_scroll_up, 0);}/*** 向下滚动*/public void listScrollDown() {listScrollOff();handler.postDelayed(run_scroll_down, 0);}/*** 停⽌滚动*/public void listScrollOff() {handler.removeCallbacks(run_scroll_down);handler.removeCallbacks(run_scroll_up);}Runnable run_scroll_up = new Runnable() {@Overridepublic void run() {/*** public void smoothScrollBy (int distance, int duration)** Added in API level 8 Smoothly scroll by distance pixels over duration milliseconds.** Parameters* distance Distance to scroll in pixels.* duration Duration of the scroll animation in milliseconds.*/listview.smoothScrollBy(1, 10);handler.postDelayed(run_scroll_up, 10);}};Runnable run_scroll_down = new Runnable() {@Overridepublic void run() {listview.smoothScrollBy(-1, 10);handler.postDelayed(run_scroll_down, 10);}};}实现ListView位置变动的是smoothScrollBy⽅法。

(Android)五分钟让你轻松学会下拉刷新和上拉加载更多

(Android)五分钟让你轻松学会下拉刷新和上拉加载更多

(Android)五分钟让你轻松学会下拉刷新和上拉加载更多为了更好的学习和工作,动动小手收藏起来吧!分享一个谷歌自带的下拉刷新和上拉加载更多例子:效果图:自定义RefreshLayout继承 SwipeRefreshLayout/*** 继承自SwipeRefreshLayout,从而实现滑动到底部时上拉加载更多的功能.*/public class RefreshLayout extends SwipeRefreshLayout implementsOnScrollListener {/*** 滑动到最下面时的上拉操作*/private int mT ouchSlop;/*** listview实例*/private ListView mListView;/*** 上拉监听器, 到了最底部的上拉加载操作*/private OnLoadListener mOnLoadListener;/*** ListView的加载中footer*/private View mListViewFooter;/*** 按下时的y坐标*/private int mYDown;/*** 抬起时的y坐标, 与mYDown一起用于滑动到底部时判断是上拉还是下拉*/private int mLastY;/*** 是否在加载中 ( 上拉加载更多 )*/private boolean isLoading = false;/*** @param context*/public RefreshLayout(Context context) {this(context, null);}@SuppressLint("InflateParams")public RefreshLayout(Context context, AttributeSet attrs) {super(context, attrs);mTouchSlop =ViewConfiguration.get(context).getScaledTouchSlop();mListViewFooter = LayoutInflater.from(context).inflate(yout.listview_footer, null, false);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {super.onLayout(changed, left, top, right, bottom);// 初始化ListView对象if (mListView == null) {getListView();}}/*** 获取ListView对象*/private void getListView() {int childs = getChildCount();if (childs > 0) {View childView = getChildAt(0);if (childView instanceof ListView) {mListView = (ListView) childView;// 设置滚动监听器给ListView, 使得滚动的情况下也可以自动加载mListView.setOnScrollListener(this);Log.d(VIEW_LOG_TAG, "### 找到listview");}}}/** (non-Javadoc)** @see android.view.ViewGroup#dispatchT ouchEvent(android.view.Moti onEvent)*/@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {final int action = event.getAction();switch (action) {case MotionEvent.ACTION_DOWN:// 按下mYDown = (int) event.getRawY();break;case MotionEvent.ACTION_MOVE:// 移动mLastY = (int) event.getRawY();break;case MotionEvent.ACTION_UP:// 抬起if (canLoad()) {loadData();}break;default:break;}return super.dispatchT ouchEvent(event);}/*** 是否可以加载更多, 条件是到了最底部, listview不在加载中, 且为上拉操作.** @return*/private boolean canLoad() {return isBottom() && !isLoading && isPullUp();}/*** 判断是否到了最底部*/private boolean isBottom() {if (mListView != null && mListView.getAdapter() != null) {return mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() - 1);}return false;}/*** 是否是上拉操作** @return*/private boolean isPullUp() {return (mYDown - mLastY) >= mT ouchSlop;}/*** 如果到了最底部,而且是上拉操作.那么执行onLoad方法*/private void loadData() {if (mOnLoadListener != null) {// 设置状态setLoading(true);//mOnLoadListener.onLoad();}}/*** @param loading*/public void setLoading(boolean loading) {isLoading = loading;if (isLoading) {mListView.addFooterView(mListViewFooter);} else {mListView.removeFooterView(mListViewFooter);mYDown = 0;mLastY = 0;}}/*** @param loadListener*/public void setOnLoadListener(OnLoadListener loadListener) {mOnLoadListener = loadListener;}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {// 滚动时到了最底部也可以加载更多if (canLoad()) {loadData();}}/*** 设置刷新*/public static void setRefreshing(SwipeRefreshLayout refreshLayout,boolean refreshing, boolean notify) {Class<? extends SwipeRefreshLayout> refreshLayoutClass = refreshLayout.getClass();if (refreshLayoutClass != null) {try {Method setRefreshing = refreshLayoutClass.getDeclaredMethod("setRefreshing", boolean.class, boolean.class);setRefreshing.setAccessible(true);setRefreshing.invoke(refreshLayout, refreshing, notify);} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}/*** 加载更多的监听器*/public static interface OnLoadListener {public void onLoad();}}public class MainActivity extends Activity implements OnRefreshListener,OnLoadListener {private RefreshLayout swipeLayout;private ListView listView;private MyAdapter adapter;private ArrayList<HashMap<String, String>> list;private View header;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);initView();setData();setListener();/*设置自动刷新 swipeLayout.setRefreshing(true);在 setRefreshing(true)并没有触发onRefresh的,须要手动调用一次*/// swipeLayout.post(new Thread(new Runnable() {// @Override// public void run() {// swipeLayout.setRefreshing(true);// }// }));// onRefresh();}/*** 初始化布局*/@SuppressLint({ "InlinedApi", "InflateParams" })private void initView() {header = getLayoutInflater().inflate(yout.header, null);swipeLayout = (RefreshLayout) findViewById(R.id.swipe_container);swipeLayout.setColorSchemeResources(R.color.color_bule2, R.color.color_bule,R.color.color_bule2,R.color.color_bule3);}/*** 添加数据*/private void setData() {list = new ArrayList<HashMap<String, String>>();for (int i = 0; i < 10; i++) {HashMap<String, String> map = new HashMap<String, String>();map.put("itemImage", i+"默认");map.put("itemText", i+"默认");list.add(map);}listView = (ListView) findViewById(R.id.list);listView.addHeaderView(header);adapter = new MyAdapter(this, list);listView.setAdapter(adapter);}/*** 设置监听*/private void setListener() {swipeLayout.setOnRefreshListener(this);swipeLayout.setOnLoadListener(this);}/*** 上拉刷新*/@Overridepublic void onRefresh() {swipeLayout.postDelayed(new Runnable() {@Overridepublic void run() {// 更新数据更新完后调用该方法结束刷新list.clear();for (int i = 0; i < 8; i++) {HashMap<String, String> map = new HashMap<String, String>();map.put("itemImage", i+"刷新");map.put("itemText", i+"刷新");list.add(map);}adapter.notifyDataSetChanged();swipeLayout.setRefreshing(false);}}, 2000);}/*** 加载更多*/@Overridepublic void onLoad() {swipeLayout.postDelayed(new Runnable() {@Overridepublic void run() {// 更新数据更新完后调用该方法结束刷新swipeLayout.setLoading(false);for (int i = 1; i < 10; i++) {HashMap<String, String> map = new HashMap<String, String>();map.put("itemImage", i+"更多");map.put("itemText", i+"更多");list.add(map);}adapter.notifyDataSetChanged();}}, 2000);}public class MyAdapter extends BaseAdapter {public ArrayList<HashMap<String, String>> list;public Context context;public LayoutInflater layoutInflater;public MyAdapter(Context context, ArrayList<HashMap<String, String>> list) {this.context = context;this.list = list;layoutInflater = LayoutInflater.from(context);}@Overridepublic int getCount() {return list.size();}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {View view = null;ViewHolder holder = null;if (convertView == null) {view = layoutInflater.inflate(yout.item, null);holder = new ViewHolder();holder.txt =(TextView) view.findViewById(R.id.textView1);view.setTag(holder);} else {view = convertView;holder = (ViewHolder) view.getTag();}holder.txt.setText(list.get(position).get("itemText")); return view;}static class ViewHolder {TextView txt;}}源码下载地址,请回复刷新即可。

Android自定义下拉刷新动画--仿百度外卖下拉刷新

Android自定义下拉刷新动画--仿百度外卖下拉刷新

Android自定义下拉刷新动画--仿百度外卖下拉刷新动画我们先来看看Android中的动画吧:Android中的动画分为三种:Tween动画,这一类的动画提供了旋转、平移、缩放等效果。

Alpha –淡入淡出Scale –缩放效果Roate –旋转效果Translate –平移效果Frame动画(帧动画),这一类动画可以创建一个Drawable序列,按照指定时间间歇一个一个显示出来。

Property动画(属性动画),Android3.0之后引入出来的属性动画,它更改的是对象的实际属性。

分析我们可以看到百度外卖的下拉刷新的头是一个骑车的快递员在路上疾行,分析一下我们得到下面的动画:背景图片的平移动画太阳的自旋转动画两个小轮子的自旋转动画这就很简单了,接下来我们去百度外面的图片资源文件里找到这几张图片:(下载百度外卖的apk直接解压即可)<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"><ImageViewandroid:id="@+id/iv_back1"android:src="@drawable/pull_back"android:layout_width="match_parent"android:layout_height="100dp" /><ImageViewandroid:id="@+id/iv_back2"android:src="@drawable/pull_back"android:layout_width="match_parent"android:layout_height="100dp" /><RelativeLayoutandroid:id="@+id/main"android:layout_centerHorizontal="true"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageViewandroid:layout_marginTop="45dp"android:id="@+id/iv_rider"android:background="@drawable/pull_rider"android:layout_width="50dp"android:layout_height="50dp" /><ImageViewandroid:id="@+id/wheel1"android:layout_marginLeft="10dp"android:layout_marginTop="90dp"android:background="@drawable/pull_wheel"android:layout_width="15dp"android:layout_height="15dp" /><ImageViewandroid:id="@+id/wheel2"android:layout_marginLeft="40dp"android:layout_marginTop="90dp"android:background="@drawable/pull_wheel"android:layout_width="15dp"android:layout_height="15dp" /></RelativeLayout><ImageViewandroid:id="@+id/ivsun"android:layout_marginTop="20dp"android:layout_toRightOf="@+id/main"android:background="@drawable/pull_sun"android:layout_width="30dp"android:layout_height="30dp" /></RelativeLayout>接下来我们定义动画效果:背景图片的平移效果:实现两个animation xml文件,一个起始位置在100%,结束位置在0%,设置repeat属性为循环往复。

Android自定义View控件实现刷新效果

Android自定义View控件实现刷新效果

Android⾃定义View控件实现刷新效果三种得到LinearInflater的⽅法a. LayoutInflater inflater = getLayoutInflater();b. LayoutInflater localinflater =(LayoutInflater)context.getSystemService(YOUT_INFLATER_SERVICE);c. LayoutInflater inflater = LayoutInflater.from(context);onDraw ⽅法绘图,invalidate刷新界⾯。

效果图:点击⼀下换颜⾊onDraw画完图后,给控件设置点击事件 ,将参数传到控件⾥,然后invalidate刷新1.onDraw画图,并增加changeColor⽅法public class CusView3 extends View {private int color = 0;public CusView3(Context context, AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);Paint mPaint = new Paint();if (color > 2) {color = 0;}switch (color) {case 0:mPaint.setColor(Color.GREEN);break;case 1:mPaint.setColor(Color.RED);break;case 2:mPaint.setColor(Color.BLUE);break;default:break;}mPaint.setStyle(Style.FILL);mPaint.setTextSize(35.0f);canvas.drawText("点击我刷新", 10, 60, mPaint);}public void changeColor() { //为了让外⾯调⽤color++;}}2.布局<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><xue.test.CusView3android:id="@+id/cusview3"android:layout_width="wrap_content"android:layout_height="wrap_content"></xue.test.CusView3></LinearLayout>3.画图后给控件设置点击事件 ,将参数传到控件⾥,然后invalidate刷新public class TestCustomViewActivity extends Activity {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.main);view3 = (CusView3) findViewById(R.id.cusview3);// 点击事件view3.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Message message = new Message();message.what = 1;myHandler.sendMessage(message);}});}Handler myHandler = new Handler() {// 接收到消息后处理public void handleMessage(Message msg) {switch (msg.what) {case 1:// 调⽤⽅法view3.changeColor();// 刷新⽅法view3.invalidate();break;}super.handleMessage(msg);}};private CusView3 view3;}⾄于⾃定义控件占整屏的问题,可能需要⽤layoutparams以上所述是⼩编给⼤家介绍的Android⾃定义View控件实现刷新效果,希望对⼤家有所帮助,如果⼤家有任何疑问欢迎给我留⾔,⼩编会及时回复⼤家的!。

SwipeRefreshLayout+RecyclerView实现上拉刷新和下拉刷新功能

SwipeRefreshLayout+RecyclerView实现上拉刷新和下拉刷新功能

SwipeRefreshLayout+RecyclerView实现上拉刷新和下拉刷新功能SwipeRefreshLayout 是⾕歌公司推出的⽤于下拉刷新的控件,SwipeRefreshLayout已经被放到了sdk中,在Version 19.1之后SwipeRefreshLayout 被放到support v4中。

源码在SDK\sdk\extras\android\support\v4\src\java\android\support\v4\widget\SwipeRefreshLayout.java⾕歌公司只提供了下拉刷新的功能,RecyclerView的出现基本就是为了替代ListView,GridView的。

今天说⼀下最常见的下拉刷新和上拉刷新的功能。

布局⽂件:<android.support.v4.widget.SwipeRefreshLayoutxmlns:android="/apk/res/android"xmlns:tools="/tools"android:id="@+id/swipe_refresh_widget"android:layout_width="match_parent"android:layout_height="match_parent" ><android.support.v7.widget.RecyclerViewandroid:id="@android:id/list"android:layout_width="match_parent"android:layout_height="match_parent"android:cacheColorHint="@null"android:scrollbars="vertical" /></android.support.v4.widget.SwipeRefreshLayout>在Activity中引⽤这个布局并初始化@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);mSwipeRefreshWidget = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_widget);mRecyclerView = (RecyclerView) findViewById(android.R.id.list);mSwipeRefreshWidget.setColorScheme(R.color.color1, R.color.color2,R.color.color3, R.color.color4);mSwipeRefreshWidget.setOnRefreshListener(this);// 这句话是为了,第⼀次进⼊页⾯的时候显⽰加载进度条mSwipeRefreshWidget.setProgressViewOffset(false, 0, (int) TypedValue.applyDimension(PLEX_UNIT_DIP, 24, getResources().getDisplayMetrics()));mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic void onScrollStateChanged(RecyclerView recyclerView,int newState) {super.onScrollStateChanged(recyclerView, newState);if (newState == RecyclerView.SCROLL_STATE_IDLE&& lastVisibleItem + 1 == adapter.getItemCount()) {mSwipeRefreshWidget.setRefreshing(true);// 此处在现实项⽬中,请换成⽹络请求数据代码,sendRequest .....handler.sendEmptyMessageDelayed(0, 3000);}}@Overridepublic void onScrolled(RecyclerView recyclerView, int dx, int dy) {super.onScrolled(recyclerView, dx, dy);lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();}});mRecyclerView.setHasFixedSize(true);mLayoutManager = new LinearLayoutManager(this);mRecyclerView.setLayoutManager(mLayoutManager);mRecyclerView.setItemAnimator(new DefaultItemAnimator());adapter = new SampleAdapter();mRecyclerView.setAdapter(adapter);// 此处在现实项⽬中,请换成⽹络请求数据代码,sendRequest .....handler.sendEmptyMessageDelayed(0, 3000);}SwipeRefreshLayout⾥⾯需要注意的Api:1、setOnRefreshListener(OnRefreshListener listener) 设置下拉监听,当⽤户下拉的时候会去执⾏回调2、setColorSchemeColors(int... colors) 设置进度条的颜⾊变化,最多可以设置4种颜⾊3、setProgressViewOffset(boolean scale, int start, int end) 调整进度条距离屏幕顶部的距离4、setRefreshing(boolean refreshing) 设置SwipeRefreshLayout当前是否处于刷新状态,⼀般是在请求数据的时候设置为true,在数据被加载到View中后,设置为false。

Android开发RecyclerView上拉加载更多功能实现

Android开发RecyclerView上拉加载更多功能实现

Android开发RecyclerView上拉加载更多功能实现实现思维 开始之前先废话⼏句,Android系统没有提供上拉加载的控件,只提供了下拉刷新的SwipeRefreshLayout控件。

这个控件我们就不废话,⽆法实现上拉刷新的功能。

现在我们说说上拉加载更多的功能实现 思维步骤:1. ⾸先我们需要⾃定义重写RecyclerView,这个是重点.原因是,如果不重写RecyclerView会出现ItemView的点击与滑动的时候有事件分发冲突的问题(滑动⽆法得到down的触摸事件,或者点击⽆法得到up的触摸事件),我们重写RecyclerView⽬的就是重新分发事件,将down和up事件不被拦截,拦截我们需要的move事件.2. 创建⼀个叫页尾的布局⽂件,它⽤来在列表的最后⾯显⽰使⽤3. 接着我们需要想办法在RecyclerView.Adapter的适配器⾥导⼊这个页尾布局。

你的列表内容适配器的普通item该如何实现还是如何实现。

4. 为了导⼊这个页尾布局,我们需要在导⼊的List长度+1,因为这个页尾布局是另外加⼊的,需要在getItemCount()这个重写⽅法⾥返回List长度上+1。

5. 现在就需要判断什么时候滚动到了列表的最后,这个时候我们需要重写⼀个之前写RecyclerView.Adapter适配器⼀般不触及的⼀个重写⽅法public int getItemViewType(int position) 。

重写它根据position位置返回普通item和页尾item的ViewType。

6. 能判断什么时候滚动到最后⾯后,我们就需要在写RecyclerView.Adapter适配器⼀样在onCreateViewHolder⽅法⾥导⼊布局,这⾥我们可以根据ViewType判断应该导⼊普通item还是页尾item7. 然后就是处理点击逻辑或者处理刷新逻辑了。

在部分在activity中实现代码部分重写RecyclerView:public class UpLoadingRecyclerView extends RecyclerView {private static final String TAG = "MyRecyclerView";private boolean isScroll;private float downY;private int mHeightPixels;private OnUpScrollListener mOnUpScrollListener;public UpLoadingRecyclerView(@NonNull Context context) {super(context);DisplayMetrics displayMetrics = getResources().getDisplayMetrics();mHeightPixels = displayMetrics.heightPixels;}public UpLoadingRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);DisplayMetrics displayMetrics = getResources().getDisplayMetrics();mHeightPixels = displayMetrics.heightPixels;}public UpLoadingRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);DisplayMetrics displayMetrics = getResources().getDisplayMetrics();mHeightPixels = displayMetrics.heightPixels;}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {return super.dispatchTouchEvent(ev);}/*** 重写拦截的⽬的是只拦截移动事件,不拦截其他触摸事件* @param e* @return*/@Overridepublic boolean onInterceptTouchEvent(MotionEvent e) {super.onInterceptTouchEvent(e);//⼀定要super.onInterceptTouchEvent(e);不要让RecyclerView的其他事件分发受到影响,否则会出现不滚动的问题switch (e.getAction()){case MotionEvent.ACTION_DOWN:isScroll = false;//按下不拦截downY = e.getY();break;case MotionEvent.ACTION_MOVE:if (Math.abs(downY - e.getY()) >= ViewConfiguration.get(getContext()).getScaledTouchSlop()) {//判断是否产⽣了最⼩滑动isScroll = true;//移动了拦截触摸事件} else {isScroll = false;}break;case MotionEvent.ACTION_UP:isScroll = false;//松开不拦截break;}return isScroll;}@Overridepublic boolean onTouchEvent(MotionEvent e) {switch (e.getAction()){case MotionEvent.ACTION_DOWN:return true;case MotionEvent.ACTION_MOVE:break;case MotionEvent.ACTION_UP:if (downY-e.getY() > mHeightPixels/3){//判断是不是从下往上滑动了屏幕的三分之⼀if (mOnUpScrollListener!=null) {mOnUpScrollListener.onScroll();Log.e(TAG, "onTouchEvent:滚动了");}}break;}return super.onTouchEvent(e);}public void setOnUpScrollListener(OnUpScrollListener listener){this.mOnUpScrollListener = listener;}public interface OnUpScrollListener{void onScroll();}}页尾布局 pull_up_refresh.xml:<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayoutxmlns:app="/apk/res-auto"xmlns:android="/apk/res/android"android:background="@color/colorGray5"android:layout_width="match_parent"android:layout_height="30dp"><ProgressBarandroid:id="@+id/footer_progress"android:layout_width="14dp"android:layout_height="14dp"android:layout_marginRight="10dp"android:visibility="gone"android:indeterminateDrawable="@anim/pull_up_ic"app:layout_constraintHorizontal_chainStyle="packed"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toTopOf="@id/footer_text"app:layout_constraintBottom_toBottomOf="@id/footer_text"app:layout_constraintRight_toLeftOf="@id/footer_text"/><TextViewandroid:id="@+id/footer_text"android:text="@string/pull_up_load_more"android:textColor="@color/fontBlack3"android:textSize="@dimen/font_size_14"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintLeft_toRightOf="@id/footer_progress"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"/></androidx.constraintlayout.widget.ConstraintLayout>ProgressBar是刷新加载时候的动画图⽚TextView就是⽂本内容适配器代码public class TNoticeListAdapter extends RecyclerView.Adapter<TNoticeListAdapter.ViewHolder> {private List<TNoticeListBase.Notice> mList;private static final int ITEM_VIEW = 1;private static final int FOOTER_VIEW = 2;public static final int FOOTER_TIPS = 0;//提⽰上拉加载更多public static final int FOOTER_ING = 1;//加载中public static final int FOOTER_ERROR = 2;//⽹络异常public static final int FOOTER_FINISH = 3;//没有更多内容private int footerState = 0;private View mFooterView;private OnFooterClickListener mFooterClickListener;private OnItemClickListener mItemClickListener;private int mScrollPosition;public TNoticeListAdapter(List<TNoticeListBase.Notice> list){this.mList = list;}@NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {if (viewType == ITEM_VIEW){View itemView = LayoutInflater.from(parent.getContext()).inflate(yout.t_notice_item,parent,false);final ViewHolder viewHolder = new ViewHolder(itemView);itemView.setOnClickListener(new View.OnClickListener() { //传出item的点击@Overridepublic void onClick(View v) {if (mItemClickListener!=null){int postion = viewHolder.getAdapterPosition();mItemClickListener.onClick(mList.get(postion).code);}}});return viewHolder;}else {mFooterView = LayoutInflater.from(parent.getContext()).inflate(yout.pull_up_refresh,parent,false);mFooterView.setOnClickListener(new View.OnClickListener() { //传出页尾View的点击@Overridepublic void onClick(View v) {if (getFooterState()==FOOTER_ERROR && mFooterClickListener!=null){ //页尾View只在⽹络异常的时候可以被点击 mFooterClickListener.onClick();}}});return new ViewHolder(mFooterView);}}@Overridepublic void onBindViewHolder(@NonNull ViewHolder holder, int position) {setScrollPosition(position);if (getItemViewType(position) == ITEM_VIEW) {TNoticeListBase.Notice data = mList.get(position);holder.itemTime.setText("今天 "+TimeUtil.getHour24(data.time)+":"+TimeUtil.getMinute(data.time));holder.itemContent.setText("\t\t" + data.content);return;} switch (footerState){case FOOTER_TIPS:holder.footerText.setText(R.string.pull_up_load_more);holder.footerProgress.setVisibility(View.GONE);break;case FOOTER_ING:holder.footerText.setText(R.string.loading_more_for_you);holder.footerProgress.setVisibility(View.VISIBLE);break;case FOOTER_ERROR:holder.footerText.setText(work_exception_click_reload);holder.footerProgress.setVisibility(View.GONE);break;case FOOTER_FINISH:holder.footerText.setText(R.string.Theres_nothing_more); holder.footerProgress.setVisibility(View.GONE);break;default:holder.footerText.setText(R.string.pull_up_load_more);holder.footerProgress.setVisibility(View.GONE);break;}}@Overridepublic int getItemViewType(int position) {//根据itemView的位置返回View的类型是普通还是页尾if (position == getItemCount()-1){return FOOTER_VIEW;}else {return ITEM_VIEW;}}@Overridepublic int getItemCount() {return mList.size()==0?0:mList.size()+1;}/*** 得到页尾状态* @return*/public int getFooterState() {return footerState;}/*** 设置页尾状态* @param footerState*/public void setFooterState(int footerState) {this.footerState = footerState;notifyDataSetChanged();}/*** 设置页尾点击监听* @param listener*/public void setFooterClickListener(OnFooterClickListener listener){ this.mFooterClickListener = listener;}/*** 设置item的点击监听* @param listener*/public void setItemClickListener(OnItemClickListener listener){this.mItemClickListener = listener;}/*** 添加数据⽅法* @param list*/public void addData(List<TNoticeListBase.Notice> list){this.mList = list;}/*** 得到滚动位置* @return*/public int getScrollPosition() {return mScrollPosition;}/*** 设置滚动位置⽤于判断当前RecyclerView有没有滚动到最后* @param position*/private void setScrollPosition(int position) {this.mScrollPosition = position;}public class ViewHolder extends RecyclerView.ViewHolder {TextView itemTime;TextView itemContent;TextView footerText;ProgressBar footerProgress;public ViewHolder(@NonNull View itemView) {super(itemView);if (mFooterView!=null && itemView == mFooterView){footerProgress = (ProgressBar)itemView.findViewById(R.id.footer_progress);footerText = (TextView)itemView.findViewById(R.id.footer_text);}else {itemTime = (TextView) itemView.findViewById(R.id.time);itemContent = (TextView) itemView.findViewById(R.id.content);}}}public interface OnFooterClickListener{void onClick();}public interface OnItemClickListener{void onClick(String code);}}在activity⾥的实现public class TNoticeListActivity extends BaseActivity {private UpLoadingRecyclerView mRecyclerView;private SwipeRefreshLayout mSwitchRefresh;private TNoticeListAdapter mAdapter;private LinearLayoutManager mLinearLayoutManager;private List<TNoticeListBase.Notice> mNoticeList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);initData();initClick();}@Overridepublic int getLayout() {return yout.activity_t_notice;}@Overridepublic void initView() {mRecyclerView = (RecyclerView)findViewById(R.id.recyclerview);mLinearLayoutManager = new LinearLayoutManager(this);mRecyclerView.setLayoutManager(mLinearLayoutManager);}/*** 模拟数据*/public void initData(){mNoticeList = new ArrayList<>();for (int i=0;i<2;i++){TNoticeListBase.Notice notice = new TNoticeListBase().new Notice();notice.time = 1547604994000L+i;notice.content = "这是⼀个测试⽤的通知内容这是⼀个测试⽤的通知内容这是⼀个测试⽤的通知内容"+i; notice.code = "dsfa13c1z616v5"+i;mNoticeList.add(notice);}mAdapter = new TNoticeListAdapter(mNoticeList);mRecyclerView.setAdapter(mAdapter);}/*** 添加加载模拟数据*/public void addData(){for (int i=0;i<10;i++){TNoticeListBase.Notice notice = new TNoticeListBase().new Notice();notice.time = 1547604994000L+i;notice.content = "这是⼆个测试⽤的通知内容"+i;notice.code = "dsfa13c1z616v5"+i;mNoticeList.add(notice);}mAdapter.addData(mNoticeList);mAdapter.setFooterState(TNoticeListAdapter.FOOTER_TIPS);}public void initClick(){mRecyclerView.setOnUpScrollListener(new UpLoadingRecyclerView.OnUpScrollListener() {@Overridepublic void onScroll() {if (mAdapter.getItemCount()-1 == mAdapter.getPosition() && mAdapter.getFooterState() == TNoticeListAdapter.FOOTER_TIPS){mAdapter.setFooterState(TNoticeListAdapter.FOOTER_ING);//加载中的逻辑L.e("正在加载中");new Thread(new Runnable() {//模拟数据加载@Overridepublic void run() {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}runOnUiThread(new Runnable() {@Overridepublic void run() {addData();}});}}).start();}}});mAdapter.setFooterClickListener(new TNoticeListAdapter.OnFooterClickListener() {@Overridepublic void onClick() {L.e("⽹络异常点击了");}});mAdapter.setItemClickListener(new TNoticeListAdapter.OnItemClickListener() {@Overridepublic void onClick(String code) {L.e("item被点击了");}});mSwitchRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {@Overridepublic void onRefresh() {Toast.makeText(TNoticeListActivity.this, "没有更多数据了", Toast.LENGTH_SHORT).show();mSwitchRefresh.setRefreshing(false);//刷新事件结束}});}}判断数据长度不够,提⽰已经是最新数据的办法,此⽅法可以在Activity⾥创建:private final int PAGE_SIZE = 20;private void downRefresh(List<TNoticeListBase.Notice> noticeList) {mAdapter.addData(noticeList);if (noticeList.size() < PAGE_SIZE) { //如果从服务器上获取的数据长度⼩于发送过去的⼀页长度,说明服务器没有数据了.页尾就显⽰没有更多数据 mAdapter.setFooterState(TNoticeListAdapter.FOOTER_FINISH);} else {mAdapter.setFooterState(TNoticeListAdapter.FOOTER_TIPS);}}。

Android自定义控件ScrollView实现上下滑动功能

Android自定义控件ScrollView实现上下滑动功能

Android⾃定义控件ScrollView实现上下滑动功能本⽂实例为⼤家分享了Android ScrollView实现上下滑动功能的具体代码,供⼤家参考,具体内容如下package com.example.zhuang;import android.content.Context;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.WindowManager;import android.widget.Scroller;public class MyScrollView extends ViewGroup {private int mScreeHeight;//屏幕⾼度private Scroller mScroller;private int mLastY;private int mStart;private int mEnd;private Context context;public MyScrollView(Context context) {super(context);initView(context);}public MyScrollView(Context context, AttributeSet attrs) {super(context, attrs);initView(context);}public MyScrollView(Context context, AttributeSet attrs,int defStyleAttr) {super(context, attrs, defStyleAttr);initView(context);}private void initView(Context context) {WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);//DisplayMetrics 类提供了⼀种关于显⽰的通⽤信息,如显⽰⼤⼩,分辨率和字体。

XRecyclerView实现下拉刷新、滚动到底部加载更多等功能

XRecyclerView实现下拉刷新、滚动到底部加载更多等功能

XRecyclerView实现下拉刷新、滚动到底部加载更多等功能介绍:⼀个实现了下拉刷新,滚动到底部加载更多以及添加header功能的的RecyclerView。

使⽤⽅式和RecyclerView完全⼀致,不需要额外的layout,不需要写特殊的adater。

加载效果内置了AVLoadingIndicatorView上的所有效果,可以根据需要指定。

效果:使⽤:xml<RelativeLayout xmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><com.jcodecraeer.xrecyclerview.XRecyclerViewandroid:id="@+id/recyclerview"android:layout_width="fill_parent"android:layout_height="fill_parent" /></RelativeLayout>2.MainActivitypackage com.example.xrecyclerview;import android.os.Bundle;import android.os.Handler;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.LinearLayoutManager;import youtInflater;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;import com.jcodecraeer.xrecyclerview.ProgressStyle;import com.jcodecraeer.xrecyclerview.XRecyclerView;import java.util.ArrayList;public class MainActivity extends AppCompatActivity {private XRecyclerView mRecyclerView;private MyAdapter mAdapter;private ArrayList<String> listData;private int refreshTime = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);mRecyclerView = (XRecyclerView)this.findViewById(R.id.recyclerview);LinearLayoutManager layoutManager = new LinearLayoutManager(this);layoutManager.setOrientation(LinearLayoutManager.VERTICAL);mRecyclerView.setLayoutManager(layoutManager);mRecyclerView.setRefreshProgressStyle(ProgressStyle.BallSpinFadeLoader);mRecyclerView.setLaodingMoreProgressStyle(ProgressStyle.Pacman);mRecyclerView.setArrowImageView(R.drawable.iconfont_downgrey);View header = LayoutInflater.from(this).inflate(yout.recyclerview_header, (ViewGroup)findViewById(android.R.id.content),false); mRecyclerView.addHeaderView(header);mRecyclerView.setLoadingListener(new XRecyclerView.LoadingListener() {@Overridepublic void onRefresh() {refreshTime ++;new Handler().postDelayed(new Runnable(){public void run() {listData.clear();for(int i = 0; i < 15 ;i++){listData.add("item" + i + "after " + refreshTime + " times of refresh");}mAdapter.notifyDataSetChanged();mRecyclerView.refreshComplete();}}, 3000); //refresh data here}@Overridepublic void onLoadMore() {new Handler().postDelayed(new Runnable(){public void run() {for(int i = 0; i < 15 ;i++){listData.add("item" + (i + listData.size()) );}mAdapter.notifyDataSetChanged();mRecyclerView.loadMoreComplete();}}, 3000);}});listData = new ArrayList<String>();mAdapter = new MyAdapter(listData);for(int i = 0; i < 15 ;i++){listData.add("item" + i);}mRecyclerView.setAdapter(mAdapter);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.menu_main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.int id = item.getItemId();//noinspection SimplifiableIfStatementif (id == R.id.action_settings) {return true;}return super.onOptionsItemSelected(item);}}3. adapterpackage com.example.xrecyclerview;import android.support.v7.widget.RecyclerView;import youtInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import java.util.ArrayList;/*** Created by jianghejie on 15/11/26.*/public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {public ArrayList<String> datas = null;public MyAdapter(ArrayList<String> datas) {this.datas = datas;}//创建新View,被LayoutManager所调⽤@Overridepublic ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {View view = LayoutInflater.from(viewGroup.getContext()).inflate(yout.item,viewGroup,false); ViewHolder vh = new ViewHolder(view);return vh;}//将数据与界⾯进⾏绑定的操作@Overridepublic void onBindViewHolder(ViewHolder viewHolder, int position) {viewHolder.mTextView.setText(datas.get(position));}//获取数据的数量@Overridepublic int getItemCount() {return datas.size();}//⾃定义的ViewHolder,持有每个Item的的所有界⾯元素public static class ViewHolder extends RecyclerView.ViewHolder {public TextView mTextView;public ViewHolder(View view){super(view);mTextView = (TextView) view.findViewById(R.id.text);}}以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
//这个地方是有遗留的问题的最后还需要处理
北京千锋互联科技有限公司 版权所有
ht tp ://www.mobilet /
if(PullUpLoadView.getDownLoadingOrNot()){ return;
} mICallBack.notifactionAbovePage(LOAD); } } } }
} /**
* 定义一个接口回调到 Activity 页面 */ public interface PullCallBack{
public void load(); public void refresh(); } PullCallBack mPullCallBack=null;
public void setPullCallBacklistener(PullCallBack mPullCallBack ){ this.mPullCallBack=mPullCallBack;
ht tp ://www.mobilet /
} }
MyScrollView
public class MyScrollView extends ScrollView{ private static final String LOAD="load"; //表示的是加载数据的状态 private static final String REFRESH="refresh"; //表示的是需要刷新页面的状态 public MyScrollView(Context context, AttributeSet attrs) {
this.mICallBack=mICallBack; } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt); if(getChildAt(0)!=null){ //有这个孩子才有意义的
View childView=getChildAt(0); //第二步:通过孩子获取孩子本身的高度 int childMeasuredHeight = childView.getMeasuredHeight(); //第三步:获取屏幕顶部的相对 y 坐标 int scrollY = getScrollY(); //屏幕顶部相对的 y 坐标 //第四步:获取当前屏幕的高度 int screenHeight=getHeight(); if(scrollY+screenHeight==childMeasuredHeight){ //说明滑动到底部了?
mMyGridView= (MyGridView) findViewById(R.id.gridView); footView= (LinearLayout) findViewById(R.id.footView); mMyScrollView= (MyScrollView) findViewById(R.id.myScrollView); } /** * 返回 GridView * @return */ public MyGridView getMyGridView(){ return mMyGridView; } /** * 设置 footView 影藏 */
} } };
/** * 获取是否正在加载数据的这个状态 * @return */
北京千锋互联科技有限公司 版权所有
ht tp ://www.mobilet /
public static boolean getDownLoadingOrNot(){ return downLoadingOrNot;
int heighMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heighMeasureSpec);
北京千锋互联科技有限公司 版权所有
北京千锋互联科技有限公司 版权所有
ht tp ://www.mobilet /
//在这个地方我们书不是需要将这个状态发送到 Activity 这个页面去 mPullCallBack.load(); handler.sendEmptyMessage(100); downLoadingOrNot=true; //表示的额是正在加载 }else{ //说明需要刷新数据
super(context, attrs); initView(); } /** * 初始化数据用的 */ private void initView() { //初始化布局加载器 LayoutInflater mLayoutInflater= (LayoutInflater) getContext().getSystemService(YOUT_INFLATER_SERVICE); View view=mLayoutInflater.inflate(yout.scroll_grid_footview,this); //这句 话的意思是把当前的布局绑定给谁
super(context, attrs); } interface ICallBack{
public void notifactionAbovePage(String tag); } ICallBack mICallBack=null; public void setOnCallBackLister(ICallBack mICallBack){
北京千锋互联科技有限公司 ilet /
super.onMeasure(widthMeasureSpec, heightMeasureSpec); }
3:需要解决什么时候滑动到了底部和顶部 解决方案:可以通过计算 ScrollView 孩子的高度,以及当前孩子滑动的顶部的相对的 Y 的偏移量 getScrollY 和当前窗体的高度 getHeight.如果 getScrollY+getHeight>=孩子的 高度,说明滑动到底部了 4:解决问题:ScrollView 知道了什么时候滑动到底部,如何将上级的状态 解决方案:直接通过回调的方法将状态在传递到上级页面 5:整合所有的对象 源代码如下: GridView public class MyGridView extends GridView { public MyGridView(Context context, AttributeSet attrs, int defStyleAttr) {
} /**
* 说明数据已经加载完成 * 这个方法是 Activity 调用的 */ public void dataDone(){
handler.sendEmptyMessage(101); } /**
* 找下那个 View * @param view */ private void findView(View view) {
super(context, attrs, defStyleAttr); } public MyGridView(Context context) {
super(context); } public MyGridView(Context context, AttributeSet attrs) {
super(context, attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
} } } //刷新 UI Handler handler=new Handler(){ @Override public void handleMessage(Message msg) {
switch (msg.what){ case 100: //表示的是需要显示底部的 View setFootViewVisible(); break; case 101: //表示的是需要隐藏底部的 View setFootViewHide(); downLoadingOrNot=false; break;
} /**
* 上一个页面回调的状态 */ private class OnCallBack implements MyScrollView.ICallBack{
@Override public void notifactionAbovePage(String tag) {
if(tag.equals(LOAD)){ //说明需要加载数据
2:ScrollView 中嵌套 GridView 的时候会造成显示不全的问题,需要解决 ScrollView 计算孩子高度的问题
解决方案:可以重写 GridView 中的 onMeasure()方法,然后给定孩子高度的最大值,然后 再设计一个测量的模式.
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expectHeight=MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MO ST);
PullUpLoadView
public class PullUpLoadView extends LinearLayout{ private static final String LOAD="load"; //表示的是加载数据的状态 private static final String REFRESH="refresh";//表示的是需要刷新页面的状态 MyGridView mMyGridView; LinearLayout footView; MyScrollView mMyScrollView; static boolean downLoadingOrNot=false; //判断当前是否正在加载数据 public PullUpLoadView(Context context, AttributeSet attrs) {
相关文档
最新文档