一,自定义自己项目的刷新效果:
很多时候我们项目也许需要自己的刷新效果。如果我们达不到那种自定义刷新控件的力,那么来看看这篇文章吧!!!基于(TwinklingRefreshLayout和SwipeToLoadLayout)都是给变头布局来实现的。
二,看看我们公司的需求:
刚下拉时候,有一个小医生慢慢出现变大变亮,后面一个下拉刷新的文字,当松开手时候文字变
为正在刷新中。
上啦加载时候:同样一个医生出现变大变亮。
三,实现过程:
1,需要很多的图片你不会ps么?找美工吧。反正我会我自己ps搞的图片但时候在项目中有的。
来个图片不然你们不信:我把48x48最为最大,然后ps图像大小然后逐个变小储存。
2,我们来新建一个项目吧!然后进入gradle里面写去依赖这句话
compile ‘com.lcodecorex:tkrefreshlayout:1.0.3’就可以用TwinklingRefreshLayout了。
3,我们来进行基本的布局和适配器吧这个都会的。
布局:
<?xml version="1.0" encoding="utf-8"?>
<com.lcodecore.tkrefreshlayout.TwinklingRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:id="@+id/refreshLayout"
android:scrollbars="none"
android:layout_height="match_parent"
>
<android.support.v7.widget.RecyclerView
android:background="#ffffff"
android:layout_below="@+id/ling_item1"
android:id="@+id/activity_last_infor_rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.lcodecore.tkrefreshlayout.TwinklingRefreshLayout>
适配器:
/**
* Created by ls on 2017/11/14.
*/
public class LastInforAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
private List<String> mData;
public LastInforAdapter(Context mContext, List<String> mData) {
this.mContext = mContext;
this.mData = mData;
}
@Override
public int getItemCount() {
return mData == null ? 0 : mData.size();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.my_item, null);
FirstViewHolder holder = new FirstViewHolder(view, mContext);
return holder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
FirstViewHolder holder1 = (FirstViewHolder) holder;
holder1.setData(mData.get(position), position);
}
class FirstViewHolder extends RecyclerView.ViewHolder {
private Context mContex;
private TextView first_view;
public FirstViewHolder(View itemView, Context mContex) {
super(itemView);
this.mContex = mContex;
first_view=itemView.findViewById(R.id.tv_my);
}
public void setData(String str, final int position) {
first_view.setText(str);
}
}
}
最重要的来了。一个好的开源框架不可能不提供给开发者拓展的接口。那么我们去看看源码呗:
首先我们直接运行我们会发现有默认的刷新效果如下:
既然有默认的我们可以点击该控件进去看看源码:
我们会发现一些熟悉的变量:
//子控件
private View mChildView;
//头部layout
protected FrameLayout mHeadLayout;
private IHeaderView mHeadView;
private IBottomView mBottomView;
//底部高度
private float mBottomHeight;
//底部layout
private FrameLayout mBottomLayout;
//刷新的状态
protected boolean isRefreshing;
//加载更多的状态
protected boolean isLoadingmore;
//是否需要加载更多,默认需要
protected boolean enableLoadmore = true;
//是否需要下拉刷新,默认需要
protected boolean enableRefresh = true;
//是否在越界回弹的时候显示下拉图标
protected boolean isOverlayRefreshShow = true;
其中有一个
//头部layout
protected FrameLayout mHeadLayout;
我们看注释就知道头部的layout,然后我们顺藤摸瓜,找到这里:
//添加头部
if (mHeadLayout == null) {
FrameLayout headViewLayout = new FrameLayout(getContext());
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
layoutParams.gravity = Gravity.TOP;
headViewLayout.setLayoutParams(layoutParams);
mHeadLayout = headViewLayout;
this.addView(mHeadLayout);//addView(view,-1)添加到-1的位置
if (mHeadView == null) setHeaderView(new GoogleDotView(getContext()));
}
//添加底部
if (mBottomLayout == null) {
FrameLayout bottomViewLayout = new FrameLayout(getContext());
LayoutParams layoutParams2 = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
layoutParams2.gravity = Gravity.BOTTOM;
bottomViewLayout.setLayoutParams(layoutParams2);
mBottomLayout = bottomViewLayout;
this.addView(mBottomLayout);
if (mBottomView == null) {
BottomProgressView mProgressView = new BottomProgressView(getContext());
setBottomView(mProgressView);
}
}
我看到这句话:
if (mHeadView == null) setHeaderView(new GoogleDotView(getContext()));
当mHeadView为空时候我们看到有一个GoogleDotView(getContext())谷歌什么view控件来填充,我们
点进去看看呗,我们会发现我去,居然这里搞了那几个圆圈圈动画之类的:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int w = getMeasuredWidth() / num - 10;
for (int i = 0; i < num; i++) {
if (animating) {
switch (i) {
// case 0:
// mPath.setAlpha(35);
// mPath.setColor(getResources().getColor(R.color.Orange));
// canvas.drawCircle(getMeasuredWidth() / 2 - cir_x * 3 - 3 * w / 3 * 2, getMeasuredHeight() / 2, r*fraction2, mPath);
// break;
case 0:
mPath.setAlpha(105);
mPath.setColor(getResources().getColor(R.color.Yellow));
canvas.drawCircle(getMeasuredWidth() / 2 - cir_x * 2 - 2 * w / 3 * 2, getMeasuredHeight() / 2, r * fraction2, mPath);
break;
case 1:
mPath.setAlpha(145);
mPath.setColor(getResources().getColor(R.color.Green));
canvas.drawCircle(getMeasuredWidth() / 2 - cir_x * 1 - w / 3 * 2, getMeasuredHeight() / 2, r * fraction2, mPath);
break;
case 2:
mPath.setAlpha(255);
mPath.setColor(getResources().getColor(R.color.Blue));
canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, r * fraction1, mPath);
break;
case 3:
mPath.setAlpha(145);
mPath.setColor(getResources().getColor(R.color.Orange));
canvas.drawCircle(getMeasuredWidth() / 2 + cir_x * 1 + w / 3 * 2, getMeasuredHeight() / 2, r * fraction2, mPath);
break;
case 4:
mPath.setAlpha(105);
mPath.setColor(getResources().getColor(R.color.Yellow));
canvas.drawCircle(getMeasuredWidth() / 2 + cir_x * 2 + 2 * w / 3 * 2, getMeasuredHeight() / 2, r * fraction2, mPath);
break;
// case 6
我们发现这个GogleDotView实现了IHeaderView 接口,我们去看看吧:
public interface IHeaderView {
View getView();
/**
* 下拉准备刷新动作
* @param fraction 当前下拉高度与总高度的比
* @param maxHeadHeight
* @param headHeight
*/
void onPullingDown(float fraction,float maxHeadHeight,float headHeight);
/**
* 下拉释放过程
* @param fraction
* @param maxHeadHeight
* @param headHeight
*/
void onPullReleasing(float fraction,float maxHeadHeight,float headHeight);
void startAnim(float maxHeadHeight,float headHeight);
void onFinish();
}
好了这里我一切都清除了,我们需要定义一个view类实现这个IHeaderView,和IBottomView接口或者内部类也可以的。这里我两种都搞一稿,必进写在activity内部扩展不太好。由于我太懒,我一个类就同时实现了这两个接口,其实这样感觉少一个类挺简洁的,你们根据自己的喜好弄吧。代码如下:
public class MyGoleView extends View implements IHeaderView, IBottomView {
private Context mcontext;
//这个是下拉式上部的显示文本
private TextView refrush_tv;
//最后给这个图片设置动画就可以了。
private ImageView refrush_image;
//设置帧动画用的
private AnimationDrawable animationDrawable;
//这个用来判断是下拉还是上拉
private int up_down = 0;//默认为上哈哈其他就为下了。
public MyGoleView(Context context, int up_down) {
super(context);
this.mcontext = context;
this.up_down = up_down;
}
public MyGoleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public View getView() {
if (up_down == 0) {
View view = LayoutInflater.from(mcontext).inflate(R.layout.refrush_header, null);
refrush_tv = view.findViewById(R.id.refrush_tv);
refrush_image = view.findViewById(R.id.refrush_image);
return view;
} else {
View view = LayoutInflater.from(mcontext).inflate(R.layout.refrush_bootom, null);
refrush_image = view.findViewById(R.id.refrush_image1);
return view;
}
}
@Override
public void onPullingUp(float fraction, float maxHeadHeight, float headHeight) {
//这里当上啦过过程中的操锁自己试试看。我懒不想研究了。
}
@Override
public void onPullingDown(float fraction, float maxHeadHeight, float headHeight) {
//我在上啦过程中布局里面没有设置文字哦!!看看我的item就知道了
if (refrush_tv != null) {
refrush_tv.setText("下拉刷新");
}
}
@Override
public void onPullReleasing(float fraction, float maxHeadHeight, float headHeight) {
if (refrush_tv != null) {
refrush_tv.setText("正在刷新中");
}
}
@Override
public void startAnim(float maxHeadHeight, float headHeight) {
//这里是我们的动画哦!!!
refrush_image.setBackgroundResource(R.drawable.anim_loading_view);
animationDrawable = (AnimationDrawable)
refrush_image.getBackground();
animationDrawable.start();
}
@Override
public void onFinish() {
animationDrawable.stop();
}
}
第二种就是本类中写,这样真的好么。我不推荐这样写,复用性太差了代码每次写都要一大堆,自己看着办吧,我这里不贴代码了,我的Demon里面有的。运行如下图:
最后github贴出来:https://github.com/luhenchang/FreshDemon_Luhenchang.git