版权声明:欢迎分享,但请注明出处,谢谢 https://blog.csdn.net/qq_28057577/article/details/78234178
前言:
在
Android实战(橘子娱乐)-首页(第二篇 首页布局与Activity代码)中我们讲解了首页布局xml文件和,MainActivity的核心逻辑代码。然后呢说这篇会讲解一下,IRecyclerView自定义刷新头ClassicRefreshHeaderView的实现,这一个系列的文章都有关联性,如果只是看其中一篇或者跳篇看的话可能思路不是很清晰,所以建议重头看起。接下来依然是一张图,可以看看刷新的效果:
其实自定义刷新头都是一些常规的逻辑,只要思路清晰,写代码应该不难,接下来我们看看代码:
ClassicRefreshHeaderView.java
package com.andy.orange.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.andy.orange.R;
import com.aspsine.irecyclerview.RefreshTrigger;
public class ClassicRefreshHeaderView extends RelativeLayout implements RefreshTrigger {
private ImageView ivArrow;
private ImageView ivSuccess;
private TextView tvRefresh;
private ProgressBar progressBar;
private Animation rotateUp;
private Animation rotateDown;
private boolean rotated = false;
private int mHeight;
public ClassicRefreshHeaderView(Context context) {
this(context, null);
}
public ClassicRefreshHeaderView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ClassicRefreshHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//加载布局
inflate(context, R.layout.irecyclerview_refresh_header_view, this);
//初始化view
tvRefresh = (TextView) findViewById(R.id.tvRefresh);
ivArrow = (ImageView) findViewById(R.id.ivArrow);
ivSuccess = (ImageView) findViewById(R.id.ivSuccess);
progressBar = (ProgressBar) findViewById(R.id.progressbar);
//向上旋转动画
rotateUp = AnimationUtils.loadAnimation(context, R.anim.rotate_up);
//向下旋转
rotateDown = AnimationUtils.loadAnimation(context, R.anim.rotate_down);
}
@Override
public void onStart(boolean automatic, int headerHeight, int finalHeight) {
this.mHeight = headerHeight;
progressBar.setIndeterminate(true);
}
@Override
public void onMove(boolean isComplete, boolean automatic, int moved) {
if (!isComplete) {
//设置显示向下的箭头、隐藏进度条和成功图标
ivArrow.setVisibility(VISIBLE);
progressBar.setVisibility(GONE);
ivSuccess.setVisibility(GONE);
//根据临界高度,判断是否刷新
if (moved <= mHeight) {
if (rotated) {
ivArrow.clearAnimation();
ivArrow.startAnimation(rotateDown);
rotated = false;
}
tvRefresh.setText("下拉刷新");
} else {
tvRefresh.setText("释放刷新");
if (!rotated) {
ivArrow.clearAnimation();
ivArrow.startAnimation(rotateUp);
rotated = true;
}
}
}
}
@Override
public void onRefresh() {
//刷新时设置显示进度条和“正在刷新”提示
ivSuccess.setVisibility(GONE);
ivArrow.clearAnimation();
ivArrow.setVisibility(GONE);
progressBar.setVisibility(VISIBLE);
tvRefresh.setText("正在刷新");
}
@Override
public void onRelease() {
}
@Override
public void onComplete() {
//刷新完成以后,显示刷新完成
rotated = false;
ivSuccess.setVisibility(VISIBLE);
ivArrow.clearAnimation();
ivArrow.setVisibility(GONE);
progressBar.setVisibility(GONE);
tvRefresh.setText("刷新完成");
}
@Override
public void onReset() {
rotated = false;
ivSuccess.setVisibility(GONE);
ivArrow.clearAnimation();
ivArrow.setVisibility(GONE);
progressBar.setVisibility(GONE);
}
}
分析:其实思路就是在类的构造函数中去加载布局,然后
让类去继承IRecyclerView关联的RefreashTrigger接口实现在不同状态中做不同的操作,比如刷新前显示刷新前的图片、刷新时候显示刷新的图片,刷新结束后显示刷新结束的图片。
接下来是inflate的布局文件:
irecyclerview_refresh_header_view.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp">
<ImageView
android:id="@+id/ivArrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="48dp"
android:layout_toLeftOf="@+id/tvRefresh"
android:background="@drawable/expend_bottom" />
<ImageView
android:id="@+id/ivSuccess"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="48dp"
android:layout_toLeftOf="@+id/tvRefresh"
android:background="@drawable/refresh_end" />
<ProgressBar
android:id="@+id/progressbar"
style="?android:attr/progressBarStyleSmallInverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="48dp"
android:layout_toLeftOf="@+id/tvRefresh" />
<TextView
android:id="@+id/tvRefresh"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center" />
</merge>
比较简单,这里就不讲了,主要讲讲其中的rotateUp和rotateDown两个动画,其实就是实现下拉高度大于刷新头高度时,实现ImageView也就是向下的箭头向上旋转180度,在下拉高度低于刷新头高度时向下旋转180度。我们来看看其中一个文件:
rotate_down.xml
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="150"
android:fillAfter="true"
android:fromDegrees="-180"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="0"
android:toDegrees="0"
android:interpolator="@android:anim/linear_interpolator"
/>
<!--
android:fillAfter="true"//设置保存结束时的状态
android:fromDegrees="-180" android:toDegrees="0"//表示旋转的开始和结束角度
android:pivotX="50%" android:pivotY="50%"//设置旋转的中心点
android:repeatCount="0"//设置重复次数
android:interpolator="@android:anim/linear_interpolator"//设置在旋转过程中的速度变化
android:duration="150"//不用讲是动画时长
-->
注释都很清楚,rotate_up.xml就不贴出来了,伙伴儿可以试着自己写,我相信你可以的。其实第二篇中我们有用到
SharedPreferencesUtils这个工具类,但是没有实际讲他里面我都封装了些什么,接下来我们来看看这个工具类的代码:
package com.andy.orange.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
/**
* Created by Andy Lau on 2017/8/10.
*/
public class SharedPreferencesUtils {
private static final String TAG ="Andy";
private static SharedPreferences sp;
private static void init(Context context) {
if (sp == null) {
Log.d(TAG,context.toString());
sp=context.getSharedPreferences("login_preferences",Context.MODE_PRIVATE);
}
}
public static void setSharedData(Context context, String key, Object value, String type){
if (type.isEmpty()) {
return;
}
if (sp == null) {
init(context);
}
if (type.equals("int")){
sp.edit().putInt(key,(int)value).commit();
}else if (type.equals("string")){
sp.edit().putString(key,(String)value).commit();
}else if (type.equals("boolean")){
sp.edit().putBoolean(key,(boolean)value).commit();
}else if (type.equals("float")){
sp.edit().putFloat(key,(float)value).commit();
}else {
sp.edit().putLong(key,(long)value).commit();
}
}
public static Object readSharedData(Context context, String key, String type){
Object result = null;
if (type.isEmpty()) {
return null;
}
if (sp == null) {
init(context);
}
if (type.equals("int")){
result=sp.getInt(key,0);
}else if (type.equals("string")){
result=sp.getString(key,"");
}else if (type.equals("boolean")){
result=sp.getBoolean(key,false);
}else if (type.equals("float")){
result=sp.getFloat(key,0f);
}else {
result=sp.getLong(key,0L);
}
return result;
}
}
比较简单就是建一个叫
login_preferences 的SharedPreferences保存登录状态信息,另外封装两个读和写的方法,提供使用。ok,这篇的任务完成,接下来我们会学习一下,首页IRecyclerView的适配器
MainRecyclerViewAdapter 部分的实现逻辑,看他是如何将数据和布局绑定在一起的。