日常备份,下载列表已做好

This commit is contained in:
Yutousama 2018-06-15 16:13:28 +08:00
parent 98d876bfe7
commit 7a1c4f4351
28 changed files with 690 additions and 342 deletions

View File

@ -4,7 +4,6 @@
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/RefreshRecyclerView/RefreshRecyclerView.iml" filepath="$PROJECT_DIR$/RefreshRecyclerView/RefreshRecyclerView.iml" /> <module fileurl="file://$PROJECT_DIR$/RefreshRecyclerView/RefreshRecyclerView.iml" filepath="$PROJECT_DIR$/RefreshRecyclerView/RefreshRecyclerView.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" /> <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/gamedatamodel/gamedatamodel.iml" filepath="$PROJECT_DIR$/gamedatamodel/gamedatamodel.iml" />
<module fileurl="file://$PROJECT_DIR$/jianrmg_v2.iml" filepath="$PROJECT_DIR$/jianrmg_v2.iml" /> <module fileurl="file://$PROJECT_DIR$/jianrmg_v2.iml" filepath="$PROJECT_DIR$/jianrmg_v2.iml" />
</modules> </modules>
</component> </component>

View File

@ -1,14 +1,14 @@
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
android { android {
compileSdkVersion 26 compileSdkVersion 25
buildToolsVersion '27.0.3' buildToolsVersion '27.0.3'
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 15
targetSdkVersion 26 targetSdkVersion 25
versionCode 5 versionCode 6
versionName "1.2.0" versionName "1.3.0"
} }
buildTypes { buildTypes {
release { release {
@ -19,7 +19,7 @@ android {
} }
dependencies { dependencies {
implementation 'com.android.support:recyclerview-v7:26+' implementation 'com.android.support:recyclerview-v7:25.0.0'
} }
ext { ext {
@ -28,7 +28,7 @@ ext {
publishedGroupId = 'cn.lemon' publishedGroupId = 'cn.lemon'
artifact = 'RefreshRecyclerView' artifact = 'RefreshRecyclerView'
libraryVersion = '1.2.0' libraryVersion = '1.4.1'
siteUrl = 'https://github.com/llxdaxia/RefreshRecyclerView' siteUrl = 'https://github.com/llxdaxia/RefreshRecyclerView'
gitUrl = 'https://github.com/llxdaxia/RefreshRecyclerView.git' gitUrl = 'https://github.com/llxdaxia/RefreshRecyclerView.git'

View File

@ -12,7 +12,8 @@ import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.TextView; import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import cn.lemon.view.adapter.Action; import cn.lemon.view.adapter.Action;
import cn.lemon.view.adapter.RecyclerAdapter; import cn.lemon.view.adapter.RecyclerAdapter;
@ -20,13 +21,15 @@ import cn.lemon.view.adapter.RecyclerAdapter;
/** /**
* Created by linlongxin on 2016/1/24. * Created by linlongxin on 2016/1/24.
*/ */
public class RefreshRecyclerView extends FrameLayout { public class RefreshRecyclerView extends FrameLayout implements SwipeRefreshLayout.OnRefreshListener{
private final String TAG = "RefreshRecyclerView"; private final String TAG = "RefreshRecyclerView";
private SwipeRefreshLayout mSwipeRefreshLayout; private SwipeRefreshLayout mSwipeRefreshLayout;
private RecyclerView mRecyclerView; private RecyclerView mRecyclerView;
private RecyclerAdapter mAdapter; private RecyclerAdapter mAdapter;
private boolean loadMoreAble; private List<Action> mRefreshActions;
private boolean mLoadMoreEnable;
private boolean mShowNoMoreEnable;
public RefreshRecyclerView(Context context) { public RefreshRecyclerView(Context context) {
this(context, null); this(context, null);
@ -39,20 +42,29 @@ public class RefreshRecyclerView extends FrameLayout {
public RefreshRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) { public RefreshRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
View view = inflate(context, R.layout.view_refresh_recycler, this); View view = inflate(context, R.layout.view_refresh_recycler, this);
mRecyclerView = view.findViewById(cn.lemon.view.R.id.recycler_view); mRecyclerView = (RecyclerView) view.findViewById(R.id.lemon_recycler_view);
mSwipeRefreshLayout = view.findViewById(R.id.refresh_layout); mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.lemon_refresh_layout);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RefreshRecyclerView); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RefreshRecyclerView);
boolean refreshAble = typedArray.getBoolean(R.styleable.RefreshRecyclerView_refresh_able, true); mLoadMoreEnable = typedArray.getBoolean(R.styleable.RefreshRecyclerView_load_more_enable, true);
loadMoreAble = typedArray.getBoolean(R.styleable.RefreshRecyclerView_load_more_able, true); mShowNoMoreEnable = typedArray.getBoolean(R.styleable.RefreshRecyclerView_show_no_more_enable, true);
if (!refreshAble) { boolean refreshEnable = typedArray.getBoolean(R.styleable.RefreshRecyclerView_refresh_enable, true);
if (!refreshEnable) {
mSwipeRefreshLayout.setEnabled(false); mSwipeRefreshLayout.setEnabled(false);
} else {
mSwipeRefreshLayout.setOnRefreshListener(this);
} }
typedArray.recycle();
} }
public void setAdapter(RecyclerAdapter adapter) { public void setAdapter(RecyclerAdapter adapter) {
if (adapter == null) {
return;
}
mRecyclerView.setAdapter(adapter); mRecyclerView.setAdapter(adapter);
mAdapter = adapter; mAdapter = adapter;
mAdapter.loadMoreAble = loadMoreAble; mAdapter.setLoadMoreEnable(mLoadMoreEnable);
mAdapter.setShowNoMoreEnable(mShowNoMoreEnable);
} }
public void setLayoutManager(final RecyclerView.LayoutManager layoutManager) { public void setLayoutManager(final RecyclerView.LayoutManager layoutManager) {
@ -74,24 +86,32 @@ public class RefreshRecyclerView extends FrameLayout {
} }
} }
public void setRefreshAction(final Action action) { public void addRefreshAction(final Action action) {
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { if (action == null) {
@Override return;
public void onRefresh() {
action.onAction();
} }
}); if (mRefreshActions == null) {
mRefreshActions = new ArrayList<>();
}
mRefreshActions.add(action);
} }
public void setLoadMoreAction(final Action action) { public void setLoadMoreAction(final Action action) {
Log.d(TAG, "setLoadMoreAction"); Log.d(TAG, "setLoadMoreAction");
if (mAdapter.isShowNoMore || !loadMoreAble) { if (mAdapter.isShowNoMoring() || !mLoadMoreEnable) {
return; return;
} }
mAdapter.loadMoreAble = true;
mAdapter.setLoadMoreAction(action); mAdapter.setLoadMoreAction(action);
} }
public void setLoadMoreErrorAction(final Action action) {
Log.d(TAG, "setLoadMoreErrorAction");
if (mAdapter.isShowNoMoring() || !mLoadMoreEnable) {
return;
}
mAdapter.setLoadMoreErrorAction(action);
}
public void showNoMore() { public void showNoMore() {
mAdapter.showNoMore(); mAdapter.showNoMore();
} }
@ -112,10 +132,6 @@ public class RefreshRecyclerView extends FrameLayout {
return mSwipeRefreshLayout; return mSwipeRefreshLayout;
} }
public TextView getNoMoreView() {
return mAdapter.mNoMoreView;
}
public void setSwipeRefreshColorsFromRes(@ColorRes int... colors) { public void setSwipeRefreshColorsFromRes(@ColorRes int... colors) {
mSwipeRefreshLayout.setColorSchemeResources(colors); mSwipeRefreshLayout.setColorSchemeResources(colors);
} }
@ -134,4 +150,11 @@ public class RefreshRecyclerView extends FrameLayout {
public void dismissSwipeRefresh() { public void dismissSwipeRefresh() {
mSwipeRefreshLayout.setRefreshing(false); mSwipeRefreshLayout.setRefreshing(false);
} }
@Override
public void onRefresh() {
for (Action a : mRefreshActions) {
a.onAction();
}
}
} }

View File

@ -13,14 +13,21 @@ import android.view.ViewGroup;
public class BaseViewHolder<T> extends RecyclerView.ViewHolder{ public class BaseViewHolder<T> extends RecyclerView.ViewHolder{
private final String TAG = "BaseViewHolder"; private final String TAG = "BaseViewHolder";
private T mData;
public BaseViewHolder(ViewGroup parent, int layoutId) {
this(LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false));
}
public BaseViewHolder(View itemView) { public BaseViewHolder(View itemView) {
super(itemView); super(itemView);
}
public BaseViewHolder(ViewGroup parent, int layoutId) {
super(LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false));
onInitializeView(); onInitializeView();
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onItemViewClick(mData);
}
});
} }
public void onInitializeView() { public void onInitializeView() {
@ -28,24 +35,25 @@ public class BaseViewHolder<T> extends RecyclerView.ViewHolder{
} }
public <T extends View> T findViewById(@IdRes int resId) { public <T extends View> T findViewById(@IdRes int resId) {
if (itemView != null) {
return (T) itemView.findViewById(resId); return (T) itemView.findViewById(resId);
} else {
return null;
}
} }
public void setData(final T data) { public void setData(final T data) {
itemView.setOnClickListener(new View.OnClickListener() { if (data == null) {
@Override return;
public void onClick(View v) {
onItemViewClick(data);
} }
}); mData = data;
}
public T getData() {
return mData;
} }
public void onItemViewClick(T data) { public void onItemViewClick(T data) {
} }
public void setTag(Object tag){
itemView.setTag(tag);
}
} }

View File

@ -2,18 +2,17 @@ package cn.lemon.view.adapter;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import android.util.SparseIntArray;
import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
* 复杂的数据类型列表 Adapter , 没有 Header , Footer 的概念所有的 item 都对应一个 ViewHolder * 复杂的数据类型列表 Adapter , 没有 Header , Footer 的概念所有的 item 都对应一个 ViewHolder
* 通过反射自动处理 onCreateViewHolder 过程如需避免反射调用请使用 CustomMultiTypeAdapter
*
* Created by linlongxin on 2016/8/22. * Created by linlongxin on 2016/8/22.
*/ */
@ -21,79 +20,34 @@ public class MultiTypeAdapter extends RecyclerAdapter {
private final String TAG = "MultiTypeAdapter"; private final String TAG = "MultiTypeAdapter";
private List<Object> mViewsData; private List<Object> mViewsData;
private SparseIntArray mPositionViewType; //position --> ViewType
private ViewHolderManager mViewHolderManager; private ViewHolderManager mViewHolderManager;
public MultiTypeAdapter(Context context) { public MultiTypeAdapter(Context context) {
super(context); super(context);
mViewsData = new ArrayList<>(); mViewsData = new ArrayList<>();
mPositionViewType = new SparseIntArray();
mViewHolderManager = new ViewHolderManager(); mViewHolderManager = new ViewHolderManager();
} }
public <T> void add(Class<? extends BaseViewHolder<T>> viewHolder, T data) {
if (isShowNoMore) {
return;
}
mViewsData.add(data);
mViewHolderManager.addViewHolder(viewHolder);
int viewType = mViewHolderManager.getViewType(viewHolder);
mPositionViewType.put(mViewCount - 1, viewType);//mViewCount从1开始
int positionStart = mViewCount - 1;
mViewCount++;
notifyItemRangeInserted(positionStart, 1);
}
public <T> void addAll(Class<? extends BaseViewHolder<T>> viewHolder, T[] data) {
addAll(viewHolder, Arrays.asList(data));
}
public <T> void addAll(Class<? extends BaseViewHolder<T>> viewHolder, List<T> data) {
int size = data.size();
if (isShowNoMore || size == 0) {
return;
}
mViewsData.addAll(data);
mViewHolderManager.addViewHolder(viewHolder);
int viewType = mViewHolderManager.getViewType(viewHolder);
int positionStart = mViewCount - 1;
for (int i = 0; i < size; i++) {
mPositionViewType.put(mViewCount - 1, viewType); //mViewCount从1开始
mViewCount++;
}
notifyItemRangeInserted(positionStart, size);
}
public void clear() {
if (mViewsData == null) {
log("clear() mData is null");
return;
}
mViewsData.clear();
mViewCount = 1;
isShowNoMore = false;
mLoadMoreView.setVisibility(View.GONE);
mNoMoreView.setVisibility(View.GONE);
notifyDataSetChanged();
}
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if (position == mViewCount - 1) { if (hasEndStatusView() && position == mViewCount - 1) {
return STATUS_TYPE; return STATUS_TYPE;
} }
return mPositionViewType.get(position); return mViewHolderManager.getViewType(position);
} }
@Override @Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
log("onCreateViewHolder -- viewType : " + viewType); log("onCreateViewHolder -- viewType : " + viewType);
if (mViewHolderManager == null) {
throw new ExceptionInInitializerError("mViewHolderManager is null , it need init");
}
if (viewType == STATUS_TYPE) { if (viewType == STATUS_TYPE) {
return new BaseViewHolder(mStatusView); return new BaseViewHolder(mStatusView);
} }
Class clazzViewHolder = mViewHolderManager.getViewHolder(viewType); Class clazzViewHolder = mViewHolderManager.getViewHolderClass(viewType);
try { try {
//这里只适配了ViewHolder构造函数只有ViewGroup.class参数或者无参情况的构造函数 //这里只适配了 ViewHolder 构造函数只有 ViewGroup.class 参数 或者 无参 情况的构造函数具体请看 Demo
BaseViewHolder holder; BaseViewHolder holder;
Constructor constructor = clazzViewHolder.getDeclaredConstructor(new Class[]{ViewGroup.class}); Constructor constructor = clazzViewHolder.getDeclaredConstructor(new Class[]{ViewGroup.class});
constructor.setAccessible(true); constructor.setAccessible(true);
@ -103,21 +57,10 @@ public class MultiTypeAdapter extends RecyclerAdapter {
holder = (BaseViewHolder) constructor.newInstance(); holder = (BaseViewHolder) constructor.newInstance();
} }
return holder; return holder;
} catch (NoSuchMethodException e) { } catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "onCreateBaseViewHolder : " + e.getMessage());
} catch (IllegalAccessException e) {
e.printStackTrace();
Log.e(TAG, "onCreateBaseViewHolder : " + e.getMessage());
} catch (InstantiationException e) {
e.printStackTrace();
Log.e(TAG, "onCreateBaseViewHolder : " + e.getMessage());
} catch (InvocationTargetException e) {
e.printStackTrace();
Log.e(TAG, "onCreateBaseViewHolder : " + e.getMessage()); Log.e(TAG, "onCreateBaseViewHolder : " + e.getMessage());
} }
return null; return null;
} }
@Override @Override
@ -128,17 +71,87 @@ public class MultiTypeAdapter extends RecyclerAdapter {
@Override @Override
public void onBindViewHolder(BaseViewHolder holder, int position) { public void onBindViewHolder(BaseViewHolder holder, int position) {
log("onBindViewHolder -- position : " + position); log("onBindViewHolder -- position : " + position);
if (position == 0 && mViewCount == 1) {
} else if (position == mViewCount - 1) {
// 显示加载更多 // 显示加载更多
if (loadMoreAble && mLoadMoreAction != null && !isShowNoMore) { if (!mIsNoMoring && mLoadMoreEnable && !mIsLoadMoring && isValidLoadMore(position)) {
mLoadMoreView.setVisibility(View.VISIBLE); mIsLoadMoring = true;
setViewVisible(mLoadMoreLayout, true);
setViewVisible(mLoadMoreView, true);
setViewVisible(mLoadMoreError, false);
setViewVisible(mNoMoreView, false);
log("load more");
if (mLoadMoreAction != null ) {
mLoadMoreAction.onAction(); mLoadMoreAction.onAction();
} }
} else { } else if (mViewsData != null && holder != null && position < mViewsData.size()){
holder.setData(mViewsData.get(position)); holder.setData(mViewsData.get(position));
} }
} }
public <T> void add(Class<? extends BaseViewHolder<T>> viewHolder, T data) {
if (mIsNoMoring || data == null || viewHolder == null) {
return;
}
mIsLoadMoring = false;
mViewsData.add(data);
mViewHolderManager.addViewHolder(viewHolder);
int viewType = mViewHolderManager.getViewType(viewHolder);
int positionStart;
if (hasEndStatusView()) {
//mViewCount从1开始
positionStart = mViewCount - 1;
} else {
positionStart = mViewCount;
}
if (positionStart >= 0) {
mViewHolderManager.putViewType(positionStart, viewType);
mViewCount++;
notifyItemRangeInserted(positionStart, 1);
}
}
public <T> void addAll(Class<? extends BaseViewHolder<T>> viewHolder, T[] data) {
addAll(viewHolder, Arrays.asList(data));
}
public <T> void addAll(Class<? extends BaseViewHolder<T>> viewHolder, List<T> data) {
if (mIsNoMoring || data == null || data.size() == 0) {
return;
}
mIsLoadMoring = false;
int size = data.size();
mViewsData.addAll(data);
mViewHolderManager.addViewHolder(viewHolder);
int viewType = mViewHolderManager.getViewType(viewHolder);
int positionStart;
if (hasEndStatusView()) {
positionStart = mViewCount - 1;
} else {
positionStart = mViewCount;
}
if (positionStart >= 0) {
for (int i = 0; i < size; i++) {
mViewHolderManager.putViewType(positionStart + i, viewType);
}
mViewCount += size;
notifyItemRangeInserted(positionStart, size);
}
}
@Override
public void clear() {
if (mViewsData == null) {
log("clear() mData is null");
return;
}
mViewsData.clear();
mViewCount = hasEndStatusView() ? 1 : 0;
mIsNoMoring = false;
mIsLoadMoring = false;
setViewVisible(mLoadMoreLayout, false);
setViewVisible(mNoMoreView, false);
notifyDataSetChanged();
}
} }

View File

@ -1,6 +1,7 @@
package cn.lemon.view.adapter; package cn.lemon.view.adapter;
import android.content.Context; import android.content.Context;
import android.os.Message;
import android.support.annotation.LayoutRes; import android.support.annotation.LayoutRes;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.util.Log; import android.util.Log;
@ -8,7 +9,6 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -22,10 +22,16 @@ import cn.lemon.view.R;
/** /**
* Created by linlongxin on 2015/12/19. * Created by linlongxin on 2015/12/19.
*/ */
public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHolder<T>> { public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHolder<T>> implements IHandler {
private static final String TAG = "RecyclerAdapter"; private static final String TAG = RecyclerAdapter.class.getSimpleName();
private boolean allowLog = false; //改成false关闭日志
protected static final int MSG_SHOW_NO_MORE = 1 << 1;
protected static final int MSG_SHOW_LOAD_MORE = 1 << 2;
protected static final int MSG_SHOW_LOAD_MORE_ERROR = 1 << 3;
//改成false关闭日志
private boolean allowLog = true;
public static final int HEADER_TYPE = 111; public static final int HEADER_TYPE = 111;
public static final int FOOTER_TYPE = 222; public static final int FOOTER_TYPE = 222;
@ -34,20 +40,32 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
private boolean hasHeader = false; private boolean hasHeader = false;
private boolean hasFooter = false; private boolean hasFooter = false;
public boolean isShowNoMore = false; //停止加载
public boolean loadMoreAble = false; //是否可加载更多 // 是否可加载更多
protected boolean mLoadMoreEnable = false;
// 是否可显示 no more
protected boolean mNoMoreEnable = false;
// 是否正在显示 load more
protected boolean mIsLoadMoring = false;
// 是否正在显示 no more
protected boolean mIsNoMoring = false;
protected Action mLoadMoreAction; protected Action mLoadMoreAction;
protected Action mErrorAction;
private List<T> mData = new ArrayList<>(); private List<T> mData = new ArrayList<>();
private View headerView; private View headerView;
private View footerView; private View footerView;
protected View mStatusView; protected View mStatusView;
protected LinearLayout mLoadMoreView; protected View mLoadMoreLayout;
public TextView mNoMoreView; protected View mLoadMoreView;
protected TextView mLoadMoreError;
protected TextView mNoMoreView;
private Context mContext; protected Context mContext;
private WeakHandler mHandler = new WeakHandler(this);
public void colseLog() { public void colseLog() {
allowLog = false; allowLog = false;
@ -55,28 +73,52 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
public RecyclerAdapter(Context context) { public RecyclerAdapter(Context context) {
mContext = context; mContext = context;
initStatusView(context);
} }
public RecyclerAdapter(Context context, T[] data) { public RecyclerAdapter(Context context, T[] data) {
this(context, Arrays.asList(data)); this(context, Arrays.asList(data));
} }
public RecyclerAdapter(Context context, List<T> data) { public RecyclerAdapter(Context context, List<T> data) {
mContext = context; mContext = context;
initStatusView(context);
this.mData = data; this.mData = data;
mViewCount += data.size(); mViewCount += data.size();
notifyDataSetChanged(); notifyDataSetChanged();
} }
public void initStatusView(Context context) { private void initEndStatusView() {
mStatusView = LayoutInflater.from(context).inflate(R.layout.view_status_last, null); if (hasEndStatusView() && mStatusView == null) {
mStatusView = LayoutInflater.from(getContext()).inflate(R.layout.view_status_last, null);
mStatusView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); mStatusView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
mLoadMoreView = (LinearLayout) mStatusView.findViewById(R.id.load_more_view); mLoadMoreLayout = mStatusView.findViewById(R.id.load_more_Layout);
mLoadMoreView = mStatusView.findViewById(R.id.load_more_loading);
mLoadMoreError = (TextView) mStatusView.findViewById(R.id.load_more_error);
mNoMoreView = (TextView) mStatusView.findViewById(R.id.no_more_view); mNoMoreView = (TextView) mStatusView.findViewById(R.id.no_more_view);
mViewCount++; mViewCount++;
mLoadMoreError.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendEmptyMessage(MSG_SHOW_LOAD_MORE);
if (mErrorAction != null) {
mErrorAction.onAction();
}
}
});
}
}
public void setLoadMoreEnable(boolean b) {
mLoadMoreEnable = b;
initEndStatusView();
}
public void setShowNoMoreEnable(boolean b) {
mNoMoreEnable = b;
initEndStatusView();
}
public boolean isShowNoMoring() {
return mIsNoMoring;
} }
@Override @Override
@ -87,9 +129,10 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
return new BaseViewHolder<>(footerView); return new BaseViewHolder<>(footerView);
} else if (viewType == STATUS_TYPE) { } else if (viewType == STATUS_TYPE) {
return new BaseViewHolder<>(mStatusView); return new BaseViewHolder<>(mStatusView);
} else } else {
return onCreateBaseViewHolder(parent, viewType); return onCreateBaseViewHolder(parent, viewType);
} }
}
public abstract BaseViewHolder<T> onCreateBaseViewHolder(ViewGroup parent, int viewType); public abstract BaseViewHolder<T> onCreateBaseViewHolder(ViewGroup parent, int viewType);
@ -99,54 +142,88 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
*/ */
@Override @Override
public void onBindViewHolder(BaseViewHolder<T> holder, int position) { public void onBindViewHolder(BaseViewHolder<T> holder, int position) {
// log("onBindViewHolder() viewCount : " + mViewCount + " position : " + position); log("onBindViewHolder() viewCount : " + mViewCount + " position : " + position);
if (position == 0) { if (holder == null || position < 0) {
// 最先加载 mStatusView 时不需要绑定数据
if (mViewCount == 1 || hasHeader) {
return;
} else {
if (mData.size() > 0)
holder.setData(mData.get(0));
else
return; return;
} }
} else if (!hasHeader && !hasFooter && position < mData.size()) { //没有Header和Footer int dataSize = mData.size();
if (hasEndStatusView()) {
if (!hasHeader && !hasFooter && position < dataSize) {
//没有Header和Footer
holder.setData(mData.get(position)); holder.setData(mData.get(position));
} else if (hasHeader && !hasFooter && position > 0 && position < mViewCount - 1) { //有Header没有Footer } else if (hasHeader && !hasFooter && position > 0 && position < mViewCount - 1 && position - 1 < dataSize) {
//有Header没有Footer
holder.setData(mData.get(position - 1)); holder.setData(mData.get(position - 1));
} else if (!hasHeader && position < mViewCount - 2) { //没有Header有Footer } else if (!hasHeader && position < mViewCount - 2 && position < dataSize) {
//没有Header有Footer
holder.setData(mData.get(position)); holder.setData(mData.get(position));
} else if (position > 0 && position < mViewCount - 2) { //都有 } else if (position > 0 && position < mViewCount - 2 && position - 1 < dataSize) {
//Header, Footer 都有
holder.setData(mData.get(position - 1)); holder.setData(mData.get(position - 1));
} }
} else {
if (!hasHeader && !hasFooter && position < dataSize) {
//没有Header和Footer
holder.setData(mData.get(position));
} else if (hasHeader && !hasFooter && position > 0 && position < mViewCount && position - 1 < dataSize) {
//有Header没有Footer
holder.setData(mData.get(position - 1));
} else if (!hasHeader && position < mViewCount - 1 && position < dataSize) {
//没有Header有Footer
holder.setData(mData.get(position));
} else if (position > 0 && position < mViewCount - 1 && position - 1 < dataSize) {
//Header, Footer 都有
holder.setData(mData.get(position - 1));
}
}
// 最后一个可见的 item 加载更多解决 remove bug // 最后一个可见的 item 加载更多解决 remove bug
int positionEnd; if (mLoadMoreEnable && !mIsNoMoring && !mIsLoadMoring && isValidLoadMore(position)) {
if ((hasHeader && hasFooter) || (!hasHeader && hasFooter)) { mIsLoadMoring = true;
positionEnd = mViewCount - 3; setViewVisible(mLoadMoreLayout, true);
} else { setViewVisible(mLoadMoreView, true);
positionEnd = mViewCount - 2; setViewVisible(mLoadMoreError, false);
} setViewVisible(mNoMoreView, false);
if (loadMoreAble && !isShowNoMore && position == positionEnd) { log("load more");
mLoadMoreView.setVisibility(View.VISIBLE);
if (mLoadMoreAction != null) { if (mLoadMoreAction != null) {
mLoadMoreAction.onAction(); mLoadMoreAction.onAction();
} }
} }
} }
/**
* load more 当前位置 view 是否有效
*/
protected boolean isValidLoadMore(int position) {
if (hasEndStatusView()) {
// 倒数第二个 item 就load more 提前触发解决一些极端 case 导致 bug 并提前加载数据提高加载效率
if (hasHeader) {
return position != 1 && position == mViewCount - 3 && mViewCount != 2;
} else {
return position != 0 && position == mViewCount - 2 && mViewCount != 1;
}
} else {
return false;
}
}
/** /**
* ViewHolder 更新 Item 的位置选择 ViewType , UI 是同步的 * ViewHolder 更新 Item 的位置选择 ViewType , UI 是同步的
*/ */
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if (hasHeader && position == 0) { //header // header
if (hasHeader && position == 0) {
return HEADER_TYPE; return HEADER_TYPE;
} }
if (hasFooter && position == mViewCount - 2) { //footer // footer
if (hasFooter && hasEndStatusView() && position == mViewCount - 2) {
return FOOTER_TYPE;
} else if (hasFooter && !hasEndStatusView() && position == mViewCount - 1) {
return FOOTER_TYPE; return FOOTER_TYPE;
} }
if (position == mViewCount - 1) { //最后View的状态 // status
if (hasEndStatusView() && position == mViewCount - 1) {
return STATUS_TYPE; return STATUS_TYPE;
} }
@ -162,37 +239,27 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
} }
public void showNoMore() { public void showNoMore() {
if (!mNoMoreEnable) {
isShowNoMore = true; return;
handler.post(new Runnable() { }
@Override mIsNoMoring = true;
public void run() { mHandler.sendEmptyMessage(MSG_SHOW_NO_MORE);
mLoadMoreView.setVisibility(View.GONE);
mNoMoreView.setVisibility(View.VISIBLE);
} }
});
/*mLoadMoreView.post(new Runnable() { public void showLoadMoreError() {
@Override if (!mLoadMoreEnable) {
public void run() { return;
mLoadMoreView.setVisibility(View.GONE);
mNoMoreView.setVisibility(View.VISIBLE);
Log.i("调试","载入View"+(mLoadMoreView.getVisibility()));
} }
});*/ mHandler.sendEmptyMessage(MSG_SHOW_LOAD_MORE_ERROR);
}
public void setLoadMoreErrorAction(Action action) {
mErrorAction = action;
} }
private android.os.Handler handler=new android.os.Handler();
public void openLoadMore() { public void openLoadMore() {
isShowNoMore = false; mIsNoMoring = false;
mLoadMoreView.post(new Runnable() { mHandler.sendEmptyMessage(MSG_SHOW_LOAD_MORE);
@Override
public void run() {
mLoadMoreView.setVisibility(View.VISIBLE);
mNoMoreView.setVisibility(View.GONE);
}
});
} }
public void setLoadMoreAction(Action action) { public void setLoadMoreAction(Action action) {
@ -200,13 +267,18 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
} }
public void add(T object) { public void add(T object) {
if (!isShowNoMore) { if (!mIsNoMoring && object != null) {
mIsLoadMoring = false;
mData.add(object); mData.add(object);
int position; int position;
if (hasFooter) { if (hasFooter && hasEndStatusView()) {
position = mViewCount - 2; position = mViewCount - 2;
} else { } else if (hasFooter && !hasEndStatusView()) {
position = mViewCount - 1; position = mViewCount - 1;
} else if (!hasFooter && hasEndStatusView()) {
position = mViewCount - 1;
} else {
position = mViewCount;
} }
mViewCount++; mViewCount++;
notifyItemInserted(position); notifyItemInserted(position);
@ -214,7 +286,8 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
} }
public void insert(T object, int itemPosition) { public void insert(T object, int itemPosition) {
if (mData != null && itemPosition < mViewCount) { int maxPosition = hasEndStatusView() ? mViewCount - 2 : mViewCount - 1;
if (mData != null && itemPosition < maxPosition && object != null) {
int dataPosition; int dataPosition;
if (hasHeader) { if (hasHeader) {
dataPosition = itemPosition - 1; dataPosition = itemPosition - 1;
@ -228,14 +301,22 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
} }
public void addAll(List<T> data) { public void addAll(List<T> data) {
if (data == null) {
return;
}
int size = data.size(); int size = data.size();
if (!isShowNoMore && size > 0) { if (!mIsNoMoring && size > 0) {
mIsLoadMoring = false;
mData.addAll(data); mData.addAll(data);
int positionStart; int positionStart;
if (hasFooter) { if (hasFooter && hasEndStatusView()) {
positionStart = mViewCount - 2; positionStart = mViewCount - 2;
} else { } else if (hasFooter && !hasEndStatusView()) {
positionStart = mViewCount - 1; positionStart = mViewCount - 1;
} else if (!hasFooter && hasEndStatusView()) {
positionStart = mViewCount - 1;
} else {
positionStart = mViewCount;
} }
mViewCount += size; mViewCount += size;
notifyItemRangeInserted(positionStart, size); notifyItemRangeInserted(positionStart, size);
@ -248,7 +329,7 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
} }
public void replace(T object, int itemPosition) { public void replace(T object, int itemPosition) {
if (mData != null) { if (mData != null && object != null) {
int dataPosition; int dataPosition;
if (hasHeader) { if (hasHeader) {
dataPosition = itemPosition - 1; dataPosition = itemPosition - 1;
@ -265,7 +346,7 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
//position start with 0 //position start with 0
public void remove(T object) { public void remove(T object) {
if (!mData.contains(object)) { if (object != null && !mData.contains(object)) {
Toast.makeText(getContext(), "删除失败", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "删除失败", Toast.LENGTH_SHORT).show();
log("remove() without the object : " + object.getClass().getName()); log("remove() without the object : " + object.getClass().getName());
return; return;
@ -280,7 +361,9 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
remove(itemPosition); remove(itemPosition);
} }
//positionItem start with 0 /**
* positionItem start with 0
*/
public void remove(int itemPosition) { public void remove(int itemPosition) {
int dataPosition; int dataPosition;
int dataSize = mData.size(); int dataSize = mData.size();
@ -314,20 +397,25 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
return; return;
} }
mData.clear(); mData.clear();
mViewCount = 1; mViewCount = hasEndStatusView() ? 1 : 0;
if (hasHeader) { if (hasHeader) {
mViewCount++; mViewCount++;
} }
if (hasFooter) { if (hasFooter) {
mViewCount++; mViewCount++;
} }
isShowNoMore = false; mIsNoMoring = false;
mLoadMoreView.setVisibility(View.GONE); mIsLoadMoring = false;
mNoMoreView.setVisibility(View.GONE); setViewVisible(mLoadMoreLayout, false);
setViewVisible(mNoMoreView, false);
notifyDataSetChanged(); notifyDataSetChanged();
} }
/**
* header 不负责数据加载也就是不会掉用 onBindViewHolder
*
* @param header
*/
public void setHeader(View header) { public void setHeader(View header) {
hasHeader = true; hasHeader = true;
headerView = header; headerView = header;
@ -352,6 +440,11 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
mViewCount++; mViewCount++;
} }
/**
* Footer 这里不负责数据的加载
*
* @param res
*/
public void setFooter(@LayoutRes int res) { public void setFooter(@LayoutRes int res) {
setFooter(LayoutInflater.from(mContext).inflate(res, null)); setFooter(LayoutInflater.from(mContext).inflate(res, null));
} }
@ -366,7 +459,11 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
public void removeFooter() { public void removeFooter() {
if (hasFooter) { if (hasFooter) {
hasFooter = false; hasFooter = false;
if (hasEndStatusView() && mViewCount > 1) {
notifyItemRemoved(mViewCount - 2); notifyItemRemoved(mViewCount - 2);
} else if (!hasEndStatusView() && mViewCount > 0) {
notifyItemRemoved(mViewCount - 1);
}
} }
} }
@ -378,9 +475,47 @@ public abstract class RecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHo
return mContext; return mContext;
} }
protected void setViewVisible(View view, boolean visibile) {
if (view != null) {
view.setVisibility(visibile ? View.VISIBLE : View.GONE);
}
}
protected boolean hasEndStatusView() {
return mLoadMoreEnable || mNoMoreEnable;
}
public void log(String content) { public void log(String content) {
if (allowLog) { if (allowLog) {
Log.d(TAG, content); Log.d(TAG, content);
} }
} }
@Override
public void handMsg(Message message) {
switch (message.what) {
case MSG_SHOW_LOAD_MORE_ERROR:
// true 阻止 load more 执行
mIsLoadMoring = true;
setViewVisible(mLoadMoreLayout, true);
setViewVisible(mLoadMoreView, false);
setViewVisible(mLoadMoreError, true);
setViewVisible(mNoMoreView, false);
break;
case MSG_SHOW_LOAD_MORE:
mIsLoadMoring = true;
setViewVisible(mLoadMoreLayout, true);
setViewVisible(mLoadMoreView, true);
setViewVisible(mLoadMoreError, false);
setViewVisible(mNoMoreView, false);
break;
case MSG_SHOW_NO_MORE:
mIsLoadMoring = false;
setViewVisible(mLoadMoreLayout, false);
setViewVisible(mNoMoreView, true);
break;
default:
break;
}
}
} }

View File

@ -1,6 +1,8 @@
package cn.lemon.view.adapter; package cn.lemon.view.adapter;
import android.util.Log; import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.util.HashMap; import java.util.HashMap;
@ -14,35 +16,47 @@ public class ViewHolderManager {
private final String TAG = "ViewHolderManager"; private final String TAG = "ViewHolderManager";
private int mViewType = 10; private int mViewType = 10;
private Map<Class<? extends BaseViewHolder>, Integer> mHolderType; private Map<Class<? extends BaseViewHolder>, Integer> mHolderToTypeMap;
private Map<Integer,Class<? extends BaseViewHolder>> mTypeHolder; private SparseArray<Class<? extends BaseViewHolder>> mTypeToHolderMap;
//position to ViewType
private SparseIntArray mPositionToTypeMap;
public ViewHolderManager() { public ViewHolderManager() {
mHolderType = new HashMap<>(); mHolderToTypeMap = new HashMap<>();
mTypeHolder = new HashMap<>(); mTypeToHolderMap = new SparseArray<>();
mPositionToTypeMap = new SparseIntArray();
}
public void putViewType(int position, int type){
mPositionToTypeMap.put(position, type);
}
public int getViewType(int position) {
return mPositionToTypeMap.get(position);
} }
public void addViewHolder(Class<? extends BaseViewHolder> viewHolder) { public void addViewHolder(Class<? extends BaseViewHolder> viewHolder) {
if (!mHolderType.containsKey(viewHolder)) { if (!mHolderToTypeMap.containsKey(viewHolder)) {
Class dataClass = (Class) ((ParameterizedType) viewHolder.getGenericSuperclass()).getActualTypeArguments()[0]; //获取ViewHolder的泛型数据class //获取ViewHolder的泛型数据class
Class dataClass = (Class) ((ParameterizedType) viewHolder.getGenericSuperclass()).getActualTypeArguments()[0];
mViewType ++; mViewType ++;
mHolderType.put(viewHolder, mViewType); mHolderToTypeMap.put(viewHolder, mViewType);
mTypeHolder.put(mViewType,viewHolder); mTypeToHolderMap.put(mViewType,viewHolder);
Log.d(TAG, "addViewHolder dataClassType : " + dataClass.getName()); Log.d(TAG, "addViewHolder dataClassType : " + dataClass.getName());
} }
} }
public int getViewType(Class<? extends BaseViewHolder> holder){ public int getViewType(Class<? extends BaseViewHolder> holder){
if(!mHolderType.containsKey(holder)){ if(!mHolderToTypeMap.containsKey(holder)){
throw new NullPointerException("please invoke addViewHolder method"); throw new IllegalArgumentException("please invoke add ViewHolder method");
} }
return mHolderType.get(holder); return mHolderToTypeMap.get(holder);
} }
public Class<? extends BaseViewHolder> getViewHolder(int viewType){ public Class<? extends BaseViewHolder> getViewHolderClass(int viewType){
if(!mTypeHolder.containsKey(viewType)){ if(mTypeToHolderMap.get(viewType) == null){
throw new NullPointerException("please invoke addViewHolder method"); throw new IllegalArgumentException("please invoke add ViewHolder method");
} }
return mTypeHolder.get(viewType); return mTypeToHolderMap.get(viewType);
} }
} }

View File

@ -1,12 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout <android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/refresh_layout" android:id="@+id/lemon_refresh_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<!-- 避免 id 命名冲突 -->
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view" android:id="@+id/lemon_recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />

View File

@ -1,16 +1,22 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<LinearLayout <RelativeLayout
android:id="@+id/load_more_view" android:id="@+id/load_more_Layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:gravity="center"
android:orientation="horizontal" android:orientation="horizontal"
android:padding="8dp" android:padding="8dp"
android:visibility="gone"> android:visibility="gone"
tools:visibility="visible">
<LinearLayout android:id="@+id/load_more_loading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ProgressBar <ProgressBar
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -25,12 +31,23 @@
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/load_more_error"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_button_retry_adapter"
android:gravity="center"
android:text="数据错误,点我重试"
android:textSize="14sp"/>
</RelativeLayout>
<TextView <TextView
android:id="@+id/no_more_view" android:id="@+id/no_more_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:gravity="center" android:gravity="center"
android:text="" android:text="没有更多了O(∩_∩)O~"
android:textSize="14sp" android:textSize="14sp"
android:visibility="gone" /> android:visibility="gone" />

View File

@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<declare-styleable name="RefreshRecyclerView"> <declare-styleable name="RefreshRecyclerView">
<attr name="refresh_able" format="boolean"/> <attr name="refresh_enable" format="boolean"/>
<attr name="load_more_able" format="boolean"/> <!-- 其中之一为 true都能使用 加载更多 和 显示没有更多数据 功能 -->
<attr name="load_more_enable" format="boolean"/>
<attr name="show_no_more_enable" format="boolean"/>
</declare-styleable> </declare-styleable>
</resources> </resources>

View File

@ -1,11 +1,11 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 26 compileSdkVersion 27
defaultConfig { defaultConfig {
applicationId "com.yutou.jianrmg_v2" applicationId "com.yutou.jianrmg_v2"
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 26 targetSdkVersion 27
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@ -17,26 +17,23 @@ android {
} }
} }
} }
dependencies { dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
//noinspection GradleCompatible //noinspection GradleCompatible
implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.0.2' implementation 'com.android.support.constraint:constraint-layout:1.1.1'
implementation 'com.android.support:design:26.1.0' //implementation 'com.android.support:design:26.1.0'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
//okhttp //okhttp
implementation 'com.squareup.okhttp3:okhttp:3.9.1' implementation 'com.squareup.okhttp3:okhttp:3.10.0'
//FastJson //FastJson
implementation 'com.alibaba:fastjson:1.2.41' implementation 'com.alibaba:fastjson:1.2.41'
// //
implementation 'com.bigkoo:convenientbanner:2.0.5' implementation 'com.bigkoo:convenientbanner:2.0.5'
// //
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
//
implementation 'com.github.siyamed:android-shape-imageview:0.9.+@aar'
//Tabs //Tabs
implementation 'com.ogaclejapan.smarttablayout:library:1.6.1@aar' implementation 'com.ogaclejapan.smarttablayout:library:1.6.1@aar'
implementation 'com.ogaclejapan.smarttablayout:utils-v13:1.6.1@aar' implementation 'com.ogaclejapan.smarttablayout:utils-v13:1.6.1@aar'
@ -44,12 +41,12 @@ dependencies {
implementation 'me.drakeet.materialdialog:library:1.3.1' implementation 'me.drakeet.materialdialog:library:1.3.1'
// //
implementation 'com.kaopiz:kprogresshud:1.1.0' implementation 'com.kaopiz:kprogresshud:1.1.0'
// //
implementation 'com.github.louisgeek:LouisMultiLineEditText:v1.0.0' implementation 'com.github.louisgeek:ClassicLinesEditView:1.0.2'
// //
implementation 'com.leon:lfilepickerlibrary:1.4.0' implementation 'com.leon:lfilepickerlibrary:1.8.0'
// // #
implementation 'com.github.limedroid:XRichText:v1.0.0' implementation 'com.zzhoujay.richtext:richtext:3.0.7'
// //
implementation 'com.orhanobut:dialogplus:1.11@aar' implementation 'com.orhanobut:dialogplus:1.11@aar'
// //
@ -59,7 +56,7 @@ dependencies {
// //
implementation project(path: ':RefreshRecyclerView') implementation project(path: ':RefreshRecyclerView')
// //
implementation 'com.github.siyamed:android-shape-imageview:0.9.+@aar' implementation 'com.github.siyamed:android-shape-imageview:0.9.3@aar'
// //
implementation 'jp.wasabeef:glide-transformations:3.0.0' implementation 'jp.wasabeef:glide-transformations:3.0.0'
// //

View File

@ -45,12 +45,13 @@
android:exported="true" /> android:exported="true" />
<activity <activity
android:name=".views.BaseActivity"></activity> android:name=".views.BaseActivity"/>
<activity <activity
android:name=".views.WebActivity"></activity> android:name=".views.WebActivity"/>
<activity android:name=".views.ModListActivity"/> <activity android:name=".views.ModListActivity"/>
<activity android:name=".views.ModActivity"/> <activity android:name=".views.ModActivity"/>
<activity android:name=".views.DownloadListActivity"/> <activity android:name=".views.DownloadListActivity"/>
<activity android:name=".views.FavoritesActivity"/>
</application> </application>
</manifest> </manifest>

View File

@ -1,24 +1,39 @@
package com.yutou.jianrmg_v2.Adapters; package com.yutou.jianrmg_v2.Adapters;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.AppCompatButton;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.alibaba.fastjson.JSON;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.yutou.jianrmg_v2.Data.AppData;
import com.yutou.jianrmg_v2.Data.TMod;
import com.yutou.jianrmg_v2.Interfaces.ModInterface;
import com.yutou.jianrmg_v2.R; import com.yutou.jianrmg_v2.R;
import com.yutou.jianrmg_v2.Tools.ModUtils;
import com.yutou.jianrmg_v2.Tools.Utils;
import com.yutou.jianrmg_v2.views.ModActivity;
import java.util.List; import java.util.List;
import me.drakeet.materialdialog.MaterialDialog;
public class DownloadItemAdapter extends BaseAdapter { public class DownloadItemAdapter extends BaseAdapter {
private Context context; private Context context;
private List<?> list; private List<TMod> list;
private ImageLoader imageLoader;
public DownloadItemAdapter(Context context, List<?> list) { public DownloadItemAdapter(Context context, List<TMod> list) {
this.context = context; this.context = context;
this.list = list; this.list = list;
imageLoader= Utils.initImageLoader(context);
} }
@Override @Override
@ -37,20 +52,66 @@ public class DownloadItemAdapter extends BaseAdapter {
} }
@Override @Override
public View getView(int i, View view, ViewGroup viewGroup) { public View getView(final int i, View view, ViewGroup viewGroup) {
Items items; Items items;
if(view==null){ if(view==null){
view= LayoutInflater.from(context).inflate(R.layout.item_download,null); view= LayoutInflater.from(context).inflate(R.layout.item_download,null);
items=new Items(); items=new Items();
items.delete=view.findViewById(R.id.delete);
items.install=view.findViewById(R.id.install);
items.icon=view.findViewById(R.id.image);
items.title=view.findViewById(R.id.title);
view.setTag(items); view.setTag(items);
}else{ }else{
items= (Items) view.getTag(); items= (Items) view.getTag();
} }
items.title.setText(list.get(i).getTitle());
imageLoader.displayImage(AppData.appConfig.getDownloadhome()+list.get(i).getIcon(),items.icon);
items.delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final MaterialDialog dialog=new MaterialDialog(context);
dialog.setTitle("提示");
dialog.setMessage("删除这个内容?");
dialog.setNegativeButton("我手滑了", new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.setPositiveButton("是的", new View.OnClickListener() {
@Override
public void onClick(View v) {
Utils.deleteFiles(Utils.getAppPath()+"/"+list.get(i).getId());
Utils.toast(context,"删除完成");
list.remove(i);
notifyDataSetChanged();
dialog.dismiss();
}
});
dialog.show();
}
});
items.install.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ModUtils mod=ModUtils.init(context);
mod.installMod(list.get(i), null);
}
});
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(context, ModActivity.class);
intent.putExtra("mod", JSON.toJSONString(list.get(i)));
context.startActivity(intent);
}
});
return view; return view;
} }
private class Items{ private class Items{
ImageView icon; ImageView icon;
TextView title; TextView title;
Button install,delete;
} }
} }

View File

@ -142,7 +142,7 @@ public class Home extends Fragment {
endText.setText(" --已经没有了--"); endText.setText(" --已经没有了--");
adapter.setFooter(endText); adapter.setFooter(endText);
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
recyclerView.setRefreshAction(new Action() { recyclerView.addRefreshAction(new Action() {
@Override @Override
public void onAction() { public void onAction() {
min=0; min=0;

View File

@ -71,7 +71,7 @@ public class MGList extends Fragment {
endText.setText(" --已经没有了--"); endText.setText(" --已经没有了--");
adapter.setFooter(endText); adapter.setFooter(endText);
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
recyclerView.setRefreshAction(new Action() { recyclerView.addRefreshAction(new Action() {
@Override @Override
public void onAction() { public void onAction() {
min=0; min=0;

View File

@ -71,7 +71,7 @@ public class ModListFragmentData {
endText.setText(" --已经没有了--"); endText.setText(" --已经没有了--");
adapter.setFooter(endText); adapter.setFooter(endText);
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
recyclerView.setRefreshAction(new Action() { recyclerView.addRefreshAction(new Action() {
@Override @Override
public void onAction() { public void onAction() {
min=0; min=0;

View File

@ -77,6 +77,7 @@ public class HttpUtils {
if(httpInterface!=null) if(httpInterface!=null)
httpInterface.httpError(e); httpInterface.httpError(e);
e.printStackTrace(); e.printStackTrace();
Log.e(e,HttpUtils.class);
} }
@Override @Override

View File

@ -50,7 +50,7 @@ public class Log {
* @param object 异常所在的类 * @param object 异常所在的类
* @return * @return
*/ */
public static String printf_Error(Exception e,Object object) { public static String e(Exception e,Object object) {
StringWriter writer=new StringWriter(); StringWriter writer=new StringWriter();
PrintWriter printWriter=new PrintWriter(writer); PrintWriter printWriter=new PrintWriter(writer);
e.printStackTrace(printWriter); e.printStackTrace(printWriter);

View File

@ -85,6 +85,10 @@ public class ModUtils {
public void installMod(TMod mod, ModInterface modInterface) { public void installMod(TMod mod, ModInterface modInterface) {
this.mod = mod; this.mod = mod;
if(modfiles!=null&&modfiles.size()>0&&!mod.getId().equals(modfiles.get(0).getMid())){
modfiles.clear();
getModDownloadInfo();
}
if (modInterface == null) { if (modInterface == null) {
modInterface = new ModInterface() { modInterface = new ModInterface() {
@Override @Override
@ -102,9 +106,11 @@ public class ModUtils {
getModDownloadInfo(); getModDownloadInfo();
return; return;
} }
Log.i("安装mod", changeMod(mod, modfiles) + ""); Log.i("安装mod", isInstallMod(mod) + " " + changeMod(mod, modfiles));
if (!isInstallMod(mod) && changeMod(mod, modfiles)) { if (changeMod(mod, modfiles) && !isInstallMod(mod)) {
install(mod, modInterface); install(mod, modInterface);
} else if (isInstallMod(mod)) {
reBackMod(mod, modInterface);
} else { } else {
if (getModPath(mod).listFiles().length > 0 && !changeMod(mod, modfiles)) { if (getModPath(mod).listFiles().length > 0 && !changeMod(mod, modfiles)) {
final MaterialDialog dialog = new MaterialDialog(context); final MaterialDialog dialog = new MaterialDialog(context);
@ -190,7 +196,7 @@ public class ModUtils {
} }
hud.dismiss(); hud.dismiss();
dialog.dismiss(); dialog.dismiss();
Toast.makeText(context, "安装成功,重启游戏生效", Toast.LENGTH_LONG).show(); Utils.toast(context, "安装成功,重启游戏生效");
modInterface.onAction(true, MOD_INSTALL); modInterface.onAction(true, MOD_INSTALL);
} }
}); });
@ -198,6 +204,7 @@ public class ModUtils {
dialog.setPositiveButton("放弃", new View.OnClickListener() { dialog.setPositiveButton("放弃", new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
modInterface.onAction(false,MOD_INSTALL);
dialog.dismiss(); dialog.dismiss();
} }
}); });
@ -267,6 +274,7 @@ public class ModUtils {
if (modInterface != null) if (modInterface != null)
modInterface.onAction(true, MOD_UNINSTALL); modInterface.onAction(true, MOD_UNINSTALL);
dialog.dismiss(); dialog.dismiss();
Utils.toast(context,"还原成功,重启游戏生效");
} }
}); });
dialog.setContentView(listView); dialog.setContentView(listView);

View File

@ -184,6 +184,7 @@ public class Utils {
} }
} }
} }
public static boolean writerFile(String srcFile, String data) { public static boolean writerFile(String srcFile, String data) {
File file = new File(srcFile); File file = new File(srcFile);
if (!file.exists()) { if (!file.exists()) {
@ -200,6 +201,7 @@ public class Utils {
} }
return false; return false;
} }
public static String readFile(String srcFile) { public static String readFile(String srcFile) {
File file = new File(srcFile); File file = new File(srcFile);
if (!file.exists()) { if (!file.exists()) {
@ -217,4 +219,16 @@ public class Utils {
} }
return null; return null;
} }
public static void deleteFiles(String path) {
File files = new File(path);
if (files.exists()) {
if (files.isDirectory()) {
for (File file : files.listFiles()) {
deleteFiles(file.getAbsolutePath());
}
}
files.delete();
}
}
} }

View File

@ -3,6 +3,7 @@ package com.yutou.jianrmg_v2.views;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent; import android.view.KeyEvent;
@ -12,9 +13,14 @@ import android.view.View;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ListView; import android.widget.ListView;
import com.alibaba.fastjson.JSON;
import com.yutou.jianrmg_v2.Adapters.DownloadItemAdapter;
import com.yutou.jianrmg_v2.Data.AppData;
import com.yutou.jianrmg_v2.Data.TMod;
import com.yutou.jianrmg_v2.Interfaces.HttpInterface; import com.yutou.jianrmg_v2.Interfaces.HttpInterface;
import com.yutou.jianrmg_v2.Network.HttpApi; import com.yutou.jianrmg_v2.Network.HttpApi;
import com.yutou.jianrmg_v2.Network.HttpUtils; import com.yutou.jianrmg_v2.Network.HttpUtils;
import com.yutou.jianrmg_v2.Tools.Log;
import com.yutou.jianrmg_v2.Tools.Utils; import com.yutou.jianrmg_v2.Tools.Utils;
import com.yutou.jianrmg_v2.R; import com.yutou.jianrmg_v2.R;
@ -24,20 +30,21 @@ import org.json.JSONObject;
import java.io.File; import java.io.File;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
import Interfaces.BaseActivityInterface; import Interfaces.BaseActivityInterface;
public class DownloadListActivity extends AppCompatActivity { public class DownloadListActivity extends AppCompatActivity {
private Context context; private Context context;
private ListView listView; private ListView listView;
private List<TMod> mods;
private Handler handler;
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_download_list); setContentView(R.layout.activity_download_list);
this.context = this; this.context = this;
handler=new Handler();
getDownloadFileList(); getDownloadFileList();
initViews(); initViews();
} }
@ -62,8 +69,13 @@ public class DownloadListActivity extends AppCompatActivity {
if(json.getInt("code")!=100){ if(json.getInt("code")!=100){
return; return;
} }
JSONArray dataList=json.getJSONArray("data"); mods= JSON.parseArray(json.getJSONArray("data").toString(),TMod.class);
handler.post(new Runnable() {
@Override
public void run() {
listView.setAdapter(new DownloadItemAdapter(context,mods));
}
});
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -0,0 +1,14 @@
package com.yutou.jianrmg_v2.views;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
public class FavoritesActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}

View File

@ -7,9 +7,6 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.FrameLayout; import android.widget.FrameLayout;
@ -22,6 +19,7 @@ import com.alibaba.fastjson.JSON;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
import com.yutou.jianrmg_v2.Adapters.ReModListAdapter; import com.yutou.jianrmg_v2.Adapters.ReModListAdapter;
import com.yutou.jianrmg_v2.Data.AppData; import com.yutou.jianrmg_v2.Data.AppData;
import com.yutou.jianrmg_v2.Data.MGamePackname;
import com.yutou.jianrmg_v2.Data.TMod; import com.yutou.jianrmg_v2.Data.TMod;
import com.yutou.jianrmg_v2.Data.TModtag; import com.yutou.jianrmg_v2.Data.TModtag;
import com.yutou.jianrmg_v2.Interfaces.HttpInterface; import com.yutou.jianrmg_v2.Interfaces.HttpInterface;
@ -32,16 +30,15 @@ import com.yutou.jianrmg_v2.R;
import com.yutou.jianrmg_v2.Tools.Log; import com.yutou.jianrmg_v2.Tools.Log;
import com.yutou.jianrmg_v2.Tools.ModUtils; import com.yutou.jianrmg_v2.Tools.ModUtils;
import com.yutou.jianrmg_v2.Tools.Utils; import com.yutou.jianrmg_v2.Tools.Utils;
import com.zzhoujay.richtext.RichText;
import com.zzhoujay.richtext.RichType;
import com.zzhoujay.richtext.ig.DefaultImageGetter;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import Interfaces.BaseActivityInterface;
import cn.droidlover.xrichtext.XRichText;
/** /**
@ -51,8 +48,7 @@ import cn.droidlover.xrichtext.XRichText;
public class ModActivity extends AppCompatActivity{ public class ModActivity extends AppCompatActivity{
private TMod tMod; private TMod tMod;
private ImageView modImage, icon, collection_img; private ImageView modImage, icon, collection_img;
private TextView title, by, downloadText; private TextView title, by, downloadText,richText;
private XRichText richText;
private LinearLayout tagsLayout; private LinearLayout tagsLayout;
private FrameLayout collection, share, download; private FrameLayout collection, share, download;
private ListView quote; private ListView quote;
@ -107,20 +103,22 @@ public class ModActivity extends AppCompatActivity{
} }
private void initData(final TMod tMod) { private void initData(final TMod tMod) {
List<MGamePackname> installClick=modUtils.getInstallClens();
System.out.println("---------->"+AppData.appConfig.getDownloadhome() + tMod.getImage());
System.out.println("---------->"+AppData.appConfig.getDownloadhome() + tMod.getIcon());
imageLoader.displayImage(AppData.appConfig.getDownloadhome() + tMod.getImage(), modImage); imageLoader.displayImage(AppData.appConfig.getDownloadhome() + tMod.getImage(), modImage);
imageLoader.displayImage(AppData.appConfig.getDownloadhome() + tMod.getIcon(), icon); imageLoader.displayImage(AppData.appConfig.getDownloadhome() + tMod.getIcon(), icon);
title.setText(tMod.getTitle()); title.setText(tMod.getTitle());
by.setText("@" + tMod.getByuser()); by.setText("@" + tMod.getByuser());
richText.text(tMod.getInfo()); RichText.fromHtml(tMod.getInfo())
.imageGetter(new DefaultImageGetter())
//.type(RichType.html)
.into(richText);
downloadText.setTag(0); downloadText.setTag(0);
if (ModUtils.getModPath(tMod).listFiles().length > 0) { if (ModUtils.getModPath(tMod).listFiles().length > 0) {
downloadText.setText("安装"); downloadText.setText("安装");
downloadText.setTag(2); downloadText.setTag(2);
} }
if(ModUtils.isInstallMod(tMod)){
downloadText.setText("还原");
downloadText.setTag(1);
}
download.setOnClickListener(new View.OnClickListener() { download.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
@ -140,7 +138,6 @@ public class ModActivity extends AppCompatActivity{
json.put("mid", tMod.getId() + ""); json.put("mid", tMod.getId() + "");
HttpUtils.post(HttpApi.HOME_URL + HttpApi.MOD_COLLCETION, json, new HttpInterface() { HttpUtils.post(HttpApi.HOME_URL + HttpApi.MOD_COLLCETION, json, new HttpInterface() {
private String state = "收藏失败,未知错误"; private String state = "收藏失败,未知错误";
@Override @Override
public void httpGetData(String string, int code) { public void httpGetData(String string, int code) {

View File

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="ModActivity"> tools:context=".views.ModActivity">
<ScrollView <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
@ -26,7 +26,8 @@
android:scaleType="fitXY" android:scaleType="fitXY"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@drawable/ic_launcher_background" /> app:srcCompat="@drawable/ic_launcher_background"
tools:ignore="VectorDrawableCompat" />
<ImageView <ImageView
android:id="@+id/icon" android:id="@+id/icon"
@ -36,7 +37,8 @@
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ModImage" app:layout_constraintTop_toBottomOf="@+id/ModImage"
app:srcCompat="@drawable/ic_launcher_background" /> app:srcCompat="@drawable/ic_launcher_background"
tools:ignore="VectorDrawableCompat" />
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
@ -72,9 +74,9 @@
app:layout_constraintBottom_toTopOf="@+id/richText" app:layout_constraintBottom_toTopOf="@+id/richText"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/by" app:layout_constraintStart_toEndOf="@+id/by"
app:layout_constraintTop_toBottomOf="@+id/title"></LinearLayout> app:layout_constraintTop_toBottomOf="@+id/title"/>
<cn.droidlover.xrichtext.XRichText <TextView
android:id="@+id/richText" android:id="@+id/richText"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="200dp" android:layout_height="200dp"

View File

@ -15,18 +15,47 @@
android:layout_width="100dp" android:layout_width="100dp"
android:layout_height="100dp" android:layout_height="100dp"
android:layout_margin="20dp" /> android:layout_margin="20dp" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
android:layout_margin="20dp"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="20dp"
android:layout_weight="1"
android:text="标题" android:text="标题"
android:textSize="18sp" /> android:textSize="18sp" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="删除" />
<Button
android:id="@+id/install"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="安装" />
</LinearLayout>
</LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -7,7 +7,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.1.2' classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0" classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0"