Merge remote-tracking branch 'master/dev-lxj-beta' into dev-lxj-beta

This commit is contained in:
2025-11-12 11:44:39 +08:00
382 changed files with 12604 additions and 2585 deletions

View File

@@ -17,7 +17,7 @@ android {
}
defaultConfig {
applicationId "com.qxcm.qxlive"
minSdk 24
minSdk 26
targetSdk 33
versionCode Integer.parseInt(project.findProperty("APP_VERSION_CODE"))
versionName project.findProperty("APP_VERSION_NAME")
@@ -66,19 +66,19 @@ android {
// // 测试版配置
beta {
// dimension "environment"
// // 测试版包名:基础包名 + .betacom.example.myapp.beta
// applicationIdSuffix ".beta"
// // 测试版版本名1.0-beta
// versionNameSuffix "-beta"
//
// // 【测试版应用名称】动态生成带标识的名称
// resValue "string", "app_name", "羽声-测试版"
//
// // 【测试版图标】替换为测试专用图标
// manifestPlaceholders = [
// appIcon: "@mipmap/ic_launcher_app_bat" // 需在main/res/mipmap放置该图标
// ]
dimension "environment"
// 测试版包名:基础包名 + .betacom.example.myapp.beta
applicationIdSuffix ".beta"
// 测试版版本名1.0-beta
versionNameSuffix "-beta"
// 【测试版应用名称】动态生成带标识的名称
resValue "string", "app_name", "羽声-测试版"
// 【测试版图标】替换为测试专用图标
manifestPlaceholders = [
appIcon: "@mipmap/ic_launcher_app_bat" // 需在main/res/mipmap放置该图标
]
}
}

View File

@@ -46,7 +46,8 @@ public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
switch (resp.errCode) {
case BaseResp.ErrCode.ERR_OK:
// 支付成功:这里需要调用后台接口确认支付状态(避免本地判断不可靠)
PayEvent messageEvent = new PayEvent(1, "支付成功");
EventBus.getDefault().post(messageEvent);
break;
case BaseResp.ErrCode.ERR_USER_CANCEL:
checkPayResultFromServer();

View File

@@ -57,6 +57,10 @@ xbanner = "1.7.0"
legacySupportV4 = "1.0.0"
fragmentKtx = "1.5.6"
interpolator = "1.0.0"
material3Android = "1.4.0"
uiToolingPreviewAndroid = "1.9.4"
tilesToolingPreview = "1.5.0"
constraintlayoutVersion = "2.2.1"
[libraries]
alipay-alipaysdk-android = { module = "com.alipay.sdk:alipaysdk-android", version.ref = "alipayAlipaysdkAndroid" }
@@ -118,6 +122,10 @@ zcw-togglebutton-library = { module = "com.zcw:togglebutton-library", version.re
androidx-legacy-support-v4 = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "legacySupportV4" }
androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "fragmentKtx" }
androidx-interpolator = { group = "androidx.interpolator", name = "interpolator", version.ref = "interpolator" }
androidx-material3-android = { group = "androidx.compose.material3", name = "material3-android", version.ref = "material3Android" }
androidx-ui-tooling-preview-android = { group = "androidx.compose.ui", name = "ui-tooling-preview-android", version.ref = "uiToolingPreviewAndroid" }
androidx-tiles-tooling-preview = { group = "androidx.wear.tiles", name = "tiles-tooling-preview", version.ref = "tilesToolingPreview" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayoutVersion" }
[plugins]

1
locktableview/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,31 @@
apply plugin: 'com.android.library'
group='com.github.RmondJone'
android {
namespace 'com.rmondjone.locktableview'
compileSdk 35
defaultConfig {
minSdk 24
targetSdk 35
versionCode 12
versionName "1.1.2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// 1. 核心AppCompat 依赖(必须添加,主题基础)
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.android.support:design:25.0.0'
implementation project(':moduleUtil')
}

View File

@@ -0,0 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.rmondjone.locktableview">
<application>
</application>
</manifest>

View File

@@ -0,0 +1,106 @@
package com.rmondjone.locktableview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
/**
* 说明 自定义水平滚动视图解决ScrollView在API23以下没有滚动监听事件问题
* 作者 郭翰林
* 创建时间 2017/3/31.
*/
public class CustomHorizontalScrollView extends HorizontalScrollView {
//触摸前的点
private float x;
//手势抬起之后的点
private float x1;
private onScrollChangeListener onScrollChangeListener;
public CustomHorizontalScrollView(Context context) {
super(context);
}
public CustomHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public interface onScrollChangeListener {
/**
* 滚动监听
*
* @param scrollView
* @param x
* @param y
*/
void onScrollChanged(HorizontalScrollView scrollView, int x, int y);
/**
* 滑动到最左侧
*
* @param scrollView
*/
void onScrollFarLeft(HorizontalScrollView scrollView);
/**
* 滑动到最右侧
*
* @param scrollView
*/
void onScrollFarRight(HorizontalScrollView scrollView);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
x = ev.getX();
break;
case MotionEvent.ACTION_UP:
x1 = ev.getX();
if (computeHorizontalScrollOffset() == 0 && x-x1<0) {
//滑动最左边
if (onScrollChangeListener != null) {
onScrollChangeListener.onScrollFarLeft(this);
}
} else if (computeHorizontalScrollRange() - computeHorizontalScrollOffset()
<= computeHorizontalScrollExtent() && x-x1>0) {
//滑动最右边
if (onScrollChangeListener != null) {
onScrollChangeListener.onScrollFarRight(this);
}
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
/**
* 设置监听
*
* @param onScrollChangeListener
*/
public void setOnScrollChangeListener(CustomHorizontalScrollView.onScrollChangeListener onScrollChangeListener) {
this.onScrollChangeListener = onScrollChangeListener;
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
//回调
if (onScrollChangeListener != null) {
onScrollChangeListener.onScrollChanged(this, l, t);
}
}
}

View File

@@ -0,0 +1,36 @@
package com.rmondjone.locktableview;
import android.content.Context;
/**
* Created by aaron on 16/8/3.
*/
public class DisplayUtil
{
public static int screenWidthPx; //屏幕宽 px
public static int screenhightPx; //屏幕高 px
public static float density;//屏幕密度
public static int densityDPI;//屏幕密度
public static float screenWidthDip;// dp单位
public static float screenHightDip;// dp单位
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
}

View File

@@ -0,0 +1,281 @@
package com.rmondjone.locktableview;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.NumberPicker;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
/**
* 说明
* 作者 郭翰林
* 创建时间 2017/9/17.
*/
public class LockColumnAdapter extends RecyclerView.Adapter<LockColumnAdapter.LockViewHolder> {
/**
* 上下文
*/
private Context mContext;
/**
* 第一列数据
*/
private ArrayList<String> mLockColumnDatas;
/**
* 第一行背景颜色
*/
private int mFristRowBackGroudColor;
/**
* 表格头部字体颜色
*/
private int mTableHeadTextColor;
/**
* 表格内容字体颜色
*/
private int mTableContentTextColor;
/**
* 是否锁定首行
*/
private boolean isLockFristRow = true;
/**
* 记录每列最大宽度
*/
private ArrayList<Integer> mColumnMaxWidths = new ArrayList<Integer>();
/**
* 记录每行最大高度
*/
private ArrayList<Integer> mRowMaxHeights = new ArrayList<Integer>();
/**
* 单元格字体大小
*/
private int mTextViewSize;
/**
* 单元格内边距
*/
private int mCellPadding;
/**
* Item点击事件
*/
private LockTableView.OnItemClickListenter mOnItemClickListenter;
/**
* Item长按事件
*/
private LockTableView.OnItemLongClickListenter mOnItemLongClickListenter;
/**
* Item项被选中监听(处理被选中的效果)
*/
private TableViewAdapter.OnItemSelectedListenter mOnItemSelectedListenter;
/**
* 是否启用交替行背景
*/
private boolean isAlternateRowBackground = false;
/**
* 交替行背景颜色1透明
*/
private int mAlternateRowColor1 = Color.TRANSPARENT;
/**
* 交替行背景颜色2#323252
*/
private int mAlternateRowColor2 = Color.parseColor("#323252");
// ... 在构造方法后添加以下方法
public void setAlternateRowBackground(boolean alternateRowBackground) {
isAlternateRowBackground = alternateRowBackground;
}
public void setAlternateRowColors(int color1, int color2) {
mAlternateRowColor1 = color1;
mAlternateRowColor2 = color2;
}
public LockColumnAdapter(Context mContext, ArrayList<String> mLockColumnDatas) {
this.mContext = mContext;
this.mLockColumnDatas = mLockColumnDatas;
}
@Override
public LockViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LockViewHolder holder = new LockViewHolder(LayoutInflater.from(mContext).inflate(R.layout.lock_item, null));
return holder;
}
@Override
public void onBindViewHolder(LockViewHolder holder, final int position) {
// 设置交替行背景颜色
if (isAlternateRowBackground && !isLockFristRow) {
if (position % 2 == 0) {
holder.mLinearLayout.setBackgroundColor(mAlternateRowColor1); // 偶数行透明
} else {
holder.mLinearLayout.setBackgroundColor(mAlternateRowColor2); // 奇数行#323252
}
} else if (isAlternateRowBackground && isLockFristRow) {
// 如果锁定首行,从第二行开始计算交替背景
if (position % 2 == 1) {
holder.mLinearLayout.setBackgroundColor(mAlternateRowColor1); // 偶数行透明
} else {
holder.mLinearLayout.setBackgroundColor(mAlternateRowColor2); // 奇数行#323252
}
}
//设置布局
holder.mTextView.setText(mLockColumnDatas.get(position));
holder.mTextView.setTextSize(mTextViewSize);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) holder.mTextView.getLayoutParams();
layoutParams.width = DisplayUtil.dip2px(mContext, mColumnMaxWidths.get(0));
if (isLockFristRow) {
layoutParams.height = DisplayUtil.dip2px(mContext, mRowMaxHeights.get(position + 1));
} else {
layoutParams.height = DisplayUtil.dip2px(mContext, mRowMaxHeights.get(position));
}
layoutParams.setMargins(mCellPadding, mCellPadding, mCellPadding, mCellPadding);
holder.mTextView.setLayoutParams(layoutParams);
//设置颜色
if (!isLockFristRow) {
if (position == 0) {
holder.mLinearLayout.setBackgroundColor(ContextCompat.getColor(mContext, mFristRowBackGroudColor));
holder.mTextView.setTextColor(ContextCompat.getColor(mContext, mTableHeadTextColor));
} else {
holder.mTextView.setTextColor(ContextCompat.getColor(mContext, mTableContentTextColor));
}
} else {
holder.mTextView.setTextColor(ContextCompat.getColor(mContext, mTableContentTextColor));
}
//添加事件
if(mOnItemClickListenter!=null){
holder.mLinearLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mOnItemSelectedListenter!=null){
mOnItemSelectedListenter.onItemSelected(v,position);
}
if(isLockFristRow){
mOnItemClickListenter.onItemClick(v,position+1);
}else{
if(position!=0){
mOnItemClickListenter.onItemClick(v,position);
}
}
}
});
}
if(mOnItemLongClickListenter!=null){
holder.mLinearLayout.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if(mOnItemSelectedListenter!=null){
mOnItemSelectedListenter.onItemSelected(v,position);
}
if (isLockFristRow){
mOnItemLongClickListenter.onItemLongClick(v,position+1);
}else{
if(position!=0){
mOnItemLongClickListenter.onItemLongClick(v,position);
}
}
return true;
}
});
}
//如果没有设置点击事件和长按事件
if(mOnItemClickListenter==null&&mOnItemLongClickListenter==null){
holder.mLinearLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mOnItemSelectedListenter!=null){
mOnItemSelectedListenter.onItemSelected(v,position);
}
}
});
holder.mLinearLayout.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if(mOnItemSelectedListenter!=null){
mOnItemSelectedListenter.onItemSelected(v,position);
}
return true;
}
});
}
}
@Override
public int getItemCount() {
return mLockColumnDatas.size();
}
@Override
public int getItemViewType(int position) {
return position;
}
class LockViewHolder extends RecyclerView.ViewHolder {
TextView mTextView;
LinearLayout mLinearLayout;
public LockViewHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView.findViewById(R.id.lock_text);
mLinearLayout = (LinearLayout) itemView.findViewById(R.id.lock_linearlayout);
}
}
//取得每行每列应用高宽
public void setColumnMaxWidths(ArrayList<Integer> mColumnMaxWidths) {
this.mColumnMaxWidths = mColumnMaxWidths;
}
public void setRowMaxHeights(ArrayList<Integer> mRowMaxHeights) {
this.mRowMaxHeights = mRowMaxHeights;
}
public void setTextViewSize(int mTextViewSize) {
this.mTextViewSize = mTextViewSize;
}
public void setLockFristRow(boolean lockFristRow) {
isLockFristRow = lockFristRow;
}
public void setCellPadding(int mCellPadding) {
this.mCellPadding = mCellPadding;
}
public void setFristRowBackGroudColor(int mFristRowBackGroudColor) {
this.mFristRowBackGroudColor = mFristRowBackGroudColor;
}
public void setTableHeadTextColor(int mTableHeadTextColor) {
this.mTableHeadTextColor = mTableHeadTextColor;
}
public void setTableContentTextColor(int mTableContentTextColor) {
this.mTableContentTextColor = mTableContentTextColor;
}
public void setOnItemClickListenter(LockTableView.OnItemClickListenter mOnItemClickListenter) {
this.mOnItemClickListenter = mOnItemClickListenter;
}
public void setOnItemLongClickListenter(LockTableView.OnItemLongClickListenter mOnItemLongClickListenter) {
this.mOnItemLongClickListenter = mOnItemLongClickListenter;
}
public void setOnItemSelectedListenter(TableViewAdapter.OnItemSelectedListenter mOnItemSelectedListenter) {
this.mOnItemSelectedListenter = mOnItemSelectedListenter;
}
}

View File

@@ -0,0 +1,993 @@
package com.rmondjone.locktableview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.method.NumberKeyListener;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.rmondjone.xrecyclerview.ProgressStyle;
import com.rmondjone.xrecyclerview.XRecyclerView;
import com.xscm.moduleutil.bean.TableCellData;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* 说明 可锁定首行和首列的表格视图
* 作者 郭翰林
* 创建时间 2017/3/29.
*/
public class LockTableView {
/**
* 上下文
*/
private Context mContext;
/**
* 表格父视图
*/
private ViewGroup mContentView;
/**
* 表格数据,每一行为一条数据,从表头计算
*/
private ArrayList<ArrayList<TableCellData>> mTableDatas = new ArrayList<ArrayList<TableCellData>>();
/**
* 表格视图
*/
private View mTableView;
/**
* 是否锁定首行
*/
private boolean isLockFristRow = true;
/**
* 是否锁定首列
*/
private boolean isLockFristColumn = true;
/**
* 最大列宽(dp)
*/
private int maxColumnWidth;
/**
* 最小列宽(dp)
*/
private int minColumnWidth;
/**
* 最大行高(dp)
*/
private int maxRowHeight;
/**
* 最小行高dp)
*/
private int minRowHeight;
/**
* 第一行背景颜色
*/
private int mFristRowBackGroudColor;
/**
* 数据为空时的缺省值
*/
private TableCellData mNullableString;
/**
* 单元格字体大小
*/
private int mTextViewSize;
/**
* 表格头部字体颜色
*/
private int mTableHeadTextColor;
/**
* 表格内容字体颜色
*/
private int mTableContentTextColor;
/**
* 表格横向滚动监听事件
*/
private OnTableViewListener mTableViewListener;
/**
* 表格横向滚动到边界监听事件
*/
private OnTableViewRangeListener mTableViewRangeListener;
/**
* 表格上拉刷新、下拉加载监听事件
*/
private OnLoadingListener mOnLoadingListener;
/**
* Item点击事件
*/
private OnItemClickListenter mOnItemClickListenter;
/**
* Item长按事件
*/
private OnItemLongClickListenter mOnItemLongClickListenter;
/**
* Item选中样式
*/
private int mOnItemSeletor;
/**
* 单元格内边距
*/
private int mCellPadding;
/**
* 要改变的列集合
*/
private HashMap<Integer, Integer> mChangeColumns = new HashMap<>();
//表格数据
/**
* 表格第一行数据,不包括第一个元素
*/
private ArrayList<TableCellData> mTableFristData = new ArrayList<>();
/**
* 表格第一列数据,不包括第一个元素
*/
private ArrayList<String> mTableColumnDatas = new ArrayList<>();
/**
* 表格左上角数据
*/
private String mColumnTitle;
/**
* 表格每一行数据,不包括第一行和第一列
*/
private ArrayList<ArrayList<TableCellData>> mTableRowDatas = new ArrayList<ArrayList<TableCellData>>();
/**
* 记录每列最大宽度
*/
private ArrayList<Integer> mColumnMaxWidths = new ArrayList<Integer>();
/**
* 记录每行最大高度
*/
private ArrayList<Integer> mRowMaxHeights = new ArrayList<Integer>();
/**
* 把所有的滚动视图放图列表,后面实现联动效果
*/
private ArrayList<HorizontalScrollView> mScrollViews = new ArrayList<HorizontalScrollView>();
//表格视图
/**
* 表格左上角视图
*/
private TextView mColumnTitleView;
/**
* 第一行布局(锁状态)
*/
private LinearLayout mLockHeadView;
/**
* 第一行布局(未锁状态)
*/
private LinearLayout mUnLockHeadView;
/**
* 第一行滚动视图(锁状态)
*/
private CustomHorizontalScrollView mLockScrollView;
/**
* 第一行滚动视图(未锁状态)
*/
private CustomHorizontalScrollView mUnLockScrollView;
/**
* 表格主视图
*/
private XRecyclerView mTableScrollView;
/**
* 列表适配器
*/
private TableViewAdapter mTableViewAdapter;
/**
* 构造方法
*
* @param mContext 上下文
* @param mContentView 表格父视图
* @param mTableDatas 表格数据
*/
public LockTableView(Context mContext, ViewGroup mContentView, ArrayList<ArrayList<TableCellData>> mTableDatas) {
this.mContext = mContext;
this.mContentView = mContentView;
this.mTableDatas = mTableDatas;
initAttrs();
}
/**
* 初始化属性
*/
private void initAttrs() {
mTableView = LayoutInflater.from(mContext).inflate(R.layout.locktableview, null);
maxColumnWidth =60;
minColumnWidth = 30;
minRowHeight = 42;
maxRowHeight = 42;
mTableHeadTextColor = R.color.beijin;
mTableContentTextColor = R.color.border_color;
mFristRowBackGroudColor = R.color.table_head;
mTextViewSize = 14;
mCellPadding=DisplayUtil.dip2px(mContext,11);
}
/**
* 展现视图
*/
public void show() {
initData();
initView();
mContentView.removeAllViews();//清空视图
mContentView.addView(mTableView);
}
/**
* 初始化表格数据
*/
private void initData() {
if (mTableDatas != null && mTableDatas.size() > 0) {
//检查数据,如果有一行数据长度不一致,以最长为标准填"N/A"字符串,如果有null也替换
int maxLength = 0;
for (int i = 0; i < mTableDatas.size(); i++) {
if (mTableDatas.get(i).size() >= maxLength) {
maxLength = mTableDatas.get(i).size();
}
ArrayList<TableCellData> rowDatas = mTableDatas.get(i);
for (int j = 0; j < rowDatas.size(); j++) {
if (rowDatas.get(j) == null || rowDatas.get(j).equals("")) {
rowDatas.set(j, mNullableString);
}
}
mTableDatas.set(i, rowDatas);
}
// Log.e("每行最多个数",maxLength+"");
for (int i = 0; i < mTableDatas.size(); i++) {
ArrayList<TableCellData> rowDatas = mTableDatas.get(i);
if (rowDatas.size() < maxLength) {
int size = maxLength - rowDatas.size();
for (int j = 0; j < size; j++) {
rowDatas.add(mNullableString);
}
mTableDatas.set(i, rowDatas);
}
}
// //测试
// for (int i=0;i<mTableDatas.size();i++){
// ArrayList<String> rowDatas=mTableDatas.get(i);
// StringBuffer b=new StringBuffer();
// for (String str:rowDatas){
// b.append("["+str+"]");
// }
// Log.e("第"+i+"行数据",b.toString()+"/"+rowDatas.size()+"个");
// }
//初始化每列最大宽度
for (int i = 0; i < mTableDatas.size(); i++) {
ArrayList<TableCellData> rowDatas = mTableDatas.get(i);
StringBuffer buffer = new StringBuffer();
for (int j = 0; j < rowDatas.size(); j++) {
TextView textView = new TextView(mContext);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextViewSize);
textView.setText(rowDatas.get(j).getTitle());
textView.setGravity(Gravity.CENTER);
//设置布局
LinearLayout.LayoutParams textViewParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
textViewParams.setMargins(mCellPadding, mCellPadding, mCellPadding, mCellPadding);//android:layout_margin="15dp"
textView.setLayoutParams(textViewParams);
if (i == 0) {
mColumnMaxWidths.add(measureTextWidth(textView, rowDatas.get(j).getTitle()));
buffer.append("[" + measureTextWidth(textView, rowDatas.get(j).getTitle()) + "]");
} else {
int length = mColumnMaxWidths.get(j);
int current = measureTextWidth(textView, rowDatas.get(j).getTitle());
if (current > length) {
mColumnMaxWidths.set(j, current);
}
buffer.append("[" + measureTextWidth(textView, rowDatas.get(j).getTitle()) + "]");
}
}
// Log.e("第"+i+"行列最大宽度",buffer.toString());
}
//如果用户指定某列宽度则按照用户指定宽度算
if (mChangeColumns.size() > 0) {
for (Integer key : mChangeColumns.keySet()) {
changeColumnWidth(key, mChangeColumns.get(key));
}
}
// Log.e("每列最大宽度dp:",mColumnMaxWidths.toString());
//初始化每行最大高度
for (int i = 0; i < mTableDatas.size(); i++) {
ArrayList<TableCellData> rowDatas = mTableDatas.get(i);
StringBuffer buffer = new StringBuffer();
TextView textView = new TextView(mContext);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextViewSize);
textView.setGravity(Gravity.CENTER);
//设置布局
LinearLayout.LayoutParams textViewParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
textViewParams.setMargins(mCellPadding, mCellPadding, mCellPadding, mCellPadding);//android:layout_margin="15dp"
textView.setLayoutParams(textViewParams);
int maxHeight = measureTextHeight(textView, rowDatas.get(0).getTitle());
mRowMaxHeights.add(maxHeight);
for (int j = 0; j < rowDatas.size(); j++) {
int currentHeight;
//如果用户指定某列宽度则按照用户指定宽度算对应列的高度
if (mChangeColumns.size() > 0 && mChangeColumns.containsKey(j)) {
currentHeight = getTextViewHeight(textView, rowDatas.get(j).getTitle(), mChangeColumns.get(j));
} else {
currentHeight = measureTextHeight(textView, rowDatas.get(j).getTitle());
}
buffer.append("[" + currentHeight + "]");
if (currentHeight > maxHeight) {
mRowMaxHeights.set(i, currentHeight);
}
}
// Log.e("第"+i+"行高度",buffer.toString());
}
// Log.e("每行最大高度dp:",mRowMaxHeights.toString());
if (isLockFristRow) {
ArrayList<TableCellData> fristRowDatas = (ArrayList<TableCellData>) mTableDatas.get(0).clone();
if (isLockFristColumn) {
//锁定第一列
mColumnTitle = fristRowDatas.get(0).getTitle();
fristRowDatas.remove(0);
mTableFristData.addAll(fristRowDatas);
//构造第一列数据,并且构造表格每行数据
for (int i = 1; i < mTableDatas.size(); i++) {
ArrayList<TableCellData> rowDatas = (ArrayList<TableCellData>) mTableDatas.get(i).clone();
mTableColumnDatas.add(rowDatas.get(0).getTitle());
rowDatas.remove(0);
mTableRowDatas.add(rowDatas);
}
} else {
mTableFristData.addAll(fristRowDatas);
for (int i = 1; i < mTableDatas.size(); i++) {
mTableRowDatas.add(mTableDatas.get(i));
}
}
} else {
if (isLockFristColumn) {
//锁定第一列
//构造第一列数据,并且构造表格每行数据
for (int i = 0; i < mTableDatas.size(); i++) {
ArrayList<TableCellData> rowDatas = (ArrayList<TableCellData>) mTableDatas.get(i).clone();
mTableColumnDatas.add(rowDatas.get(0).getTitle());
rowDatas.remove(0);
mTableRowDatas.add(rowDatas);
}
} else {
for (int i = 0; i < mTableDatas.size(); i++) {
mTableRowDatas.add(mTableDatas.get(i));
}
}
}
// Log.e("第一行数据", mTableFristData.toString());
// Log.e("第一列数据", mTableColumnDatas.toString());
// Log.e("每行数据", mTableRowDatas.toString());
} else {
Toast.makeText(mContext, "表格数据为空!", Toast.LENGTH_SHORT).show();
}
}
/**
* 初始化表格视图
*/
private void initView() {
mColumnTitleView = (TextView) mTableView.findViewById(R.id.lockHeadView_Text);
mLockHeadView = (LinearLayout) mTableView.findViewById(R.id.lockHeadView);
mUnLockHeadView = (LinearLayout) mTableView.findViewById(R.id.unLockHeadView);
mLockScrollView = (CustomHorizontalScrollView) mTableView.findViewById(R.id.lockHeadView_ScrollView);
mUnLockScrollView = (CustomHorizontalScrollView) mTableView.findViewById(R.id.unlockHeadView_ScrollView);
//表格主视图
mTableScrollView = (XRecyclerView) mTableView.findViewById(R.id.table_scrollView);
LinearLayoutManager layoutManager = new LinearLayoutManager(mContext);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mTableScrollView.setLayoutManager(layoutManager);
// mTableScrollView.setArrowImageView(R.drawable.iconfont_downgrey);
// mTableScrollView.setRefreshProgressStyle(ProgressStyle.BallRotate);
// mTableScrollView.setLoadingMoreProgressStyle(ProgressStyle.BallRotate);
// mTableScrollView.setLoadingListener(new XRecyclerView.LoadingListener() {
// @Override
// public void onRefresh() {
// if (mOnLoadingListener != null) {
// mOnLoadingListener.onRefresh(mTableScrollView, mTableDatas);
// }
// }
//
// @Override
// public void onLoadMore() {
// if (mOnLoadingListener != null) {
// mOnLoadingListener.onLoadMore(mTableScrollView, mTableDatas);
// }
// }
// });
mTableViewAdapter = new TableViewAdapter(mContext, mTableColumnDatas, mTableRowDatas, isLockFristColumn, isLockFristRow);
mTableViewAdapter.setCellPadding(mCellPadding);
mTableViewAdapter.setColumnMaxWidths(mColumnMaxWidths);
mTableViewAdapter.setRowMaxHeights(mRowMaxHeights);
mTableViewAdapter.setTextViewSize(mTextViewSize);
mTableViewAdapter.setTableContentTextColor(mTableContentTextColor);
mTableViewAdapter.setTableHeadTextColor(mTableHeadTextColor);
mTableViewAdapter.setFristRowBackGroudColor(mFristRowBackGroudColor);
mTableViewAdapter.setHorizontalScrollView(new OnTableViewListener() {
@Override
public void onTableViewScrollChange(int x, int y) {
changeAllScrollView(x, y);
}
});
// if (mOnItemClickListenter != null) {
mTableViewAdapter.setOnItemClickListenter(null);
// }
// if (mOnItemLongClickListenter != null) {
// mTableViewAdapter.setOnItemLongClickListenter(mOnItemLongClickListenter);
// }
// if (mOnItemSeletor != 0) {
// mTableViewAdapter.setOnItemSeletor(mOnItemSeletor);
// } else {
// mTableViewAdapter.setOnItemSeletor(R.color.dashline_color);
// }
mTableViewAdapter.setTableViewRangeListener(new OnTableViewRangeListener() {
@Override
public void onLeft(HorizontalScrollView view) {
if (mTableViewRangeListener != null) {
mTableViewRangeListener.onLeft(view);
}
}
@Override
public void onRight(HorizontalScrollView view) {
if (mTableViewRangeListener != null) {
mTableViewRangeListener.onRight(view);
}
}
});
mTableViewAdapter.setOnTableViewCreatedListener(new TableViewAdapter.OnTableViewCreatedListener() {
@Override
public void onTableViewCreatedCompleted(CustomHorizontalScrollView mScrollView) {
mScrollViews.add(mScrollView);
}
});
mTableScrollView.setAdapter(mTableViewAdapter);
mLockHeadView.setBackgroundColor(ContextCompat.getColor(mContext, mFristRowBackGroudColor));
mUnLockHeadView.setBackgroundColor(ContextCompat.getColor(mContext, mFristRowBackGroudColor));
if (isLockFristRow) {
if (isLockFristColumn) {
mLockHeadView.setVisibility(View.VISIBLE);
mUnLockHeadView.setVisibility(View.GONE);
} else {
mLockHeadView.setVisibility(View.GONE);
mUnLockHeadView.setVisibility(View.VISIBLE);
}
creatHeadView();
} else {
mLockHeadView.setVisibility(View.GONE);
mUnLockHeadView.setVisibility(View.GONE);
}
}
/**
* 创建头部视图
*/
private void creatHeadView() {
if (isLockFristColumn) {
mColumnTitleView.setTextColor(ContextCompat.getColor(mContext, mTableHeadTextColor));
mColumnTitleView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextViewSize);
mColumnTitleView.setText(mColumnTitle);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mColumnTitleView.getLayoutParams();
layoutParams.width = DisplayUtil.dip2px(mContext, mColumnMaxWidths.get(0));
layoutParams.height = DisplayUtil.dip2px(mContext, mRowMaxHeights.get(0));
layoutParams.setMargins(mCellPadding, mCellPadding, mCellPadding, mCellPadding);
mColumnTitleView.setLayoutParams(layoutParams);
//构造滚动视图
createScollview(mLockScrollView, mTableFristData, true);
mScrollViews.add(mLockScrollView);
mLockScrollView.setOnScrollChangeListener(new CustomHorizontalScrollView.onScrollChangeListener() {
@Override
public void onScrollChanged(HorizontalScrollView scrollView, int x, int y) {
changeAllScrollView(x, y);
}
@Override
public void onScrollFarLeft(HorizontalScrollView scrollView) {
if (mTableViewRangeListener != null) {
mTableViewRangeListener.onLeft(scrollView);
}
}
@Override
public void onScrollFarRight(HorizontalScrollView scrollView) {
if (mTableViewRangeListener != null) {
mTableViewRangeListener.onRight(scrollView);
}
}
});
} else {
createScollview(mUnLockScrollView, mTableFristData, true);
mScrollViews.add(mUnLockScrollView);
mUnLockScrollView.setOnScrollChangeListener(new CustomHorizontalScrollView.onScrollChangeListener() {
@Override
public void onScrollChanged(HorizontalScrollView scrollView, int x, int y) {
changeAllScrollView(x, y);
}
@Override
public void onScrollFarLeft(HorizontalScrollView scrollView) {
if (mTableViewRangeListener != null) {
mTableViewRangeListener.onLeft(scrollView);
}
}
@Override
public void onScrollFarRight(HorizontalScrollView scrollView) {
if (mTableViewRangeListener != null) {
mTableViewRangeListener.onRight(scrollView);
}
}
});
}
}
/**
* 改变所有滚动视图位置
*
* @param x
* @param y
*/
private void changeAllScrollView(int x, int y) {
if (mScrollViews.size() > 0) {
if (mTableViewListener != null) {
mTableViewListener.onTableViewScrollChange(x, y);
}
for (int i = 0; i < mScrollViews.size(); i++) {
HorizontalScrollView scrollView = mScrollViews.get(i);
scrollView.scrollTo(x, y);
}
}
}
/**
* 根据最大最小值计算TextView的宽度
*
* @param textView
* @param text
* @return
*/
private int measureTextWidth(TextView textView, String text) {
if (textView != null) {
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) textView.getLayoutParams();
int width = DisplayUtil.px2dip(mContext, layoutParams.leftMargin) +
DisplayUtil.px2dip(mContext, layoutParams.rightMargin) +
getTextViewWidth(textView, text);
if (width <= minColumnWidth) {
return minColumnWidth;
} else if (width > minColumnWidth && width <= maxColumnWidth) {
return width;
} else {
return maxColumnWidth;
}
}
return 0;
}
/**
* 计算TextView高度
*
* @param textView
* @param text
* @return
*/
private int measureTextHeight(TextView textView, String text) {
if (textView != null) {
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) textView.getLayoutParams();
int height = getTextViewHeight(textView, text);
if (height < minRowHeight) {
return minRowHeight;
} else if (height > minRowHeight && height < maxRowHeight) {
return height;
} else {
return maxRowHeight;
}
}
return 0;
}
/**
* 根据文字计算textview的高度
*
* @param textView
* @param text
* @return
*/
private int getTextViewHeight(TextView textView, String text) {
if (textView != null) {
int width = measureTextWidth(textView, text);
TextPaint textPaint = textView.getPaint();
StaticLayout staticLayout = new StaticLayout(text, textPaint, DisplayUtil.dip2px(mContext, width), Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
int height = DisplayUtil.px2dip(mContext, staticLayout.getHeight());
return height;
}
return 0;
}
/**
* 说明 根据文字和指定宽度计算高度
* 作者 郭翰林
* 创建时间 2018/3/15 下午12:39
*
* @param textView
* @param text
* @param width
* @return
*/
private int getTextViewHeight(TextView textView, String text, int width) {
if (textView != null) {
TextPaint textPaint = textView.getPaint();
StaticLayout staticLayout = new StaticLayout(text, textPaint, DisplayUtil.dip2px(mContext, width), Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
int height = DisplayUtil.px2dip(mContext, staticLayout.getHeight());
return height;
}
return 0;
}
/**
* 根据文字计算textview的高度
*
* @param view
* @param text
* @return
*/
private int getTextViewWidth(TextView view, String text) {
if (view != null) {
TextPaint paint = view.getPaint();
return DisplayUtil.px2dip(mContext, (int) paint.measureText(text));
}
return 0;
}
/**
* 构造滚动视图
*
* @param scrollView
* @param datas
* @param isFristRow 是否是第一行
*/
private void createScollview(HorizontalScrollView scrollView, List<TableCellData> datas, boolean isFristRow) {
//设置LinearLayout
LinearLayout linearLayout = new LinearLayout(mContext);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.MATCH_PARENT);
linearLayout.setLayoutParams(layoutParams);
linearLayout.setGravity(Gravity.CENTER);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
for (int i = 0; i < datas.size(); i++) {
//构造单元格
TextView textView = new TextView(mContext);
if (isFristRow) {
textView.setTextColor(ContextCompat.getColor(mContext, mTableHeadTextColor));
} else {
textView.setTextColor(ContextCompat.getColor(mContext, mTableContentTextColor));
}
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextViewSize);
textView.setGravity(Gravity.CENTER);
textView.setText(datas.get(i).getTitle());
//设置布局
LinearLayout.LayoutParams textViewParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
textViewParams.setMargins(mCellPadding, mCellPadding, mCellPadding, mCellPadding);
textView.setLayoutParams(textViewParams);
ViewGroup.LayoutParams textViewParamsCopy = textView.getLayoutParams();
if (isLockFristColumn) {
textViewParamsCopy.width = DisplayUtil.dip2px(mContext, mColumnMaxWidths.get(i + 1));
} else {
textViewParamsCopy.width = DisplayUtil.dip2px(mContext, mColumnMaxWidths.get(i));
}
linearLayout.addView(textView);
// //画分隔线
// if (i != datas.size() - 1) {
// View splitView = new View(mContext);
// ViewGroup.LayoutParams splitViewParmas = new ViewGroup.LayoutParams(DisplayUtil.dip2px(mContext, 1),
// ViewGroup.LayoutParams.MATCH_PARENT);
// splitView.setLayoutParams(splitViewParmas);
// if (isFristRow) {
// splitView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.white));
// } else {
// splitView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.light_gray));
// }
// linearLayout.addView(splitView);
// }
}
scrollView.addView(linearLayout);
}
/**
* 说明 改变指定列指定宽度
* 作者 郭翰林
* 创建时间 2018/3/15 上午11:06
*
* @param mColumnNum
* @param mColumnWidth
*/
private void changeColumnWidth(int mColumnNum, int mColumnWidth) {
if (mColumnMaxWidths != null && mColumnMaxWidths.size() > 0) {
if (mColumnNum < mColumnMaxWidths.size() && mColumnNum >= 0) {
mColumnMaxWidths.set(mColumnNum, mColumnWidth + DisplayUtil.px2dip(mContext, 15) * 2);
} else {
Log.e("LockTableView", "指定列数不存在");
}
}
}
//属性设置
public LockTableView setLockFristRow(boolean lockFristRow) {
isLockFristRow = lockFristRow;
return this;
}
public LockTableView setLockFristColumn(boolean lockFristColumn) {
isLockFristColumn = lockFristColumn;
return this;
}
public LockTableView setMaxColumnWidth(int maxColumnWidth) {
this.maxColumnWidth = maxColumnWidth;
return this;
}
public LockTableView setMinColumnWidth(int minColumnWidth) {
this.minColumnWidth = minColumnWidth;
return this;
}
public LockTableView setFristRowBackGroudColor(int mFristRowBackGroudColor) {
this.mFristRowBackGroudColor = mFristRowBackGroudColor;
return this;
}
public LockTableView setNullableString(TableCellData mNullableString) {
this.mNullableString = mNullableString;
return this;
}
public LockTableView setTextViewSize(int mTextViewSize) {
this.mTextViewSize = mTextViewSize;
return this;
}
public LockTableView setTableHeadTextColor(int mTableHeadTextColor) {
this.mTableHeadTextColor = mTableHeadTextColor;
return this;
}
public LockTableView setTableContentTextColor(int mTableContentTextColor) {
this.mTableContentTextColor = mTableContentTextColor;
return this;
}
public LockTableView setMaxRowHeight(int maxRowHeight) {
this.maxRowHeight = maxRowHeight;
return this;
}
public LockTableView setMinRowHeight(int minRowHeight) {
this.minRowHeight = minRowHeight;
return this;
}
public LockTableView setTableViewListener(OnTableViewListener mTableViewListener) {
this.mTableViewListener = mTableViewListener;
return this;
}
public LockTableView setOnLoadingListener(OnLoadingListener mOnLoadingListener) {
this.mOnLoadingListener = mOnLoadingListener;
return this;
}
public LockTableView setTableViewRangeListener(OnTableViewRangeListener mTableViewRangeListener) {
this.mTableViewRangeListener = mTableViewRangeListener;
return this;
}
public LockTableView setOnItemClickListenter(OnItemClickListenter mOnItemClickListenter) {
this.mOnItemClickListenter = mOnItemClickListenter;
return this;
}
public LockTableView setOnItemLongClickListenter(OnItemLongClickListenter mOnItemLongClickListenter) {
this.mOnItemLongClickListenter = mOnItemLongClickListenter;
return this;
}
public LockTableView setOnItemSeletor(int mOnItemSeletor) {
this.mOnItemSeletor = mOnItemSeletor;
return this;
}
public LockTableView setCellPadding(int mCellPadding) {
this.mCellPadding = DisplayUtil.dip2px(mContext,mCellPadding);
return this;
}
/**
* 指定第几列对应的宽度
*
* @param mColumnNum
* @param mColumnWidth
* @return
*/
public LockTableView setColumnWidth(int mColumnNum, int mColumnWidth) {
//判断是否已经设置过
if (mChangeColumns.containsKey(mColumnNum)) {
mChangeColumns.remove(mColumnNum);
}
mChangeColumns.put(mColumnNum, mColumnWidth);
return this;
}
//值获取
public ArrayList<Integer> getColumnMaxWidths() {
return mColumnMaxWidths;
}
public ArrayList<Integer> getRowMaxHeights() {
return mRowMaxHeights;
}
public LinearLayout getLockHeadView() {
return mLockHeadView;
}
public LinearLayout getUnLockHeadView() {
return mUnLockHeadView;
}
public XRecyclerView getTableScrollView() {
return mTableScrollView;
}
public ArrayList<HorizontalScrollView> getScrollViews() {
return mScrollViews;
}
/**
* 说明 数据刷新时,重新设值
* 作者 郭翰林
* 创建时间 2017/9/17 下午2:33
*
* @param mTableDatas
*/
public void setTableDatas(ArrayList<ArrayList<TableCellData>> mTableDatas) {
this.mTableDatas = mTableDatas;
mTableFristData.clear();
mTableColumnDatas.clear();
mTableRowDatas.clear();
mColumnMaxWidths.clear();
mRowMaxHeights.clear();
initData();
mTableViewAdapter.notifyDataSetChanged();
}
/**
* 横向滚动监听
*/
public interface OnTableViewListener {
/**
* 滚动监听
*
* @param x
* @param y
*/
void onTableViewScrollChange(int x, int y);
}
/**
* 横向滚动视图滑动到边界的监听
*/
public interface OnTableViewRangeListener {
/**
* 说明 最左侧
* 作者 郭翰林
* 创建时间 2017/12/14 下午4:45
*
* @param view
*/
void onLeft(HorizontalScrollView view);
/**
* 说明 最右侧
* 作者 郭翰林
* 创建时间 2017/12/14 下午4:45
*
* @param view
*/
void onRight(HorizontalScrollView view);
}
/**
* 上拉刷新,下拉加载
*/
public interface OnLoadingListener {
/**
* 说明 下拉刷新
* 作者 郭翰林
* 创建时间 2017/9/17 下午1:54
*
* @param mXRecyclerView
* @param mTableDatas
*/
void onRefresh(XRecyclerView mXRecyclerView, ArrayList<ArrayList<String>> mTableDatas);
/**
* 说明 上拉加载
* 作者 郭翰林
* 创建时间 2017/9/17 下午1:55
*
* @param mXRecyclerView
* @param mTableDatas
*/
void onLoadMore(XRecyclerView mXRecyclerView, ArrayList<ArrayList<String>> mTableDatas);
}
/**
* 说明 Item点击事件
* 作者 郭翰林
* 创建时间 2018/2/2 下午4:50
*/
public interface OnItemClickListenter {
/**
* @param item 点击项
* @param position 点击位置
*/
void onItemClick(View item, int position);
}
/**
* 说明 Item长按事件
* 作者 郭翰林
* 创建时间 2018/2/2 下午4:50
*/
public interface OnItemLongClickListenter {
/**
* @param item 点击项
* @param position 点击位置
*/
void onItemLongClick(View item, int position);
}
}

View File

@@ -0,0 +1,376 @@
package com.rmondjone.locktableview;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.rmondjone.xrecyclerview.XRecyclerView;
import com.xscm.moduleutil.bean.TableCellData;
import java.util.ArrayList;
/**
* 说明
* 作者 郭翰林
* 创建时间 2017/9/17.
*/
public class TableViewAdapter extends RecyclerView.Adapter<TableViewAdapter.TableViewHolder> {
/**
* 上下文
*/
private Context mContext;
/**
* 第一列数据
*/
private ArrayList<String> mLockColumnDatas;
/**
* 表格数据
*/
private ArrayList<ArrayList<TableCellData>> mTableDatas;
/**
* 第一列是否被锁定
*/
private boolean isLockColumn;
/**
* 第一行是否被锁定
*/
private boolean isLockFristRow;
/**
* 记录每列最大宽度
*/
private ArrayList<Integer> mColumnMaxWidths = new ArrayList<Integer>();
/**
* 记录每行最大高度
*/
private ArrayList<Integer> mRowMaxHeights = new ArrayList<Integer>();
/**
* 单元格字体大小
*/
private int mTextViewSize;
/**
* 第一行背景颜色
*/
private int mFristRowBackGroudColor;
/**
* 表格头部字体颜色
*/
private int mTableHeadTextColor;
/**
* 表格内容字体颜色
*/
private int mTableContentTextColor;
/**
* 单元格内边距
*/
private int mCellPadding;
/**
* 表格横向滚动监听事件
*/
private LockTableView.OnTableViewListener mTableViewListener;
/**
* 表格横向滚动到边界监听事件
*/
private LockTableView.OnTableViewRangeListener mTableViewRangeListener;
/**
* Item点击事件
*/
private LockTableView.OnItemClickListenter mOnItemClickListenter;
/**
* Item长按事件
*/
private LockTableView.OnItemLongClickListenter mOnItemLongClickListenter;
/**
* Item选中样式
*/
private int mOnItemSeletor;
/**
* 表格视图加载完成监听事件
*/
private OnTableViewCreatedListener mOnTableViewCreatedListener;
/**
* 锁定视图Adapter
*/
private LockColumnAdapter mLockAdapter;
/**
* 未锁定视图Adapter
*/
private UnLockColumnAdapter mUnLockAdapter;
/**
* 构造方法
*
* @param mContext
* @param mLockColumnDatas
* @param mTableDatas
* @param isLockColumn
*/
public TableViewAdapter(Context mContext, ArrayList<String> mLockColumnDatas, ArrayList<ArrayList<TableCellData>> mTableDatas, boolean isLockColumn, boolean isLockRow) {
this.mContext = mContext;
this.mLockColumnDatas = mLockColumnDatas;
this.mTableDatas = mTableDatas;
this.isLockColumn = isLockColumn;
this.isLockFristRow = isLockRow;
}
@Override
public TableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
TableViewHolder mTableViewHolder = new TableViewHolder(LayoutInflater.from(mContext).inflate(R.layout.locktablecontentview, null));
if (mOnTableViewCreatedListener != null) {
mOnTableViewCreatedListener.onTableViewCreatedCompleted(mTableViewHolder.mScrollView);
}
return mTableViewHolder;
}
@Override
public void onBindViewHolder(final TableViewHolder holder, int position) {
LinearLayoutManager layoutManager = new LinearLayoutManager(mContext);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
if (isLockColumn) {
//构造锁定视图
holder.mLockRecyclerView.setVisibility(View.VISIBLE);
if (mLockAdapter == null) {
mLockAdapter = new LockColumnAdapter(mContext, mLockColumnDatas);
mLockAdapter.setCellPadding(mCellPadding);
mLockAdapter.setRowMaxHeights(mRowMaxHeights);
mLockAdapter.setColumnMaxWidths(mColumnMaxWidths);
mLockAdapter.setTextViewSize(mTextViewSize);
mLockAdapter.setLockFristRow(isLockFristRow);
mLockAdapter.setFristRowBackGroudColor(mFristRowBackGroudColor);
mLockAdapter.setTableHeadTextColor(mTableHeadTextColor);
mLockAdapter.setTableContentTextColor(mTableContentTextColor);
// 添加交替行背景颜色设置
mLockAdapter.setAlternateRowBackground(true);
// mLockAdapter.setOnItemSelectedListenter(new OnItemSelectedListenter() {
// @Override
// public void onItemSelected(View view, int position) {
// RecyclerView.LayoutManager mLockLayoutManager = holder.mLockRecyclerView.getLayoutManager();
// int itemCount=mLockLayoutManager.getItemCount();
// View item=mLockLayoutManager.getChildAt(position);
// item.setBackgroundColor(ContextCompat.getColor(mContext,mOnItemSeletor));
// for(int i=0;i<itemCount;i++){
// if(i!=position){
// mLockLayoutManager.getChildAt(i).setBackgroundColor(Color.TRANSPARENT);
// }
// }
// RecyclerView.LayoutManager mUnLockLayoutManager = holder.mMainRecyclerView.getLayoutManager();
// int itemUnLockCount=mUnLockLayoutManager.getItemCount();
// View mUnlockItem=mUnLockLayoutManager.getChildAt(position);
// mUnlockItem.setBackgroundColor(ContextCompat.getColor(mContext,mOnItemSeletor));
// for(int i=0;i<itemUnLockCount;i++){
// if(i!=position){
// mUnLockLayoutManager.getChildAt(i).setBackgroundColor(Color.TRANSPARENT);
// }
// }
// }
// });
// if (mOnItemClickListenter != null) {
// mLockAdapter.setOnItemClickListenter(mOnItemClickListenter);
// }
// if (mOnItemLongClickListenter != null) {
// mLockAdapter.setOnItemLongClickListenter(mOnItemLongClickListenter);
// }
holder.mLockRecyclerView.setLayoutManager(layoutManager);
// holder.mLockRecyclerView.addItemDecoration(new DividerItemDecoration(mContext
// , DividerItemDecoration.VERTICAL));
holder.mLockRecyclerView.setAdapter(mLockAdapter);
} else {
mLockAdapter.notifyDataSetChanged();
}
} else {
holder.mLockRecyclerView.setVisibility(View.GONE);
}
//构造主表格视图
if (mUnLockAdapter == null) {
mUnLockAdapter = new UnLockColumnAdapter(mContext, mTableDatas);
mUnLockAdapter.setCellPadding(mCellPadding);
mUnLockAdapter.setColumnMaxWidths(mColumnMaxWidths);
mUnLockAdapter.setRowMaxHeights(mRowMaxHeights);
mUnLockAdapter.setTextViewSize(mTextViewSize);
mUnLockAdapter.setLockFristRow(isLockFristRow);
mUnLockAdapter.setFristRowBackGroudColor(mFristRowBackGroudColor);
mUnLockAdapter.setTableHeadTextColor(mTableHeadTextColor);
mUnLockAdapter.setTableContentTextColor(mTableContentTextColor);
mUnLockAdapter.setLockFristColumn(isLockColumn);
// 添加交替行背景颜色设置
mUnLockAdapter.setAlternateRowBackground(true);
// mUnLockAdapter.setOnItemSelectedListenter(new OnItemSelectedListenter() {
// @Override
// public void onItemSelected(View view, int position) {
// if(isLockColumn){
// RecyclerView.LayoutManager mLockLayoutManager = holder.mLockRecyclerView.getLayoutManager();
// int itemCount=mLockLayoutManager.getItemCount();
// View item=mLockLayoutManager.getChildAt(position);
// item.setBackgroundColor(ContextCompat.getColor(mContext,mOnItemSeletor));
// for(int i=0;i<itemCount;i++){
// if(i!=position){
// mLockLayoutManager.getChildAt(i).setBackgroundColor(Color.TRANSPARENT);
// }
// }
// }
// RecyclerView.LayoutManager mUnLockLayoutManager = holder.mMainRecyclerView.getLayoutManager();
// int itemUnLockCount=mUnLockLayoutManager.getItemCount();
// View mUnlockItem=mUnLockLayoutManager.getChildAt(position);
// mUnlockItem.setBackgroundColor(ContextCompat.getColor(mContext,mOnItemSeletor));
// for(int i=0;i<itemUnLockCount;i++){
// if(i!=position){
// mUnLockLayoutManager.getChildAt(i).setBackgroundColor(Color.TRANSPARENT);
// }
// }
// }
// });
// if (mOnItemClickListenter != null) {
// mUnLockAdapter.setOnItemClickListenter(mOnItemClickListenter);
// }
// if (mOnItemLongClickListenter != null) {
// mUnLockAdapter.setOnItemLongClickListenter(mOnItemLongClickListenter);
// }
LinearLayoutManager unlockLayoutManager = new LinearLayoutManager(mContext);
unlockLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
holder.mMainRecyclerView.setLayoutManager(unlockLayoutManager);
// holder.mMainRecyclerView.addItemDecoration(new DividerItemDecoration(mContext
// , DividerItemDecoration.VERTICAL));
holder.mMainRecyclerView.setAdapter(mUnLockAdapter);
} else {
mUnLockAdapter.notifyDataSetChanged();
}
}
@Override
public int getItemCount() {
return 1;
}
class TableViewHolder extends RecyclerView.ViewHolder {
RecyclerView mLockRecyclerView;
RecyclerView mMainRecyclerView;
CustomHorizontalScrollView mScrollView;
public TableViewHolder(View itemView) {
super(itemView);
mLockRecyclerView = (RecyclerView) itemView.findViewById(R.id.lock_recyclerview);
mMainRecyclerView = (RecyclerView) itemView.findViewById(R.id.main_recyclerview);
//解决滑动冲突只保留最外层RecyclerView的下拉和上拉事件
mLockRecyclerView.setFocusable(false);
mMainRecyclerView.setFocusable(false);
mScrollView = (CustomHorizontalScrollView) itemView.findViewById(R.id.lockScrollView_parent);
mScrollView.setOnScrollChangeListener(new CustomHorizontalScrollView.onScrollChangeListener() {
@Override
public void onScrollChanged(HorizontalScrollView scrollView, int x, int y) {
if (mTableViewListener != null) {
mTableViewListener.onTableViewScrollChange(x, y);
}
}
@Override
public void onScrollFarLeft(HorizontalScrollView scrollView) {
if (mTableViewRangeListener != null) {
mTableViewRangeListener.onLeft(scrollView);
}
}
@Override
public void onScrollFarRight(HorizontalScrollView scrollView) {
if (mTableViewRangeListener != null) {
mTableViewRangeListener.onRight(scrollView);
}
}
});
}
}
/**
* 表格创建完成回调
*/
public interface OnTableViewCreatedListener {
/**
* 返回当前横向滚动视图给上个界面
*/
void onTableViewCreatedCompleted(CustomHorizontalScrollView mScrollView);
}
/**
* Item项被选中监听
*/
public interface OnItemSelectedListenter {
void onItemSelected(View view, int position);
}
//取得每行每列应用高宽
public void setColumnMaxWidths(ArrayList<Integer> mColumnMaxWidths) {
this.mColumnMaxWidths = mColumnMaxWidths;
}
public void setRowMaxHeights(ArrayList<Integer> mRowMaxHeights) {
this.mRowMaxHeights = mRowMaxHeights;
}
public void setTextViewSize(int mTextViewSize) {
this.mTextViewSize = mTextViewSize;
}
public void setFristRowBackGroudColor(int mFristRowBackGroudColor) {
this.mFristRowBackGroudColor = mFristRowBackGroudColor;
}
public void setTableHeadTextColor(int mTableHeadTextColor) {
this.mTableHeadTextColor = mTableHeadTextColor;
}
public void setTableContentTextColor(int mTableContentTextColor) {
this.mTableContentTextColor = mTableContentTextColor;
}
public void setHorizontalScrollView(LockTableView.OnTableViewListener mTableViewListener) {
this.mTableViewListener = mTableViewListener;
}
public void setOnTableViewCreatedListener(OnTableViewCreatedListener mOnTableViewCreatedListener) {
this.mOnTableViewCreatedListener = mOnTableViewCreatedListener;
}
public void setTableViewRangeListener(LockTableView.OnTableViewRangeListener mTableViewRangeListener) {
this.mTableViewRangeListener = mTableViewRangeListener;
}
public void setOnItemClickListenter(LockTableView.OnItemClickListenter mOnItemClickListenter) {
this.mOnItemClickListenter = mOnItemClickListenter;
}
public void setOnItemLongClickListenter(LockTableView.OnItemLongClickListenter mOnItemLongClickListenter) {
this.mOnItemLongClickListenter = mOnItemLongClickListenter;
}
public void setOnItemSeletor(int mOnItemSeletor) {
this.mOnItemSeletor = mOnItemSeletor;
}
public void setCellPadding(int mCellPadding) {
this.mCellPadding = mCellPadding;
}
}

View File

@@ -0,0 +1,376 @@
package com.rmondjone.locktableview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.xscm.moduleutil.bean.TableCellData;
import java.util.ArrayList;
import java.util.List;
/**
* 说明
* 作者 郭翰林
* 创建时间 2017/9/17.
*/
public class UnLockColumnAdapter extends RecyclerView.Adapter<UnLockColumnAdapter.UnLockViewHolder> {
/**
* 上下文
*/
private Context mContext;
/**
* 表格数据
*/
private ArrayList<ArrayList<TableCellData>> mTableDatas;
/**
* 第一行背景颜色
*/
private int mFristRowBackGroudColor;
/**
* 表格头部字体颜色
*/
private int mTableHeadTextColor;
/**
* 表格内容字体颜色
*/
private int mTableContentTextColor;
/**
* 记录每列最大宽度
*/
private ArrayList<Integer> mColumnMaxWidths = new ArrayList<Integer>();
/**
* 记录每行最大高度
*/
private ArrayList<Integer> mRowMaxHeights = new ArrayList<Integer>();
/**
* 单元格字体大小
*/
private int mTextViewSize;
/**
* 是否锁定首行
*/
private boolean isLockFristRow = true;
/**
* 是否锁定首列
*/
private boolean isLockFristColumn = true;
/**
* 单元格内边距
*/
private int mCellPadding;
/**
* Item点击事件
*/
private LockTableView.OnItemClickListenter mOnItemClickListenter;
/**
* Item长按事件
*/
private LockTableView.OnItemLongClickListenter mOnItemLongClickListenter;
/**
* Item项被选中监听(处理被选中的效果)
*/
private TableViewAdapter.OnItemSelectedListenter mOnItemSelectedListenter;
/**
* 构造方法
*
* @param mContext
* @param mTableDatas
*/
public UnLockColumnAdapter(Context mContext, ArrayList<ArrayList<TableCellData>> mTableDatas) {
this.mContext = mContext;
this.mTableDatas = mTableDatas;
}
/**
* 是否启用交替行背景
*/
private boolean isAlternateRowBackground = false;
/**
* 交替行背景颜色1透明
*/
private int mAlternateRowColor1 = Color.TRANSPARENT;
/**
* 交替行背景颜色2#323252
*/
private int mAlternateRowColor2 = Color.parseColor("#323252");
// ... 在构造方法后添加以下方法
public void setAlternateRowBackground(boolean alternateRowBackground) {
isAlternateRowBackground = alternateRowBackground;
}
public void setAlternateRowColors(int color1, int color2) {
mAlternateRowColor1 = color1;
mAlternateRowColor2 = color2;
}
@Override
public int getItemCount() {
return mTableDatas.size();
}
@Override
public UnLockViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
UnLockViewHolder holder = new UnLockViewHolder(LayoutInflater.from(mContext).inflate(R.layout.unlock_item, null));
return holder;
}
@Override
public void onBindViewHolder(@NonNull UnLockViewHolder holder, @SuppressLint("RecyclerView") int position) {
ArrayList<TableCellData> datas = mTableDatas.get(position);
// 设置交替行背景颜色
if (isAlternateRowBackground && !isLockFristRow) {
if (position % 2 == 0) {
holder.mLinearLayout.setBackgroundColor(mAlternateRowColor1); // 偶数行透明
} else {
holder.mLinearLayout.setBackgroundColor(mAlternateRowColor2); // 奇数行#323252
}
} else if (isAlternateRowBackground && isLockFristRow) {
// 如果锁定首行,从第二行开始计算交替背景
if (position % 2 == 1) {
holder.mLinearLayout.setBackgroundColor(mAlternateRowColor1); // 偶数行透明
} else {
holder.mLinearLayout.setBackgroundColor(mAlternateRowColor2); // 奇数行#323252
}
}
if (isLockFristRow) {
//第一行是锁定的
createRowView(holder.mLinearLayout, datas, false, mRowMaxHeights.get(position + 1));
} else {
if (position == 0) {
holder.mLinearLayout.setBackgroundColor(ContextCompat.getColor(mContext, mFristRowBackGroudColor));
createRowView(holder.mLinearLayout, datas, true, mRowMaxHeights.get(position));
} else {
createRowView(holder.mLinearLayout, datas, false, mRowMaxHeights.get(position));
}
}
//添加事件
// if(mOnItemClickListenter!=null){
// holder.mLinearLayout.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// if(mOnItemSelectedListenter!=null){
// mOnItemSelectedListenter.onItemSelected(v,position);
// }
// if(isLockFristRow){
// mOnItemClickListenter.onItemClick(v,position+1);
// }else{
// if(position!=0){
// mOnItemClickListenter.onItemClick(v,position);
// }
// }
// }
// });
// }
// if(mOnItemLongClickListenter!=null){
// holder.mLinearLayout.setOnLongClickListener(new View.OnLongClickListener() {
// @Override
// public boolean onLongClick(View v) {
// if(mOnItemSelectedListenter!=null){
// mOnItemSelectedListenter.onItemSelected(v,position);
// }
// if (isLockFristRow){
// mOnItemLongClickListenter.onItemLongClick(v,position+1);
// }else{
// if(position!=0){
// mOnItemLongClickListenter.onItemLongClick(v,position);
// }
// }
// return true;
// }
// });
// }
//如果没有设置点击事件和长按事件
// if(mOnItemClickListenter==null&&mOnItemLongClickListenter==null){
// holder.mLinearLayout.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// if(mOnItemSelectedListenter!=null){
// mOnItemSelectedListenter.onItemSelected(v,position);
// }
// }
// });
// holder.mLinearLayout.setOnLongClickListener(new View.OnLongClickListener() {
// @Override
// public boolean onLongClick(View v) {
// if(mOnItemSelectedListenter!=null){
// mOnItemSelectedListenter.onItemSelected(v,position);
// }
// return true;
// }
// });
// }
}
@Override
public int getItemViewType(int position) {
return position;
}
//取得每行每列应用高宽
public void setColumnMaxWidths(ArrayList<Integer> mColumnMaxWidths) {
this.mColumnMaxWidths = mColumnMaxWidths;
}
public void setRowMaxHeights(ArrayList<Integer> mRowMaxHeights) {
this.mRowMaxHeights = mRowMaxHeights;
}
public void setTextViewSize(int mTextViewSize) {
this.mTextViewSize = mTextViewSize;
}
public void setLockFristRow(boolean lockFristRow) {
isLockFristRow = lockFristRow;
}
public void setFristRowBackGroudColor(int mFristRowBackGroudColor) {
this.mFristRowBackGroudColor = mFristRowBackGroudColor;
}
public void setTableHeadTextColor(int mTableHeadTextColor) {
this.mTableHeadTextColor = mTableHeadTextColor;
}
public void setTableContentTextColor(int mTableContentTextColor) {
this.mTableContentTextColor = mTableContentTextColor;
}
public void setLockFristColumn(boolean lockFristColumn) {
isLockFristColumn = lockFristColumn;
}
public void setOnItemClickListenter(LockTableView.OnItemClickListenter mOnItemClickListenter) {
this.mOnItemClickListenter = mOnItemClickListenter;
}
public void setOnItemLongClickListenter(LockTableView.OnItemLongClickListenter mOnItemLongClickListenter) {
this.mOnItemLongClickListenter = mOnItemLongClickListenter;
}
public void setOnItemSelectedListenter(TableViewAdapter.OnItemSelectedListenter mOnItemSelectedListenter) {
this.mOnItemSelectedListenter = mOnItemSelectedListenter;
}
public void setCellPadding(int mCellPadding) {
this.mCellPadding = mCellPadding;
}
class UnLockViewHolder extends RecyclerView.ViewHolder {
LinearLayout mLinearLayout;
public UnLockViewHolder(View itemView) {
super(itemView);
mLinearLayout = (LinearLayout) itemView.findViewById(R.id.unlock_linearlayout);
}
}
/**
* 构造每行数据视图
*
* @param linearLayout
* @param datas
* @param isFristRow 是否是第一行
*/
private void createRowView(LinearLayout linearLayout, List<TableCellData> datas, boolean isFristRow, int mMaxHeight) {
//设置LinearLayout
linearLayout.removeAllViews();//首先清空LinearLayout,复用会造成重复绘制,使内容超出预期长度
for (int i = 0; i < datas.size(); i++) {
//根据数据内容决定显示ImageView还是TextView
if (datas.get(i).getTitle().equals("1") || datas.get(i).getTitle().equals("0")) {
//显示ImageView
ImageView imageView = new ImageView(mContext);
if (datas.get(i).getTitle().equals("1")) {
imageView.setImageResource(com.xscm.moduleutil.R.mipmap.icon_yes);
} else {
imageView.setImageResource(com.xscm.moduleutil.R.mipmap.icon_no);
}
//设置布局
LinearLayout.LayoutParams imageParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
imageParams.setMargins(mCellPadding, mCellPadding, mCellPadding, mCellPadding);
imageParams.height = DisplayUtil.dip2px(mContext, mMaxHeight);
if (isLockFristColumn) {
imageParams.width = DisplayUtil.dip2px(mContext, mColumnMaxWidths.get(i+1));
} else {
imageParams.width = DisplayUtil.dip2px(mContext, mColumnMaxWidths.get(i));
}
imageView.setLayoutParams(imageParams);
imageView.setScaleType(ImageView.ScaleType.CENTER);
linearLayout.addView(imageView);
} else {
//显示TextView
TextView textView = new TextView(mContext);
if (isFristRow) {
textView.setTextColor(ContextCompat.getColor(mContext, mTableHeadTextColor));
} else {
textView.setTextColor(ContextCompat.getColor(mContext, mTableContentTextColor));
}
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextViewSize);
textView.setGravity(Gravity.CENTER);
textView.setText(datas.get(i).getTitle());
// 添加颜色值空值检查
String color = datas.get(i).getColor();
if (color != null && !color.isEmpty() &&
!color.equals("")) {
textView.setTextColor(Color.parseColor(color));
}
//设置布局
LinearLayout.LayoutParams textViewParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
textViewParams.setMargins(mCellPadding, mCellPadding, mCellPadding, mCellPadding);
textViewParams.height = DisplayUtil.dip2px(mContext, mMaxHeight);
if (isLockFristColumn) {
textViewParams.width = DisplayUtil.dip2px(mContext, mColumnMaxWidths.get(i+1));
} else {
textViewParams.width = DisplayUtil.dip2px(mContext, mColumnMaxWidths.get(i));
}
textView.setLayoutParams(textViewParams);
linearLayout.addView(textView);
}
// //画分隔线
// if (i != datas.size() - 1) {
// View splitView = new View(mContext);
// ViewGroup.LayoutParams splitViewParmas = new ViewGroup.LayoutParams(DisplayUtil.dip2px(mContext, 1),
// ViewGroup.LayoutParams.MATCH_PARENT);
// splitView.setLayoutParams(splitViewParmas);
// if (isFristRow) {
// splitView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.white));
// } else {
// splitView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.light_gray));
// }
// linearLayout.addView(splitView);
// }
}
}
}

View File

@@ -0,0 +1,41 @@
package com.rmondjone.xrecyclerview;
import com.google.android.material.appbar.AppBarLayout;
/**
* Created by jianghejie on 16/6/19.
*/
public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener {
public enum State {
EXPANDED,
COLLAPSED,
IDLE
}
private State mCurrentState = State.IDLE;
@Override
public final void onOffsetChanged(AppBarLayout appBarLayout, int i) {
if (i == 0) {
if (mCurrentState != State.EXPANDED) {
onStateChanged(appBarLayout, State.EXPANDED);
}
mCurrentState = State.EXPANDED;
} else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
if (mCurrentState != State.COLLAPSED) {
onStateChanged(appBarLayout, State.COLLAPSED);
}
mCurrentState = State.COLLAPSED;
} else {
if (mCurrentState != State.IDLE) {
onStateChanged(appBarLayout, State.IDLE);
}
mCurrentState = State.IDLE;
}
}
public abstract void onStateChanged(AppBarLayout appBarLayout, State state);
}

View File

@@ -0,0 +1,268 @@
package com.rmondjone.xrecyclerview;
import android.animation.ValueAnimator;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.rmondjone.xrecyclerview.progressindicator.AVLoadingIndicatorView;
import com.rmondjone.locktableview.R;
import java.util.Date;
public class ArrowRefreshHeader extends LinearLayout implements BaseRefreshHeader {
private LinearLayout mContainer;
private ImageView mArrowImageView;
private SimpleViewSwitcher mProgressBar;
private TextView mStatusTextView;
private int mState = STATE_NORMAL;
private TextView mHeaderTimeView;
private Animation mRotateUpAnim;
private Animation mRotateDownAnim;
private static final int ROTATE_ANIM_DURATION = 180;
public int mMeasuredHeight;
public ArrowRefreshHeader(Context context) {
super(context);
initView();
}
/**
* @param context
* @param attrs
*/
public ArrowRefreshHeader(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
private void initView() {
// 初始情况设置下拉刷新view高度为0
mContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate(
R.layout.listview_header, null);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
lp.setMargins(0, 0, 0, 0);
this.setLayoutParams(lp);
this.setPadding(0, 0, 0, 0);
addView(mContainer, new LayoutParams(LayoutParams.MATCH_PARENT, 0));
setGravity(Gravity.BOTTOM);
mArrowImageView = (ImageView)findViewById(R.id.listview_header_arrow);
mStatusTextView = (TextView)findViewById(R.id.refresh_status_textview);
//init the progress view
mProgressBar = (SimpleViewSwitcher)findViewById(R.id.listview_header_progressbar);
AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(getContext());
progressView.setIndicatorColor(0xffB5B5B5);
progressView.setIndicatorId(ProgressStyle.BallSpinFadeLoader);
mProgressBar.setView(progressView);
mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
mRotateUpAnim.setFillAfter(true);
mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
mRotateDownAnim.setFillAfter(true);
mHeaderTimeView = (TextView)findViewById(R.id.last_refresh_time);
measure(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
mMeasuredHeight = getMeasuredHeight();
}
public void setProgressStyle(int style) {
if(style == ProgressStyle.SysProgress){
mProgressBar.setView(new ProgressBar(getContext(), null, android.R.attr.progressBarStyle));
}else{
AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(this.getContext());
progressView.setIndicatorColor(0xffB5B5B5);
progressView.setIndicatorId(style);
mProgressBar.setView(progressView);
}
}
public void setArrowImageView(int resid){
mArrowImageView.setImageResource(resid);
}
public void setState(int state) {
if (state == mState) return ;
if (state == STATE_REFRESHING) { // 显示进度
mArrowImageView.clearAnimation();
mArrowImageView.setVisibility(View.INVISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
smoothScrollTo(mMeasuredHeight);
} else if(state == STATE_DONE) {
mArrowImageView.setVisibility(View.INVISIBLE);
mProgressBar.setVisibility(View.INVISIBLE);
} else { // 显示箭头图片
mArrowImageView.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.INVISIBLE);
}
switch(state){
case STATE_NORMAL:
if (mState == STATE_RELEASE_TO_REFRESH) {
mArrowImageView.startAnimation(mRotateDownAnim);
}
if (mState == STATE_REFRESHING) {
mArrowImageView.clearAnimation();
}
mStatusTextView.setText(R.string.listview_header_hint_normal);
break;
case STATE_RELEASE_TO_REFRESH:
if (mState != STATE_RELEASE_TO_REFRESH) {
mArrowImageView.clearAnimation();
mArrowImageView.startAnimation(mRotateUpAnim);
mStatusTextView.setText(R.string.listview_header_hint_release);
}
break;
case STATE_REFRESHING:
mStatusTextView.setText(R.string.refreshing);
break;
case STATE_DONE:
mStatusTextView.setText(R.string.refresh_done);
break;
default:
}
mState = state;
}
public int getState() {
return mState;
}
@Override
public void refreshComplete(){
mHeaderTimeView.setText(friendlyTime(new Date()));
setState(STATE_DONE);
new Handler().postDelayed(new Runnable(){
public void run() {
reset();
}
}, 200);
}
public void setVisibleHeight(int height) {
if (height < 0) height = 0;
LayoutParams lp = (LayoutParams) mContainer .getLayoutParams();
lp.height = height;
mContainer.setLayoutParams(lp);
}
public int getVisibleHeight() {
LayoutParams lp = (LayoutParams) mContainer.getLayoutParams();
return lp.height;
}
@Override
public void onMove(float delta) {
if(getVisibleHeight() > 0 || delta > 0) {
setVisibleHeight((int) delta + getVisibleHeight());
if (mState <= STATE_RELEASE_TO_REFRESH) { // 未处于刷新状态,更新箭头
if (getVisibleHeight() > mMeasuredHeight) {
setState(STATE_RELEASE_TO_REFRESH);
}else {
setState(STATE_NORMAL);
}
}
}
}
@Override
public boolean releaseAction() {
boolean isOnRefresh = false;
int height = getVisibleHeight();
if (height == 0) // not visible.
isOnRefresh = false;
if(getVisibleHeight() > mMeasuredHeight && mState < STATE_REFRESHING){
setState(STATE_REFRESHING);
isOnRefresh = true;
}
// refreshing and header isn't shown fully. do nothing.
if (mState == STATE_REFRESHING && height <= mMeasuredHeight) {
// return false;
}
if (mState != STATE_REFRESHING) {
smoothScrollTo(0);
}
if (mState == STATE_REFRESHING) {
int destHeight = mMeasuredHeight;
smoothScrollTo(destHeight);
}
return isOnRefresh;
}
public void reset() {
smoothScrollTo(0);
new Handler().postDelayed(new Runnable() {
public void run() {
setState(STATE_NORMAL);
}
}, 500);
}
private void smoothScrollTo(int destHeight) {
ValueAnimator animator = ValueAnimator.ofInt(getVisibleHeight(), destHeight);
animator.setDuration(300).start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
setVisibleHeight((int) animation.getAnimatedValue());
}
});
animator.start();
}
public static String friendlyTime(Date time) {
//获取time距离当前的秒数
int ct = (int)((System.currentTimeMillis() - time.getTime())/1000);
if(ct == 0) {
return "刚刚";
}
if(ct > 0 && ct < 60) {
return ct + "秒前";
}
if(ct >= 60 && ct < 3600) {
return Math.max(ct / 60,1) + "分钟前";
}
if(ct >= 3600 && ct < 86400)
return ct / 3600 + "小时前";
if(ct >= 86400 && ct < 2592000){ //86400 * 30
int day = ct / 86400 ;
return day + "天前";
}
if(ct >= 2592000 && ct < 31104000) { //86400 * 30
return ct / 2592000 + "月前";
}
return ct / 31104000 + "年前";
}
}

View File

@@ -0,0 +1,19 @@
package com.rmondjone.xrecyclerview;
/**
* Created by jianghejie on 15/11/22.
*/
interface BaseRefreshHeader {
int STATE_NORMAL = 0;
int STATE_RELEASE_TO_REFRESH = 1;
int STATE_REFRESHING = 2;
int STATE_DONE = 3;
void onMove(float delta);
boolean releaseAction();
void refreshComplete();
}

View File

@@ -0,0 +1,38 @@
package com.rmondjone.xrecyclerview;
/**
* Created by jianghejie on 16/6/20.
*/
public interface ItemTouchHelperAdapter {
/**
* Called when an item has been dragged far enough to trigger a move. This is called every time
* an item is shifted, and <strong>not</strong> at the end of a "drop" event.<br/>
* <br/>
* Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after
* adjusting the underlying data to reflect this move.
*
* @param fromPosition The start position of the moved item.
* @param toPosition Then resolved position of the moved item.
*
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
* @see RecyclerView.ViewHolder#getAdapterPosition()
*/
void onItemMove(int fromPosition, int toPosition);
/**
* Called when an item has been dismissed by a swipe.<br/>
* <br/>
* Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after
* adjusting the underlying data to reflect this removal.
*
* @param position The position of the item dismissed.
*
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
* @see RecyclerView.ViewHolder#getAdapterPosition()
*/
void onItemDismiss(int position);
}

View File

@@ -0,0 +1,108 @@
package com.rmondjone.xrecyclerview;
/**
* Created by jianghejie on 15/11/22.
*/
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class JellyView extends View implements BaseRefreshHeader{
Path path;
Paint paint;
private int minimumHeight = 0;
private int jellyHeight =0;
public JellyView(Context context) {
super(context);
init();
}
public JellyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public JellyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@SuppressWarnings("unused")
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public JellyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
if (isInEditMode()) {
return;
}
path = new Path();
paint = new Paint();
paint.setColor(getContext().getResources().getColor(android.R.color.holo_blue_bright));
paint.setAntiAlias(true);
}
public void setJellyColor(int jellyColor) {
paint.setColor(jellyColor);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path.reset();
path.lineTo(0, minimumHeight);
path.quadTo(getMeasuredWidth() / 2, minimumHeight + jellyHeight, getMeasuredWidth(), minimumHeight);
path.lineTo(getMeasuredWidth(), 0);
canvas.drawPath(path, paint);
}
@Override
public void setMinimumHeight(int minimumHeight) {
this.minimumHeight = minimumHeight;
}
public void setJellyHeight(int ribbonHeight) {
this.jellyHeight = ribbonHeight;
}
@Override
public int getMinimumHeight() {
return minimumHeight;
}
public int getJellyHeight() {
return jellyHeight;
}
@Override
public void refreshComplete(){
}
@Override
public void onMove(float delta) {
jellyHeight = jellyHeight + (int)delta;
Log.i("jellyHeight", "delta = " + delta);
this.invalidate();
}
@Override
public boolean releaseAction() {
return false;
}
}

View File

@@ -0,0 +1,108 @@
package com.rmondjone.xrecyclerview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.rmondjone.xrecyclerview.progressindicator.AVLoadingIndicatorView;
import com.rmondjone.locktableview.R;
public class LoadingMoreFooter extends LinearLayout {
private SimpleViewSwitcher progressCon;
public final static int STATE_LOADING = 0;
public final static int STATE_COMPLETE = 1;
public final static int STATE_NOMORE = 2;
private TextView mText;
private String loadingHint;
private String noMoreHint;
private String loadingDoneHint;
public LoadingMoreFooter(Context context) {
super(context);
initView();
}
/**
* @param context
* @param attrs
*/
public LoadingMoreFooter(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public void setLoadingHint(String hint) {
loadingHint = hint;
}
public void setNoMoreHint(String hint) {
noMoreHint = hint;
}
public void setLoadingDoneHint(String hint) {
loadingDoneHint = hint;
}
public void initView(){
setGravity(Gravity.CENTER);
setLayoutParams(new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
progressCon = new SimpleViewSwitcher(getContext());
progressCon.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(this.getContext());
progressView.setIndicatorColor(0xffB5B5B5);
progressView.setIndicatorId(ProgressStyle.BallSpinFadeLoader);
progressCon.setView(progressView);
addView(progressCon);
mText = new TextView(getContext());
mText.setText("正在加载...");
loadingHint = (String)getContext().getText(R.string.listview_loading);
noMoreHint = (String)getContext().getText(R.string.nomore_loading);
loadingDoneHint = (String)getContext().getText(R.string.loading_done);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins( (int)getResources().getDimension(R.dimen.textandiconmargin),0,0,0 );
mText.setLayoutParams(layoutParams);
addView(mText);
}
public void setProgressStyle(int style) {
if(style == ProgressStyle.SysProgress){
progressCon.setView(new ProgressBar(getContext(), null, android.R.attr.progressBarStyle));
}else{
AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(this.getContext());
progressView.setIndicatorColor(0xffB5B5B5);
progressView.setIndicatorId(style);
progressCon.setView(progressView);
}
}
public void setState(int state) {
switch(state) {
case STATE_LOADING:
progressCon.setVisibility(View.VISIBLE);
mText.setText(loadingHint);
this.setVisibility(View.VISIBLE);
break;
case STATE_COMPLETE:
mText.setText(loadingDoneHint);
this.setVisibility(View.GONE);
break;
case STATE_NOMORE:
mText.setText(noMoreHint);
progressCon.setVisibility(View.GONE);
this.setVisibility(View.VISIBLE);
break;
}
}
}

View File

@@ -0,0 +1,36 @@
package com.rmondjone.xrecyclerview;
/**
* Created by jianghejie on 15/11/23.
*/
public class ProgressStyle {
public static final int SysProgress=-1;
public static final int BallPulse=0;
public static final int BallGridPulse=1;
public static final int BallClipRotate=2;
public static final int BallClipRotatePulse=3;
public static final int SquareSpin=4;
public static final int BallClipRotateMultiple=5;
public static final int BallPulseRise=6;
public static final int BallRotate=7;
public static final int CubeTransition=8;
public static final int BallZigZag=9;
public static final int BallZigZagDeflect=10;
public static final int BallTrianglePath=11;
public static final int BallScale=12;
public static final int LineScale=13;
public static final int LineScaleParty=14;
public static final int BallScaleMultiple=15;
public static final int BallPulseSync=16;
public static final int BallBeat=17;
public static final int LineScalePulseOut=18;
public static final int LineScalePulseOutRapid=19;
public static final int BallScaleRipple=20;
public static final int BallScaleRippleMultiple=21;
public static final int BallSpinFadeLoader=22;
public static final int LineSpinFadeLoader=23;
public static final int TriangleSkewSpin=24;
public static final int Pacman=25;
public static final int BallGridBeat=26;
public static final int SemiCircleSpin=27;
}

View File

@@ -0,0 +1,88 @@
package com.rmondjone.xrecyclerview;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.View;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
/**
* Created by jianghejie on 16/6/20.
*/
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
public static final float ALPHA_FULL = 1.0f;
private final ItemTouchHelperAdapter mAdapter;
private XRecyclerView mXrecyclerView;
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter, XRecyclerView recyclerView) {
mAdapter = adapter;
this.mXrecyclerView = recyclerView;
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
// Enable drag and swipe in both directions
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
if (source.getItemViewType() != target.getItemViewType()) {
return false;
}
// Notify the adapter of the move
mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
// Notify the adapter of the dismissal
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
// Fade out the view as it is swiped out of the parent's bounds
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
View itemView = viewHolder.itemView;
final float alpha = ALPHA_FULL - Math.abs(dX) / (float) itemView.getWidth();
itemView.setAlpha(alpha);
}
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
// Let the view holder know that this item is being moved or dragged
viewHolder.itemView.setBackgroundColor(Color.LTGRAY);
}
super.onSelectedChanged(viewHolder, actionState);
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setAlpha(ALPHA_FULL);
viewHolder.itemView.setBackgroundColor(0);
}
}

View File

@@ -0,0 +1,60 @@
package com.rmondjone.xrecyclerview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by jianghejie on 15/11/22.
*/
public class SimpleViewSwitcher extends ViewGroup {
public SimpleViewSwitcher(Context context) {
super(context);
}
public SimpleViewSwitcher(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SimpleViewSwitcher(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int childCount = this.getChildCount();
int maxHeight = 0;
int maxWidth = 0;
for (int i = 0; i < childCount; i++) {
View child = this.getChildAt(i);
this.measureChild(child, widthMeasureSpec, heightMeasureSpec);
int cw = child.getMeasuredWidth();
// int ch = child.getMeasuredHeight();
maxWidth = child.getMeasuredWidth();
maxHeight = child.getMeasuredHeight();
}
setMeasuredDimension(maxWidth, maxHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
child.layout(0, 0, r - l, b - t);
}
}
}
public void setView(View view) {
if (this.getChildCount() != 0){
this.removeViewAt(0);
}
this.addView(view,0);
}
}

View File

@@ -0,0 +1,775 @@
package com.rmondjone.xrecyclerview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import com.google.android.material.appbar.AppBarLayout;
import java.util.ArrayList;
import java.util.List;
public class XRecyclerView extends RecyclerView {
private boolean isLoadingData = false;
private boolean isNoMore = false;
private int mRefreshProgressStyle = ProgressStyle.SysProgress;
private int mLoadingMoreProgressStyle = ProgressStyle.SysProgress;
private ArrayList<View> mHeaderViews = new ArrayList<>();
private WrapAdapter mWrapAdapter;
private float mLastY = -1;
private static final float DRAG_RATE = 3;
private LoadingListener mLoadingListener;
private ArrowRefreshHeader mRefreshHeader;
private boolean pullRefreshEnabled = true;
private boolean loadingMoreEnabled = true;
//下面的ItemViewType是保留值(ReservedItemViewType),如果用户的adapter与它们重复将会强制抛出异常。不过为了简化,我们检测到重复时对用户的提示是ItemViewType必须小于10000
private static final int TYPE_REFRESH_HEADER = 10000;//设置一个很大的数字,尽可能避免和用户的adapter冲突
private static final int TYPE_FOOTER = 10001;
private static final int HEADER_INIT_INDEX = 10002;
private static List<Integer> sHeaderTypes = new ArrayList<>();//每个header必须有不同的type,不然滚动的时候顺序会变化
private int mPageCount = 0;
//adapter没有数据的时候显示,类似于listView的emptyView
private View mEmptyView;
private View mFootView;
private final RecyclerView.AdapterDataObserver mDataObserver = new DataObserver();
private AppBarStateChangeListener.State appbarState = AppBarStateChangeListener.State.EXPANDED;
public XRecyclerView(Context context) {
this(context, null);
}
public XRecyclerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public XRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
if (pullRefreshEnabled) {
mRefreshHeader = new ArrowRefreshHeader(getContext());
mRefreshHeader.setProgressStyle(mRefreshProgressStyle);
}
LoadingMoreFooter footView = new LoadingMoreFooter(getContext());
footView.setProgressStyle(mLoadingMoreProgressStyle);
mFootView = footView;
mFootView.setVisibility(GONE);
}
public void setFootViewText(String loading, String noMore) {
if (mFootView instanceof LoadingMoreFooter) {
((LoadingMoreFooter) mFootView).setLoadingHint(loading);
((LoadingMoreFooter) mFootView).setNoMoreHint(noMore);
}
}
public void addHeaderView(View view) {
sHeaderTypes.add(HEADER_INIT_INDEX + mHeaderViews.size());
mHeaderViews.add(view);
if (mWrapAdapter != null) {
mWrapAdapter.notifyDataSetChanged();
}
}
//根据header的ViewType判断是哪个header
private View getHeaderViewByType(int itemType) {
if (!isHeaderType(itemType)) {
return null;
}
return mHeaderViews.get(itemType - HEADER_INIT_INDEX);
}
//判断一个type是否为HeaderType
private boolean isHeaderType(int itemViewType) {
return mHeaderViews.size() > 0 && sHeaderTypes.contains(itemViewType);
}
//判断是否是XRecyclerView保留的itemViewType
private boolean isReservedItemViewType(int itemViewType) {
if (itemViewType == TYPE_REFRESH_HEADER || itemViewType == TYPE_FOOTER || sHeaderTypes.contains(itemViewType)) {
return true;
} else {
return false;
}
}
public void setFootView(final View view) {
mFootView = view;
}
public void loadMoreComplete() {
isLoadingData = false;
if (mFootView instanceof LoadingMoreFooter) {
((LoadingMoreFooter) mFootView).setState(LoadingMoreFooter.STATE_COMPLETE);
} else {
mFootView.setVisibility(View.GONE);
}
}
public void setNoMore(boolean noMore) {
isLoadingData = false;
isNoMore = noMore;
if (mFootView instanceof LoadingMoreFooter) {
((LoadingMoreFooter) mFootView).setState(isNoMore ? LoadingMoreFooter.STATE_NOMORE : LoadingMoreFooter.STATE_COMPLETE);
} else {
mFootView.setVisibility(View.GONE);
}
}
public void refresh() {
if (pullRefreshEnabled && mLoadingListener != null) {
mRefreshHeader.setState(ArrowRefreshHeader.STATE_REFRESHING);
mLoadingListener.onRefresh();
}
}
public void reset() {
setNoMore(false);
loadMoreComplete();
refreshComplete();
}
public void refreshComplete() {
mRefreshHeader.refreshComplete();
setNoMore(false);
}
public void setRefreshHeader(ArrowRefreshHeader refreshHeader) {
mRefreshHeader = refreshHeader;
}
public void setPullRefreshEnabled(boolean enabled) {
pullRefreshEnabled = enabled;
}
public void setLoadingMoreEnabled(boolean enabled) {
loadingMoreEnabled = enabled;
if (!enabled) {
if (mFootView instanceof LoadingMoreFooter) {
((LoadingMoreFooter) mFootView).setState(LoadingMoreFooter.STATE_COMPLETE);
}
}
}
public void setRefreshProgressStyle(int style) {
mRefreshProgressStyle = style;
if (mRefreshHeader != null) {
mRefreshHeader.setProgressStyle(style);
}
}
public void setLoadingMoreProgressStyle(int style) {
mLoadingMoreProgressStyle = style;
if (mFootView instanceof LoadingMoreFooter) {
((LoadingMoreFooter) mFootView).setProgressStyle(style);
}
}
public void setArrowImageView(int resId) {
if (mRefreshHeader != null) {
mRefreshHeader.setArrowImageView(resId);
}
}
public void setEmptyView(View emptyView) {
this.mEmptyView = emptyView;
mDataObserver.onChanged();
}
public View getEmptyView() {
return mEmptyView;
}
@Override
public void setAdapter(Adapter adapter) {
mWrapAdapter = new WrapAdapter(adapter);
super.setAdapter(mWrapAdapter);
adapter.registerAdapterDataObserver(mDataObserver);
mDataObserver.onChanged();
}
//避免用户自己调用getAdapter() 引起的ClassCastException
@Override
public Adapter getAdapter() {
if (mWrapAdapter != null)
return mWrapAdapter.getOriginalAdapter();
else
return null;
}
@Override
public void setLayoutManager(LayoutManager layout) {
super.setLayoutManager(layout);
if (mWrapAdapter != null) {
if (layout instanceof GridLayoutManager) {
final GridLayoutManager gridManager = ((GridLayoutManager) layout);
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return (mWrapAdapter.isHeader(position) || mWrapAdapter.isFooter(position) || mWrapAdapter.isRefreshHeader(position))
? gridManager.getSpanCount() : 1;
}
});
}
}
}
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
if (state == RecyclerView.SCROLL_STATE_IDLE && mLoadingListener != null && !isLoadingData && loadingMoreEnabled) {
LayoutManager layoutManager = getLayoutManager();
int lastVisibleItemPosition;
if (layoutManager instanceof GridLayoutManager) {
lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int[] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(into);
lastVisibleItemPosition = findMax(into);
} else {
lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
}
if (layoutManager.getChildCount() > 0
&& lastVisibleItemPosition >= layoutManager.getItemCount() - 1
//因为我的控件里layoutManager.getItemCount()永远等于1(item),layoutManager.getChildCount()
//永远等于2(刷新头和item),所以这个条件永远不成立,永远调不了上拉加载事件,需要注释掉
//&& layoutManager.getItemCount() > layoutManager.getChildCount()
&& !isNoMore
&& mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING
//只有当更多底部视图显示在页面上才开始进行加载更多数据
&&lastVisibleItemPosition>=2) {
isLoadingData = true;
if (mFootView instanceof LoadingMoreFooter) {
((LoadingMoreFooter) mFootView).setState(LoadingMoreFooter.STATE_LOADING);
} else {
mFootView.setVisibility(View.VISIBLE);
}
mLoadingListener.onLoadMore();
}
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mLastY == -1) {
mLastY = ev.getRawY();
}
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastY = ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
final float deltaY = ev.getRawY() - mLastY;
mLastY = ev.getRawY();
if (isOnTop() && pullRefreshEnabled && appbarState == AppBarStateChangeListener.State.EXPANDED) {
mRefreshHeader.onMove(deltaY / DRAG_RATE);
if (mRefreshHeader.getVisibleHeight() > 0 && mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) {
return false;
}
}
break;
default:
mLastY = -1; // reset
if (isOnTop() && pullRefreshEnabled && appbarState == AppBarStateChangeListener.State.EXPANDED) {
if (mRefreshHeader.releaseAction()) {
if (mLoadingListener != null) {
mLoadingListener.onRefresh();
}
}
}
break;
}
return super.onTouchEvent(ev);
}
private int findMax(int[] lastPositions) {
int max = lastPositions[0];
for (int value : lastPositions) {
if (value > max) {
max = value;
}
}
return max;
}
private boolean isOnTop() {
if (mRefreshHeader.getParent() != null) {
return true;
} else {
return false;
}
}
private class DataObserver extends RecyclerView.AdapterDataObserver {
@Override
public void onChanged() {
if (mWrapAdapter != null) {
mWrapAdapter.notifyDataSetChanged();
}
if (mWrapAdapter != null && mEmptyView != null) {
int emptyCount = 1 + mWrapAdapter.getHeadersCount();
if (loadingMoreEnabled) {
emptyCount++;
}
if (mWrapAdapter.getItemCount() == emptyCount) {
mEmptyView.setVisibility(View.VISIBLE);
XRecyclerView.this.setVisibility(View.GONE);
} else {
mEmptyView.setVisibility(View.GONE);
XRecyclerView.this.setVisibility(View.VISIBLE);
}
}
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount);
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount);
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload);
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount);
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
mWrapAdapter.notifyItemMoved(fromPosition, toPosition);
}
}
;
private class WrapAdapter extends RecyclerView.Adapter<ViewHolder> {
private RecyclerView.Adapter adapter;
public WrapAdapter(RecyclerView.Adapter adapter) {
this.adapter = adapter;
}
public RecyclerView.Adapter getOriginalAdapter() {
return this.adapter;
}
public boolean isHeader(int position) {
return position >= 1 && position < mHeaderViews.size() + 1;
}
public boolean isFooter(int position) {
if (loadingMoreEnabled) {
return position == getItemCount() - 1;
} else {
return false;
}
}
public boolean isRefreshHeader(int position) {
return position == 0;
}
public int getHeadersCount() {
return mHeaderViews.size();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_REFRESH_HEADER) {
return new SimpleViewHolder(mRefreshHeader);
} else if (isHeaderType(viewType)) {
return new SimpleViewHolder(getHeaderViewByType(viewType));
} else if (viewType == TYPE_FOOTER) {
return new SimpleViewHolder(mFootView);
}
return adapter.onCreateViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (isHeader(position) || isRefreshHeader(position)) {
return;
}
int adjPosition = position - (getHeadersCount() + 1);
int adapterCount;
if (adapter != null) {
adapterCount = adapter.getItemCount();
if (adjPosition < adapterCount) {
adapter.onBindViewHolder(holder, adjPosition);
}
}
}
// some times we need to override this
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List<Object> payloads) {
if (isHeader(position) || isRefreshHeader(position)) {
return;
}
int adjPosition = position - (getHeadersCount() + 1);
int adapterCount;
if (adapter != null) {
adapterCount = adapter.getItemCount();
if (adjPosition < adapterCount) {
if (payloads.isEmpty()) {
adapter.onBindViewHolder(holder, adjPosition);
} else {
adapter.onBindViewHolder(holder, adjPosition, payloads);
}
}
}
}
@Override
public int getItemCount() {
if (loadingMoreEnabled) {
if (adapter != null) {
return getHeadersCount() + adapter.getItemCount() + 2;
} else {
return getHeadersCount() + 2;
}
} else {
if (adapter != null) {
return getHeadersCount() + adapter.getItemCount() + 1;
} else {
return getHeadersCount() + 1;
}
}
}
@Override
public int getItemViewType(int position) {
int adjPosition = position - (getHeadersCount() + 1);
if (isRefreshHeader(position)) {
return TYPE_REFRESH_HEADER;
}
if (isHeader(position)) {
position = position - 1;
return sHeaderTypes.get(position);
}
if (isFooter(position)) {
return TYPE_FOOTER;
}
int adapterCount;
if (adapter != null) {
adapterCount = adapter.getItemCount();
if (adjPosition < adapterCount) {
int type = adapter.getItemViewType(adjPosition);
if (isReservedItemViewType(type)) {
throw new IllegalStateException("XRecyclerView require itemViewType in adapter should be less than 10000 ");
}
return type;
}
}
return 0;
}
@Override
public long getItemId(int position) {
if (adapter != null && position >= getHeadersCount() + 1) {
int adjPosition = position - (getHeadersCount() + 1);
if (adjPosition < adapter.getItemCount()) {
return adapter.getItemId(adjPosition);
}
}
return -1;
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if (manager instanceof GridLayoutManager) {
final GridLayoutManager gridManager = ((GridLayoutManager) manager);
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return (isHeader(position) || isFooter(position) || isRefreshHeader(position))
? gridManager.getSpanCount() : 1;
}
});
}
adapter.onAttachedToRecyclerView(recyclerView);
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
adapter.onDetachedFromRecyclerView(recyclerView);
}
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
super.onViewAttachedToWindow(holder);
ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
if (lp != null
&& lp instanceof StaggeredGridLayoutManager.LayoutParams
&& (isHeader(holder.getLayoutPosition()) || isRefreshHeader(holder.getLayoutPosition()) || isFooter(holder.getLayoutPosition()))) {
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
p.setFullSpan(true);
}
adapter.onViewAttachedToWindow(holder);
}
@Override
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
adapter.onViewDetachedFromWindow(holder);
}
@Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
adapter.onViewRecycled(holder);
}
@Override
public boolean onFailedToRecycleView(RecyclerView.ViewHolder holder) {
return adapter.onFailedToRecycleView(holder);
}
@Override
public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
adapter.unregisterAdapterDataObserver(observer);
}
@Override
public void registerAdapterDataObserver(AdapterDataObserver observer) {
adapter.registerAdapterDataObserver(observer);
}
private class SimpleViewHolder extends RecyclerView.ViewHolder {
public SimpleViewHolder(View itemView) {
super(itemView);
}
}
}
public void setLoadingListener(LoadingListener listener) {
mLoadingListener = listener;
}
public interface LoadingListener {
void onRefresh();
void onLoadMore();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
//解决和CollapsingToolbarLayout冲突的问题
AppBarLayout appBarLayout = null;
ViewParent p = getParent();
while (p != null) {
if (p instanceof CoordinatorLayout) {
break;
}
p = p.getParent();
}
if (p instanceof CoordinatorLayout) {
CoordinatorLayout coordinatorLayout = (CoordinatorLayout) p;
final int childCount = coordinatorLayout.getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
final View child = coordinatorLayout.getChildAt(i);
if (child instanceof AppBarLayout) {
appBarLayout = (AppBarLayout) child;
break;
}
}
if (appBarLayout != null) {
appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() {
@Override
public void onStateChanged(AppBarLayout appBarLayout, State state) {
appbarState = state;
}
});
}
}
}
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
private int mOrientation;
/**
* Sole constructor. Takes in a {@link Drawable} to be used as the interior
* divider.
*
* @param divider A divider {@code Drawable} to be drawn on the RecyclerView
*/
public DividerItemDecoration(Drawable divider) {
mDivider = divider;
}
/**
* Draws horizontal or vertical dividers onto the parent RecyclerView.
*
* @param canvas The {@link Canvas} onto which dividers will be drawn
* @param parent The RecyclerView onto which dividers are being added
* @param state The current RecyclerView.State of the RecyclerView
*/
@Override
public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == LinearLayoutManager.HORIZONTAL) {
drawHorizontalDividers(canvas, parent);
} else if (mOrientation == LinearLayoutManager.VERTICAL) {
drawVerticalDividers(canvas, parent);
}
}
/**
* Determines the size and location of offsets between items in the parent
* RecyclerView.
*
* @param outRect The {@link Rect} of offsets to be added around the child
* view
* @param view The child view to be decorated with an offset
* @param parent The RecyclerView onto which dividers are being added
* @param state The current RecyclerView.State of the RecyclerView
*/
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (parent.getChildAdapterPosition(view) <= mWrapAdapter.getHeadersCount() + 1) {
return;
}
mOrientation = ((LinearLayoutManager) parent.getLayoutManager()).getOrientation();
if (mOrientation == LinearLayoutManager.HORIZONTAL) {
outRect.left = mDivider.getIntrinsicWidth();
} else if (mOrientation == LinearLayoutManager.VERTICAL) {
outRect.top = mDivider.getIntrinsicHeight();
}
}
/**
* Adds dividers to a RecyclerView with a LinearLayoutManager or its
* subclass oriented horizontally.
*
* @param canvas The {@link Canvas} onto which horizontal dividers will be
* drawn
* @param parent The RecyclerView onto which horizontal dividers are being
* added
*/
private void drawHorizontalDividers(Canvas canvas, RecyclerView parent) {
int parentTop = parent.getPaddingTop();
int parentBottom = parent.getHeight() - parent.getPaddingBottom();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount - 1; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int parentLeft = child.getRight() + params.rightMargin;
int parentRight = parentLeft + mDivider.getIntrinsicWidth();
mDivider.setBounds(parentLeft, parentTop, parentRight, parentBottom);
mDivider.draw(canvas);
}
}
/**
* Adds dividers to a RecyclerView with a LinearLayoutManager or its
* subclass oriented vertically.
*
* @param canvas The {@link Canvas} onto which vertical dividers will be
* drawn
* @param parent The RecyclerView onto which vertical dividers are being
* added
*/
private void drawVerticalDividers(Canvas canvas, RecyclerView parent) {
int parentLeft = parent.getPaddingLeft();
int parentRight = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount - 1; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int parentTop = child.getBottom() + params.bottomMargin;
int parentBottom = parentTop + mDivider.getIntrinsicHeight();
mDivider.setBounds(parentLeft, parentTop, parentRight, parentBottom);
mDivider.draw(canvas);
}
}
}
/**
* add by LinGuanHong below
*/
private int scrollDyCounter = 0;
@Override
public void scrollToPosition(int position) {
super.scrollToPosition(position);
/** if we scroll to position 0, the scrollDyCounter should be reset */
if (position == 0) {
scrollDyCounter = 0;
}
}
@Override
public void onScrolled(int dx, int dy) {
super.onScrolled(dx, dy);
if (scrollAlphaChangeListener == null) {
return;
}
int height = scrollAlphaChangeListener.setLimitHeight();
scrollDyCounter = scrollDyCounter + dy;
if (scrollDyCounter <= 0) {
scrollAlphaChangeListener.onAlphaChange(0);
} else if (scrollDyCounter <= height && scrollDyCounter > 0) {
float scale = (float) scrollDyCounter / height; /** 255/height = x/255 */
float alpha = (255 * scale);
scrollAlphaChangeListener.onAlphaChange((int) alpha);
} else {
scrollAlphaChangeListener.onAlphaChange(255);
}
}
private ScrollAlphaChangeListener scrollAlphaChangeListener;
public void setScrollAlphaChangeListener(
ScrollAlphaChangeListener scrollAlphaChangeListener
) {
this.scrollAlphaChangeListener = scrollAlphaChangeListener;
}
public interface ScrollAlphaChangeListener {
void onAlphaChange(int alpha);
/**
* you can handle the alpha insert it
*/
int setLimitHeight(); /** set a height for the begging of the alpha start to change */
}
}

View File

@@ -0,0 +1,365 @@
package com.rmondjone.xrecyclerview.progressindicator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.IntDef;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallBeatIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallClipRotateIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallClipRotateMultipleIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallClipRotatePulseIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallGridBeatIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallGridPulseIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallPulseIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallPulseRiseIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallPulseSyncIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallRotateIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallScaleIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallScaleMultipleIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallScaleRippleIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallScaleRippleMultipleIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallSpinFadeLoaderIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallTrianglePathIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallZigZagDeflectIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BallZigZagIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.BaseIndicatorController;
import com.rmondjone.xrecyclerview.progressindicator.indicator.CubeTransitionIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.LineScaleIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.LineScalePartyIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.LineScalePulseOutIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.LineScalePulseOutRapidIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.LineSpinFadeLoaderIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.PacmanIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.SemiCircleSpinIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.SquareSpinIndicator;
import com.rmondjone.xrecyclerview.progressindicator.indicator.TriangleSkewSpinIndicator;
import com.rmondjone.locktableview.R;
/**
* Created by Jack on 2015/10/15
*
.BallPulse,
.BallGridPulse,
.BallClipRotate,
.BallClipRotatePulse,
.SquareSpin,
.BallClipRotateMultiple,
.BallPulseRise,
.BallRotate,
.CubeTransition,
.BallZigZag,
.BallZigZagDeflect,
.BallTrianglePath,
.BallScale,
.LineScale,
.LineScaleParty,
.BallScaleMultiple,
.BallPulseSync,
.BallBeat,
.LineScalePulseOut,
.LineScalePulseOutRapid,
.BallScaleRipple,
.BallScaleRippleMultiple,
.BallSpinFadeLoader,
.LineSpinFadeLoader,
.TriangleSkewSpin,
.Pacman,
.BallGridBeat,
.SemiCircleSpin
*
*/
public class AVLoadingIndicatorView extends View{
//indicators
public static final int BallPulse=0;
public static final int BallGridPulse=1;
public static final int BallClipRotate=2;
public static final int BallClipRotatePulse=3;
public static final int SquareSpin=4;
public static final int BallClipRotateMultiple=5;
public static final int BallPulseRise=6;
public static final int BallRotate=7;
public static final int CubeTransition=8;
public static final int BallZigZag=9;
public static final int BallZigZagDeflect=10;
public static final int BallTrianglePath=11;
public static final int BallScale=12;
public static final int LineScale=13;
public static final int LineScaleParty=14;
public static final int BallScaleMultiple=15;
public static final int BallPulseSync=16;
public static final int BallBeat=17;
public static final int LineScalePulseOut=18;
public static final int LineScalePulseOutRapid=19;
public static final int BallScaleRipple=20;
public static final int BallScaleRippleMultiple=21;
public static final int BallSpinFadeLoader=22;
public static final int LineSpinFadeLoader=23;
public static final int TriangleSkewSpin=24;
public static final int Pacman=25;
public static final int BallGridBeat=26;
public static final int SemiCircleSpin=27;
@IntDef(flag = true,
value = {
BallPulse,
BallGridPulse,
BallClipRotate,
BallClipRotatePulse,
SquareSpin,
BallClipRotateMultiple,
BallPulseRise,
BallRotate,
CubeTransition,
BallZigZag,
BallZigZagDeflect,
BallTrianglePath,
BallScale,
LineScale,
LineScaleParty,
BallScaleMultiple,
BallPulseSync,
BallBeat,
LineScalePulseOut,
LineScalePulseOutRapid,
BallScaleRipple,
BallScaleRippleMultiple,
BallSpinFadeLoader,
LineSpinFadeLoader,
TriangleSkewSpin,
Pacman,
BallGridBeat,
SemiCircleSpin
})
public @interface Indicator{}
//Sizes (with defaults in DP)
public static final int DEFAULT_SIZE=30;
//attrs
int mIndicatorId;
int mIndicatorColor;
Paint mPaint;
BaseIndicatorController mIndicatorController;
private boolean mHasAnimation;
public AVLoadingIndicatorView(Context context) {
super(context);
init(null, 0);
}
public AVLoadingIndicatorView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public AVLoadingIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public AVLoadingIndicatorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs, defStyleAttr);
}
private void init(AttributeSet attrs, int defStyle) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.AVLoadingIndicatorView);
mIndicatorId=a.getInt(R.styleable.AVLoadingIndicatorView_indicator, BallPulse);
mIndicatorColor=a.getColor(R.styleable.AVLoadingIndicatorView_indicator_color, Color.WHITE);
a.recycle();
mPaint=new Paint();
mPaint.setColor(mIndicatorColor);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
applyIndicator();
}
public void setIndicatorId(int indicatorId){
mIndicatorId = indicatorId;
applyIndicator();
}
public void setIndicatorColor(int color){
mIndicatorColor = color;
mPaint.setColor(mIndicatorColor);
this.invalidate();
}
private void applyIndicator(){
switch (mIndicatorId){
case BallPulse:
mIndicatorController=new BallPulseIndicator();
break;
case BallGridPulse:
mIndicatorController=new BallGridPulseIndicator();
break;
case BallClipRotate:
mIndicatorController=new BallClipRotateIndicator();
break;
case BallClipRotatePulse:
mIndicatorController=new BallClipRotatePulseIndicator();
break;
case SquareSpin:
mIndicatorController=new SquareSpinIndicator();
break;
case BallClipRotateMultiple:
mIndicatorController=new BallClipRotateMultipleIndicator();
break;
case BallPulseRise:
mIndicatorController=new BallPulseRiseIndicator();
break;
case BallRotate:
mIndicatorController=new BallRotateIndicator();
break;
case CubeTransition:
mIndicatorController=new CubeTransitionIndicator();
break;
case BallZigZag:
mIndicatorController=new BallZigZagIndicator();
break;
case BallZigZagDeflect:
mIndicatorController=new BallZigZagDeflectIndicator();
break;
case BallTrianglePath:
mIndicatorController=new BallTrianglePathIndicator();
break;
case BallScale:
mIndicatorController=new BallScaleIndicator();
break;
case LineScale:
mIndicatorController=new LineScaleIndicator();
break;
case LineScaleParty:
mIndicatorController=new LineScalePartyIndicator();
break;
case BallScaleMultiple:
mIndicatorController=new BallScaleMultipleIndicator();
break;
case BallPulseSync:
mIndicatorController=new BallPulseSyncIndicator();
break;
case BallBeat:
mIndicatorController=new BallBeatIndicator();
break;
case LineScalePulseOut:
mIndicatorController=new LineScalePulseOutIndicator();
break;
case LineScalePulseOutRapid:
mIndicatorController=new LineScalePulseOutRapidIndicator();
break;
case BallScaleRipple:
mIndicatorController=new BallScaleRippleIndicator();
break;
case BallScaleRippleMultiple:
mIndicatorController=new BallScaleRippleMultipleIndicator();
break;
case BallSpinFadeLoader:
mIndicatorController=new BallSpinFadeLoaderIndicator();
break;
case LineSpinFadeLoader:
mIndicatorController=new LineSpinFadeLoaderIndicator();
break;
case TriangleSkewSpin:
mIndicatorController=new TriangleSkewSpinIndicator();
break;
case Pacman:
mIndicatorController=new PacmanIndicator();
break;
case BallGridBeat:
mIndicatorController=new BallGridBeatIndicator();
break;
case SemiCircleSpin:
mIndicatorController=new SemiCircleSpinIndicator();
break;
}
mIndicatorController.setTarget(this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureDimension(dp2px(DEFAULT_SIZE), widthMeasureSpec);
int height = measureDimension(dp2px(DEFAULT_SIZE), heightMeasureSpec);
setMeasuredDimension(width, height);
}
private int measureDimension(int defaultSize,int measureSpec){
int result = defaultSize;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(defaultSize, specSize);
} else {
result = defaultSize;
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawIndicator(canvas);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!mHasAnimation){
mHasAnimation=true;
applyAnimation();
}
}
@Override
public void setVisibility(int v) {
if (getVisibility() != v) {
super.setVisibility(v);
if (v == GONE || v == INVISIBLE) {
mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.END);
} else {
mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START);
}
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.CANCEL);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START);
}
void drawIndicator(Canvas canvas){
mIndicatorController.draw(canvas, mPaint);
}
void applyAnimation(){
mIndicatorController.initAnimation();
}
private int dp2px(int dpValue) {
return (int) getContext().getResources().getDisplayMetrics().density * dpValue;
}
}

View File

@@ -0,0 +1,82 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class BallBeatIndicator extends com.rmondjone.xrecyclerview.progressindicator.indicator.BaseIndicatorController {
public static final float SCALE=1.0f;
public static final int ALPHA=255;
private float[] scaleFloats=new float[]{SCALE,
SCALE,
SCALE};
int[] alphas=new int[]{ALPHA,
ALPHA,
ALPHA,};
@Override
public void draw(Canvas canvas, Paint paint) {
float circleSpacing=4;
float radius=(getWidth()-circleSpacing*2)/6;
float x = getWidth()/ 2-(radius*2+circleSpacing);
float y=getHeight() / 2;
for (int i = 0; i < 3; i++) {
canvas.save();
float translateX=x+(radius*2)*i+circleSpacing*i;
canvas.translate(translateX, y);
canvas.scale(scaleFloats[i], scaleFloats[i]);
paint.setAlpha(alphas[i]);
canvas.drawCircle(0, 0, radius, paint);
canvas.restore();
}
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
int[] delays=new int[]{350,0,350};
for (int i = 0; i < 3; i++) {
final int index=i;
ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.75f,1);
scaleAnim.setDuration(700);
scaleAnim.setRepeatCount(-1);
scaleAnim.setStartDelay(delays[i]);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloats[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
ValueAnimator alphaAnim=ValueAnimator.ofInt(255,51,255);
alphaAnim.setDuration(700);
alphaAnim.setRepeatCount(-1);
alphaAnim.setStartDelay(delays[i]);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
alphas[index] = (int) animation.getAnimatedValue();
postInvalidate();
}
});
alphaAnim.start();
animators.add(scaleAnim);
animators.add(alphaAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,65 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/16.
*/
public class BallClipRotateIndicator extends BaseIndicatorController {
float scaleFloat=1,degrees;
@Override
public void draw(Canvas canvas, Paint paint) {
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
float circleSpacing=12;
float x = (getWidth()) / 2;
float y=(getHeight()) / 2;
canvas.translate(x, y);
canvas.scale(scaleFloat, scaleFloat);
canvas.rotate(degrees);
RectF rectF=new RectF(-x+circleSpacing,-y+circleSpacing,0+x-circleSpacing,0+y-circleSpacing);
canvas.drawArc(rectF, -45, 270, false, paint);
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.6f,0.5f,1);
scaleAnim.setDuration(750);
scaleAnim.setRepeatCount(-1);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloat = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
ValueAnimator rotateAnim=ValueAnimator.ofFloat(0,180,360);
rotateAnim.setDuration(750);
rotateAnim.setRepeatCount(-1);
rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
degrees = (float) animation.getAnimatedValue();
postInvalidate();
}
});
rotateAnim.start();
animators.add(scaleAnim);
animators.add(rotateAnim);
return animators;
}
}

View File

@@ -0,0 +1,85 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/17.
*/
public class BallClipRotateMultipleIndicator extends BaseIndicatorController{
float scaleFloat=1,degrees;
@Override
public void draw(Canvas canvas, Paint paint) {
paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE);
float circleSpacing=12;
float x=getWidth()/2;
float y=getHeight()/2;
canvas.save();
canvas.translate(x, y);
canvas.scale(scaleFloat, scaleFloat);
canvas.rotate(degrees);
//draw two big arc
float[] bStartAngles=new float[]{135,-45};
for (int i = 0; i < 2; i++) {
RectF rectF=new RectF(-x+circleSpacing,-y+circleSpacing,x-circleSpacing,y-circleSpacing);
canvas.drawArc(rectF, bStartAngles[i], 90, false, paint);
}
canvas.restore();
canvas.translate(x, y);
canvas.scale(scaleFloat, scaleFloat);
canvas.rotate(-degrees);
//draw two small arc
float[] sStartAngles=new float[]{225,45};
for (int i = 0; i < 2; i++) {
RectF rectF=new RectF(-x/1.8f+circleSpacing,-y/1.8f+circleSpacing,x/1.8f-circleSpacing,y/1.8f-circleSpacing);
canvas.drawArc(rectF, sStartAngles[i], 90, false, paint);
}
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.6f,1);
scaleAnim.setDuration(1000);
scaleAnim.setRepeatCount(-1);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloat = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
ValueAnimator rotateAnim=ValueAnimator.ofFloat(0, 180,360);
rotateAnim.setDuration(1000);
rotateAnim.setRepeatCount(-1);
rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
degrees = (float) animation.getAnimatedValue();
postInvalidate();
}
});
rotateAnim.start();
animators.add(scaleAnim);
animators.add(rotateAnim);
return animators;
}
}

View File

@@ -0,0 +1,94 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/16.
*/
public class BallClipRotatePulseIndicator extends BaseIndicatorController {
float scaleFloat1,scaleFloat2,degrees;
@Override
public void draw(Canvas canvas, Paint paint) {
float circleSpacing=12;
float x=getWidth()/2;
float y=getHeight()/2;
//draw fill circle
canvas.save();
canvas.translate(x, y);
canvas.scale(scaleFloat1, scaleFloat1);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(0, 0, x / 2.5f, paint);
canvas.restore();
canvas.translate(x, y);
canvas.scale(scaleFloat2, scaleFloat2);
canvas.rotate(degrees);
paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE);
//draw two arc
float[] startAngles=new float[]{225,45};
for (int i = 0; i < 2; i++) {
RectF rectF=new RectF(-x+circleSpacing,-y+circleSpacing,x-circleSpacing,y-circleSpacing);
canvas.drawArc(rectF, startAngles[i], 90, false, paint);
}
}
@Override
public List<Animator> createAnimation() {
ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.3f,1);
scaleAnim.setDuration(1000);
scaleAnim.setRepeatCount(-1);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloat1 = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
ValueAnimator scaleAnim2=ValueAnimator.ofFloat(1,0.6f,1);
scaleAnim2.setDuration(1000);
scaleAnim2.setRepeatCount(-1);
scaleAnim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloat2 = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim2.start();
ValueAnimator rotateAnim=ValueAnimator.ofFloat(0, 180,360);
rotateAnim.setDuration(1000);
rotateAnim.setRepeatCount(-1);
rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
degrees = (float) animation.getAnimatedValue();
postInvalidate();
}
});
rotateAnim.start();
List<Animator> animators=new ArrayList<>();
animators.add(scaleAnim);
animators.add(scaleAnim2);
animators.add(rotateAnim);
return animators;
}
}

View File

@@ -0,0 +1,76 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/20.
*/
public class BallGridBeatIndicator extends BaseIndicatorController {
public static final int ALPHA=255;
int[] alphas=new int[]{ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA};
@Override
public void draw(Canvas canvas, Paint paint) {
float circleSpacing=4;
float radius=(getWidth()-circleSpacing*4)/6;
float x = getWidth()/ 2-(radius*2+circleSpacing);
float y = getWidth()/ 2-(radius*2+circleSpacing);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
canvas.save();
float translateX=x+(radius*2)*j+circleSpacing*j;
float translateY=y+(radius*2)*i+circleSpacing*i;
canvas.translate(translateX, translateY);
paint.setAlpha(alphas[3 * i + j]);
canvas.drawCircle(0, 0, radius, paint);
canvas.restore();
}
}
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
int[] durations={960, 930, 1190, 1130, 1340, 940, 1200, 820, 1190};
int[] delays= {360, 400, 680, 410, 710, -150, -120, 10, 320};
for (int i = 0; i < 9; i++) {
final int index=i;
ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 168,255);
alphaAnim.setDuration(durations[i]);
alphaAnim.setRepeatCount(-1);
alphaAnim.setStartDelay(delays[i]);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
alphas[index] = (int) animation.getAnimatedValue();
postInvalidate();
}
});
alphaAnim.start();
animators.add(alphaAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,103 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/16.
*/
public class BallGridPulseIndicator extends BaseIndicatorController{
public static final int ALPHA=255;
public static final float SCALE=1.0f;
int[] alphas=new int[]{ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA};
float[] scaleFloats=new float[]{SCALE,
SCALE,
SCALE,
SCALE,
SCALE,
SCALE,
SCALE,
SCALE,
SCALE};
@Override
public void draw(Canvas canvas, Paint paint) {
float circleSpacing=4;
float radius=(getWidth()-circleSpacing*4)/6;
float x = getWidth()/ 2-(radius*2+circleSpacing);
float y = getWidth()/ 2-(radius*2+circleSpacing);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
canvas.save();
float translateX=x+(radius*2)*j+circleSpacing*j;
float translateY=y+(radius*2)*i+circleSpacing*i;
canvas.translate(translateX, translateY);
canvas.scale(scaleFloats[3 * i + j], scaleFloats[3 * i + j]);
paint.setAlpha(alphas[3 * i + j]);
canvas.drawCircle(0, 0, radius, paint);
canvas.restore();
}
}
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
int[] durations={720, 1020, 1280, 1420, 1450, 1180, 870, 1450, 1060};
int[] delays= {-60, 250, -170, 480, 310, 30, 460, 780, 450};
for (int i = 0; i < 9; i++) {
final int index=i;
ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.5f,1);
scaleAnim.setDuration(durations[i]);
scaleAnim.setRepeatCount(-1);
scaleAnim.setStartDelay(delays[i]);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloats[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 210, 122, 255);
alphaAnim.setDuration(durations[i]);
alphaAnim.setRepeatCount(-1);
alphaAnim.setStartDelay(delays[i]);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
alphas[index] = (int) animation.getAnimatedValue();
postInvalidate();
}
});
alphaAnim.start();
animators.add(scaleAnim);
animators.add(alphaAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,68 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/16.
*/
public class BallPulseIndicator extends BaseIndicatorController{
public static final float SCALE=1.0f;
//scale x ,y
private float[] scaleFloats=new float[]{SCALE,
SCALE,
SCALE};
@Override
public void draw(Canvas canvas, Paint paint) {
float circleSpacing=4;
float radius=(Math.min(getWidth(),getHeight())-circleSpacing*2)/6;
float x = getWidth()/ 2-(radius*2+circleSpacing);
float y=getHeight() / 2;
for (int i = 0; i < 3; i++) {
canvas.save();
float translateX=x+(radius*2)*i+circleSpacing*i;
canvas.translate(translateX, y);
canvas.scale(scaleFloats[i], scaleFloats[i]);
canvas.drawCircle(0, 0, radius, paint);
canvas.restore();
}
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
int[] delays=new int[]{120,240,360};
for (int i = 0; i < 3; i++) {
final int index=i;
ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.3f,1);
scaleAnim.setDuration(750);
scaleAnim.setRepeatCount(-1);
scaleAnim.setStartDelay(delays[i]);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloats[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
animators.add(scaleAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,41 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/17.
*/
public class BallPulseRiseIndicator extends BaseIndicatorController{
@Override
public void draw(Canvas canvas, Paint paint) {
float radius=getWidth()/10;
canvas.drawCircle(getWidth()/4,radius*2,radius,paint);
canvas.drawCircle(getWidth()*3/4,radius*2,radius,paint);
canvas.drawCircle(radius,getHeight()-2*radius,radius,paint);
canvas.drawCircle(getWidth()/2,getHeight()-2*radius,radius,paint);
canvas.drawCircle(getWidth()-radius,getHeight()-2*radius,radius,paint);
}
@Override
public List<Animator> createAnimation() {
PropertyValuesHolder rotation6=PropertyValuesHolder.ofFloat("rotationX",0,360);
ObjectAnimator animator=ObjectAnimator.ofPropertyValuesHolder(getTarget(), rotation6);
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(-1);
animator.setDuration(1500);
animator.start();
List<Animator> animators=new ArrayList<>();
animators.add(animator);
return animators;
}
}

View File

@@ -0,0 +1,57 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class BallPulseSyncIndicator extends BaseIndicatorController {
float[] translateYFloats=new float[3];
@Override
public void draw(Canvas canvas, Paint paint) {
float circleSpacing=4;
float radius=(getWidth()-circleSpacing*2)/6;
float x = getWidth()/ 2-(radius*2+circleSpacing);
for (int i = 0; i < 3; i++) {
canvas.save();
float translateX=x+(radius*2)*i+circleSpacing*i;
canvas.translate(translateX, translateYFloats[i]);
canvas.drawCircle(0, 0, radius, paint);
canvas.restore();
}
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
float circleSpacing=4;
float radius=(getWidth()-circleSpacing*2)/6;
int[] delays=new int[]{70,140,210};
for (int i = 0; i < 3; i++) {
final int index=i;
ValueAnimator scaleAnim=ValueAnimator.ofFloat(getHeight()/2,getHeight()/2-radius*2,getHeight()/2);
scaleAnim.setDuration(600);
scaleAnim.setRepeatCount(-1);
scaleAnim.setStartDelay(delays[i]);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
translateYFloats[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
animators.add(scaleAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,71 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/17.
*/
public class BallRotateIndicator extends BaseIndicatorController{
float scaleFloat=0.5f;
@Override
public void draw(Canvas canvas, Paint paint) {
float radius=getWidth()/10;
float x = getWidth()/ 2;
float y=getHeight()/2;
canvas.save();
canvas.translate(x - radius * 2 - radius, y);
canvas.scale(scaleFloat, scaleFloat);
canvas.drawCircle(0, 0, radius, paint);
canvas.restore();
canvas.save();
canvas.translate(x, y);
canvas.scale(scaleFloat, scaleFloat);
canvas.drawCircle(0, 0, radius, paint);
canvas.restore();
canvas.save();
canvas.translate(x + radius * 2 + radius, y);
canvas.scale(scaleFloat, scaleFloat);
canvas.drawCircle(0,0,radius, paint);
canvas.restore();
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
ValueAnimator scaleAnim=ValueAnimator.ofFloat(0.5f,1,0.5f);
scaleAnim.setDuration(1000);
scaleAnim.setRepeatCount(-1);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloat = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
ObjectAnimator rotateAnim=ObjectAnimator.ofFloat(getTarget(),"rotation",0,180,360);
rotateAnim.setDuration(1000);
rotateAnim.setRepeatCount(-1);
rotateAnim.start();
animators.add(scaleAnim);
animators.add(rotateAnim);
return animators;
}
}

View File

@@ -0,0 +1,63 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class BallScaleIndicator extends BaseIndicatorController {
float scale=1;
int alpha=255;
@Override
public void draw(Canvas canvas, Paint paint) {
float circleSpacing=4;
paint.setAlpha(alpha);
canvas.scale(scale,scale,getWidth()/2,getHeight()/2);
paint.setAlpha(alpha);
canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2-circleSpacing,paint);
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1);
scaleAnim.setInterpolator(new LinearInterpolator());
scaleAnim.setDuration(1000);
scaleAnim.setRepeatCount(-1);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scale = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 0);
alphaAnim.setInterpolator(new LinearInterpolator());
alphaAnim.setDuration(1000);
alphaAnim.setRepeatCount(-1);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
alpha = (int) animation.getAnimatedValue();
postInvalidate();
}
});
alphaAnim.start();
animators.add(scaleAnim);
animators.add(alphaAnim);
return animators;
}
}

View File

@@ -0,0 +1,70 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class BallScaleMultipleIndicator extends BaseIndicatorController {
float[] scaleFloats=new float[]{1,1,1};
int[] alphaInts=new int[]{255,255,255};
@Override
public void draw(Canvas canvas, Paint paint) {
float circleSpacing=4;
for (int i = 0; i < 3; i++) {
paint.setAlpha(alphaInts[i]);
canvas.scale(scaleFloats[i],scaleFloats[i],getWidth()/2,getHeight()/2);
canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2-circleSpacing,paint);
}
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
long[] delays=new long[]{0, 200, 400};
for (int i = 0; i < 3; i++) {
final int index=i;
ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1);
scaleAnim.setInterpolator(new LinearInterpolator());
scaleAnim.setDuration(1000);
scaleAnim.setRepeatCount(-1);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloats[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.setStartDelay(delays[i]);
scaleAnim.start();
ValueAnimator alphaAnim=ValueAnimator.ofInt(255,0);
alphaAnim.setInterpolator(new LinearInterpolator());
alphaAnim.setDuration(1000);
alphaAnim.setRepeatCount(-1);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
alphaInts[index] = (int) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.setStartDelay(delays[i]);
alphaAnim.start();
animators.add(scaleAnim);
animators.add(alphaAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,59 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class BallScaleRippleIndicator extends BallScaleIndicator {
@Override
public void draw(Canvas canvas, Paint paint) {
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
super.draw(canvas, paint);
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1);
scaleAnim.setInterpolator(new LinearInterpolator());
scaleAnim.setDuration(1000);
scaleAnim.setRepeatCount(-1);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scale = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
ValueAnimator alphaAnim=ValueAnimator.ofInt(0, 255);
alphaAnim.setInterpolator(new LinearInterpolator());
alphaAnim.setDuration(1000);
alphaAnim.setRepeatCount(-1);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
alpha = (int) animation.getAnimatedValue();
postInvalidate();
}
});
alphaAnim.start();
animators.add(scaleAnim);
animators.add(alphaAnim);
return animators;
}
}

View File

@@ -0,0 +1,65 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class BallScaleRippleMultipleIndicator extends BallScaleMultipleIndicator{
@Override
public void draw(Canvas canvas, Paint paint) {
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
super.draw(canvas, paint);
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
long[] delays=new long[]{0, 200, 400};
for (int i = 0; i < 3; i++) {
final int index=i;
ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1);
scaleAnim.setInterpolator(new LinearInterpolator());
scaleAnim.setDuration(1000);
scaleAnim.setRepeatCount(-1);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloats[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.setStartDelay(delays[i]);
scaleAnim.start();
ValueAnimator alphaAnim=ValueAnimator.ofInt(0,255);
scaleAnim.setInterpolator(new LinearInterpolator());
alphaAnim.setDuration(1000);
alphaAnim.setRepeatCount(-1);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
alphaInts[index] = (int) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.setStartDelay(delays[i]);
alphaAnim.start();
animators.add(scaleAnim);
animators.add(alphaAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,116 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/20.
*/
public class BallSpinFadeLoaderIndicator extends BaseIndicatorController {
public static final float SCALE=1.0f;
public static final int ALPHA=255;
float[] scaleFloats=new float[]{SCALE,
SCALE,
SCALE,
SCALE,
SCALE,
SCALE,
SCALE,
SCALE};
int[] alphas=new int[]{ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA,
ALPHA};
@Override
public void draw(Canvas canvas, Paint paint) {
float radius=getWidth()/10;
for (int i = 0; i < 8; i++) {
canvas.save();
Point point=circleAt(getWidth(),getHeight(),getWidth()/2-radius,i*(Math.PI/4));
canvas.translate(point.x,point.y);
canvas.scale(scaleFloats[i],scaleFloats[i]);
paint.setAlpha(alphas[i]);
canvas.drawCircle(0,0,radius,paint);
canvas.restore();
}
}
/**
* 圆O的圆心为(a,b),半径为R,点A与到X轴的为角α.
*则点A的坐标为(a+R*cosα,b+R*sinα)
* @param width
* @param height
* @param radius
* @param angle
* @return
*/
Point circleAt(int width,int height,float radius,double angle){
float x= (float) (width/2+radius*(Math.cos(angle)));
float y= (float) (height/2+radius*(Math.sin(angle)));
return new Point(x,y);
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
int[] delays= {0, 120, 240, 360, 480, 600, 720, 780, 840};
for (int i = 0; i < 8; i++) {
final int index=i;
ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.4f,1);
scaleAnim.setDuration(1000);
scaleAnim.setRepeatCount(-1);
scaleAnim.setStartDelay(delays[i]);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloats[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 77, 255);
alphaAnim.setDuration(1000);
alphaAnim.setRepeatCount(-1);
alphaAnim.setStartDelay(delays[i]);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
alphas[index] = (int) animation.getAnimatedValue();
postInvalidate();
}
});
alphaAnim.start();
animators.add(scaleAnim);
animators.add(alphaAnim);
}
return animators;
}
final class Point{
public float x;
public float y;
public Point(float x, float y){
this.x=x;
this.y=y;
}
}
}

View File

@@ -0,0 +1,82 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class BallTrianglePathIndicator extends BaseIndicatorController {
float[] translateX=new float[3],translateY=new float[3];
@Override
public void draw(Canvas canvas, Paint paint) {
paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE);
for (int i = 0; i < 3; i++) {
canvas.save();
canvas.translate(translateX[i], translateY[i]);
canvas.drawCircle(0, 0, getWidth() / 10, paint);
canvas.restore();
}
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
float startX=getWidth()/5;
float startY=getWidth()/5;
for (int i = 0; i < 3; i++) {
final int index=i;
ValueAnimator translateXAnim=ValueAnimator.ofFloat(getWidth()/2,getWidth()-startX,startX,getWidth()/2);
if (i==1){
translateXAnim=ValueAnimator.ofFloat(getWidth()-startX,startX,getWidth()/2,getWidth()-startX);
}else if (i==2){
translateXAnim=ValueAnimator.ofFloat(startX,getWidth()/2,getWidth()-startX,startX);
}
ValueAnimator translateYAnim=ValueAnimator.ofFloat(startY,getHeight()-startY,getHeight()-startY,startY);
if (i==1){
translateYAnim=ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,startY,getHeight()-startY);
}else if (i==2){
translateYAnim=ValueAnimator.ofFloat(getHeight()-startY,startY,getHeight()-startY,getHeight()-startY);
}
translateXAnim.setDuration(2000);
translateXAnim.setInterpolator(new LinearInterpolator());
translateXAnim.setRepeatCount(-1);
translateXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
translateX [index]= (float) animation.getAnimatedValue();
postInvalidate();
}
});
translateXAnim.start();
translateYAnim.setDuration(2000);
translateYAnim.setInterpolator(new LinearInterpolator());
translateYAnim.setRepeatCount(-1);
translateYAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
translateY [index]= (float) animation.getAnimatedValue();
postInvalidate();
}
});
translateYAnim.start();
animators.add(translateXAnim);
animators.add(translateYAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,64 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class BallZigZagDeflectIndicator extends BallZigZagIndicator {
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
float startX=getWidth()/6;
float startY=getWidth()/6;
for (int i = 0; i < 2; i++) {
final int index=i;
ValueAnimator translateXAnim=ValueAnimator.ofFloat(startX,getWidth()-startX,startX,getWidth()-startX,startX);
if (i==1){
translateXAnim=ValueAnimator.ofFloat(getWidth()-startX,startX,getWidth()-startX,startX,getWidth()-startX);
}
ValueAnimator translateYAnim=ValueAnimator.ofFloat(startY,startY,getHeight()-startY,getHeight()-startY,startY);
if (i==1){
translateYAnim=ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,startY,startY,getHeight()-startY);
}
translateXAnim.setDuration(2000);
translateXAnim.setInterpolator(new LinearInterpolator());
translateXAnim.setRepeatCount(-1);
translateXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
translateX [index]= (float) animation.getAnimatedValue();
postInvalidate();
}
});
translateXAnim.start();
translateYAnim.setDuration(2000);
translateYAnim.setInterpolator(new LinearInterpolator());
translateYAnim.setRepeatCount(-1);
translateYAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
translateY [index]= (float) animation.getAnimatedValue();
postInvalidate();
}
});
translateYAnim.start();
animators.add(translateXAnim);
animators.add(translateYAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,75 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class BallZigZagIndicator extends BaseIndicatorController {
float[] translateX=new float[2],translateY=new float[2];
@Override
public void draw(Canvas canvas, Paint paint) {
for (int i = 0; i < 2; i++) {
canvas.save();
canvas.translate(translateX[i], translateY[i]);
canvas.drawCircle(0, 0, getWidth() / 10, paint);
canvas.restore();
}
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
float startX=getWidth()/6;
float startY=getWidth()/6;
for (int i = 0; i < 2; i++) {
final int index=i;
ValueAnimator translateXAnim=ValueAnimator.ofFloat(startX,getWidth()-startX,getWidth()/2,startX);
if (i==1){
translateXAnim=ValueAnimator.ofFloat(getWidth()-startX,startX,getWidth()/2,getWidth()-startX);
}
ValueAnimator translateYAnim=ValueAnimator.ofFloat(startY,startY,getHeight()/2,startY);
if (i==1){
translateYAnim=ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,getHeight()/2,getHeight()-startY);
}
translateXAnim.setDuration(1000);
translateXAnim.setInterpolator(new LinearInterpolator());
translateXAnim.setRepeatCount(-1);
translateXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
translateX[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
translateXAnim.start();
translateYAnim.setDuration(1000);
translateYAnim.setInterpolator(new LinearInterpolator());
translateYAnim.setRepeatCount(-1);
translateYAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
translateY[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
translateYAnim.start();
animators.add(translateXAnim);
animators.add(translateYAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,99 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
import java.util.List;
/**
* Created by Jack on 2015/10/15.
*/
public abstract class BaseIndicatorController {
private View mTarget;
private List<Animator> mAnimators;
public void setTarget(View target){
this.mTarget=target;
}
public View getTarget(){
return mTarget;
}
public int getWidth(){
return mTarget.getWidth();
}
public int getHeight(){
return mTarget.getHeight();
}
public void postInvalidate(){
mTarget.postInvalidate();
}
/**
* draw indicator
* @param canvas
* @param paint
*/
public abstract void draw(Canvas canvas,Paint paint);
/**
* create animation or animations
*/
public abstract List<Animator> createAnimation();
public void initAnimation(){
mAnimators=createAnimation();
}
/**
* make animation to start or end when target
* view was be Visible or Gone or Invisible.
* make animation to cancel when target view
* be onDetachedFromWindow.
* @param animStatus
*/
public void setAnimationStatus(AnimStatus animStatus){
if (mAnimators==null){
return;
}
int count=mAnimators.size();
for (int i = 0; i < count; i++) {
Animator animator=mAnimators.get(i);
boolean isRunning=animator.isRunning();
switch (animStatus){
case START:
if (!isRunning){
animator.start();
}
break;
case END:
if (isRunning){
animator.end();
}
break;
case CANCEL:
if (isRunning){
animator.cancel();
}
break;
}
}
}
public enum AnimStatus{
START,END,CANCEL
}
}

View File

@@ -0,0 +1,110 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/18.
*/
public class CubeTransitionIndicator extends BaseIndicatorController {
float[] translateX=new float[2],translateY=new float[2];
float degrees,scaleFloat=1.0f;
@Override
public void draw(Canvas canvas, Paint paint) {
float rWidth=getWidth()/5;
float rHeight=getHeight()/5;
for (int i = 0; i < 2; i++) {
canvas.save();
canvas.translate(translateX[i], translateY[i]);
canvas.rotate(degrees);
canvas.scale(scaleFloat,scaleFloat);
RectF rectF=new RectF(-rWidth/2,-rHeight/2,rWidth/2,rHeight/2);
canvas.drawRect(rectF,paint);
canvas.restore();
}
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
float startX=getWidth()/5;
float startY=getHeight()/5;
for (int i = 0; i < 2; i++) {
final int index=i;
translateX[index]=startX;
ValueAnimator translationXAnim=ValueAnimator.ofFloat(startX,getWidth()-startX,getWidth()-startX, startX,startX);
if (i==1){
translationXAnim=ValueAnimator.ofFloat(getWidth()-startX,startX,startX, getWidth()-startX,getWidth()-startX);
}
translationXAnim.setInterpolator(new LinearInterpolator());
translationXAnim.setDuration(1600);
translationXAnim.setRepeatCount(-1);
translationXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
translateX[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
translationXAnim.start();
translateY[index]=startY;
ValueAnimator translationYAnim=ValueAnimator.ofFloat(startY,startY,getHeight()-startY,getHeight()- startY,startY);
if (i==1){
translationYAnim=ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,startY,startY,getHeight()-startY);
}
translationYAnim.setDuration(1600);
translationYAnim.setInterpolator(new LinearInterpolator());
translationYAnim.setRepeatCount(-1);
translationYAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
translateY[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
translationYAnim.start();
animators.add(translationXAnim);
animators.add(translationYAnim);
}
ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.5f,1,0.5f,1);
scaleAnim.setDuration(1600);
scaleAnim.setInterpolator(new LinearInterpolator());
scaleAnim.setRepeatCount(-1);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloat = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
ValueAnimator rotateAnim=ValueAnimator.ofFloat(0,180,360,1.5f*360,2*360);
rotateAnim.setDuration(1600);
rotateAnim.setInterpolator(new LinearInterpolator());
rotateAnim.setRepeatCount(-1);
rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
degrees = (float) animation.getAnimatedValue();
postInvalidate();
}
});
rotateAnim.start();
animators.add(scaleAnim);
animators.add(rotateAnim);
return animators;
}
}

View File

@@ -0,0 +1,62 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class LineScaleIndicator extends BaseIndicatorController {
public static final float SCALE=1.0f;
float[] scaleYFloats=new float[]{SCALE,
SCALE,
SCALE,
SCALE,
SCALE,};
@Override
public void draw(Canvas canvas, Paint paint) {
float translateX=getWidth()/11;
float translateY=getHeight()/2;
for (int i = 0; i < 5; i++) {
canvas.save();
canvas.translate((2 + i * 2) * translateX - translateX / 2, translateY);
canvas.scale(SCALE, scaleYFloats[i]);
RectF rectF=new RectF(-translateX/2,-getHeight()/2.5f,translateX/2,getHeight()/2.5f);
canvas.drawRoundRect(rectF, 5, 5, paint);
canvas.restore();
}
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
long[] delays=new long[]{100,200,300,400,500};
for (int i = 0; i < 5; i++) {
final int index=i;
ValueAnimator scaleAnim=ValueAnimator.ofFloat(1, 0.4f, 1);
scaleAnim.setDuration(1000);
scaleAnim.setRepeatCount(-1);
scaleAnim.setStartDelay(delays[i]);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleYFloats[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
animators.add(scaleAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,64 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class LineScalePartyIndicator extends BaseIndicatorController {
public static final float SCALE=1.0f;
float[] scaleFloats=new float[]{SCALE,
SCALE,
SCALE,
SCALE,
SCALE,};
@Override
public void draw(Canvas canvas, Paint paint) {
float translateX=getWidth()/9;
float translateY=getHeight()/2;
for (int i = 0; i < 4; i++) {
canvas.save();
canvas.translate((2 + i * 2) * translateX - translateX / 2, translateY);
canvas.scale(scaleFloats[i], scaleFloats[i]);
RectF rectF=new RectF(-translateX/2,-getHeight()/2.5f,translateX/2,getHeight()/2.5f);
canvas.drawRoundRect(rectF,5,5,paint);
canvas.restore();
}
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
long[] durations=new long[]{1260, 430, 1010, 730};
long[] delays=new long[]{770, 290, 280, 740};
for (int i = 0; i < 4; i++) {
final int index=i;
ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.4f,1);
scaleAnim.setDuration(durations[i]);
scaleAnim.setRepeatCount(-1);
scaleAnim.setStartDelay(delays[i]);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFloats[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
animators.add(scaleAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,37 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class LineScalePulseOutIndicator extends LineScaleIndicator {
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
long[] delays=new long[]{500,250,0,250,500};
for (int i = 0; i < 5; i++) {
final int index=i;
ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.3f,1);
scaleAnim.setDuration(900);
scaleAnim.setRepeatCount(-1);
scaleAnim.setStartDelay(delays[i]);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleYFloats[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
animators.add(scaleAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,37 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/19.
*/
public class LineScalePulseOutRapidIndicator extends LineScaleIndicator {
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
long[] delays=new long[]{400,200,0,200,400};
for (int i = 0; i < 5; i++) {
final int index=i;
ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.4f,1);
scaleAnim.setDuration(1000);
scaleAnim.setRepeatCount(-1);
scaleAnim.setStartDelay(delays[i]);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleYFloats[index] = (float) animation.getAnimatedValue();
postInvalidate();
}
});
scaleAnim.start();
animators.add(scaleAnim);
}
return animators;
}
}

View File

@@ -0,0 +1,30 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
/**
* Created by Jack on 2015/10/24.
* Email:81813780@qq.com
*/
public class LineSpinFadeLoaderIndicator extends BallSpinFadeLoaderIndicator {
@Override
public void draw(Canvas canvas, Paint paint) {
float radius=getWidth()/10;
for (int i = 0; i < 8; i++) {
canvas.save();
Point point=circleAt(getWidth(),getHeight(),getWidth()/2.5f-radius,i*(Math.PI/4));
canvas.translate(point.x, point.y);
canvas.scale(scaleFloats[i], scaleFloats[i]);
canvas.rotate(i*45);
paint.setAlpha(alphas[i]);
RectF rectF=new RectF(-radius,-radius/1.5f,1.5f*radius,radius/1.5f);
canvas.drawRoundRect(rectF,5,5,paint);
canvas.restore();
}
}
}

View File

@@ -0,0 +1,119 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/16.
*/
public class PacmanIndicator extends BaseIndicatorController{
private float translateX;
private int alpha;
private float degrees1,degrees2;
@Override
public void draw(Canvas canvas, Paint paint) {
drawPacman(canvas,paint);
drawCircle(canvas,paint);
}
private void drawPacman(Canvas canvas,Paint paint){
float x=getWidth()/2;
float y=getHeight()/2;
canvas.save();
canvas.translate(x, y);
canvas.rotate(degrees1);
paint.setAlpha(255);
RectF rectF1=new RectF(-x/1.7f,-y/1.7f,x/1.7f,y/1.7f);
canvas.drawArc(rectF1, 0, 270, true, paint);
canvas.restore();
canvas.save();
canvas.translate(x, y);
canvas.rotate(degrees2);
paint.setAlpha(255);
RectF rectF2=new RectF(-x/1.7f,-y/1.7f,x/1.7f,y/1.7f);
canvas.drawArc(rectF2,90,270,true,paint);
canvas.restore();
}
private void drawCircle(Canvas canvas, Paint paint) {
float radius=getWidth()/11;
paint.setAlpha(alpha);
canvas.drawCircle(translateX, getHeight() / 2, radius, paint);
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
float startT=getWidth()/11;
ValueAnimator translationAnim=ValueAnimator.ofFloat(getWidth()-startT,getWidth()/2);
translationAnim.setDuration(650);
translationAnim.setInterpolator(new LinearInterpolator());
translationAnim.setRepeatCount(-1);
translationAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
translateX = (float) animation.getAnimatedValue();
postInvalidate();
}
});
translationAnim.start();
ValueAnimator alphaAnim=ValueAnimator.ofInt(255,122);
alphaAnim.setDuration(650);
alphaAnim.setRepeatCount(-1);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
alpha = (int) animation.getAnimatedValue();
postInvalidate();
}
});
alphaAnim.start();
ValueAnimator rotateAnim1=ValueAnimator.ofFloat(0, 45, 0);
rotateAnim1.setDuration(650);
rotateAnim1.setRepeatCount(-1);
rotateAnim1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
degrees1 = (float) animation.getAnimatedValue();
postInvalidate();
}
});
rotateAnim1.start();
ValueAnimator rotateAnim2=ValueAnimator.ofFloat(0,-45,0);
rotateAnim2.setDuration(650);
rotateAnim2.setRepeatCount(-1);
rotateAnim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
degrees2 = (float) animation.getAnimatedValue();
postInvalidate();
}
});
rotateAnim2.start();
animators.add(translationAnim);
animators.add(alphaAnim);
animators.add(rotateAnim1);
animators.add(rotateAnim2);
return animators;
}
}

View File

@@ -0,0 +1,36 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/20.
*/
public class SemiCircleSpinIndicator extends BaseIndicatorController {
@Override
public void draw(Canvas canvas, Paint paint) {
RectF rectF=new RectF(0,0,getWidth(),getHeight());
canvas.drawArc(rectF,-60,120,false,paint);
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
ObjectAnimator rotateAnim=ObjectAnimator.ofFloat(getTarget(),"rotation",0,180,360);
rotateAnim.setDuration(600);
rotateAnim.setRepeatCount(-1);
rotateAnim.start();
animators.add(rotateAnim);
return animators;
}
}

View File

@@ -0,0 +1,37 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/16.
*/
public class SquareSpinIndicator extends BaseIndicatorController {
@Override
public void draw(Canvas canvas, Paint paint) {
canvas.drawRect(new RectF(getWidth()/5,getHeight()/5,getWidth()*4/5,getHeight()*4/5),paint);
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
PropertyValuesHolder rotation5=PropertyValuesHolder.ofFloat("rotationX",0,180,180,0,0);
PropertyValuesHolder rotation6=PropertyValuesHolder.ofFloat("rotationY",0,0,180,180,0);
ObjectAnimator animator=ObjectAnimator.ofPropertyValuesHolder(getTarget(), rotation6,rotation5);
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(-1);
animator.setDuration(2500);
animator.start();
animators.add(animator);
return animators;
}
}

View File

@@ -0,0 +1,45 @@
package com.rmondjone.xrecyclerview.progressindicator.indicator;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jack on 2015/10/20.
*/
public class TriangleSkewSpinIndicator extends BaseIndicatorController {
@Override
public void draw(Canvas canvas, Paint paint) {
Path path=new Path();
path.moveTo(getWidth()/5,getHeight()*4/5);
path.lineTo(getWidth()*4/5, getHeight()*4/5);
path.lineTo(getWidth()/2,getHeight()/5);
path.close();
canvas.drawPath(path, paint);
}
@Override
public List<Animator> createAnimation() {
List<Animator> animators=new ArrayList<>();
PropertyValuesHolder rotation5=PropertyValuesHolder.ofFloat("rotationX",0,180,180,0,0);
PropertyValuesHolder rotation6=PropertyValuesHolder.ofFloat("rotationY",0,0,180,180,0);
ObjectAnimator animator=ObjectAnimator.ofPropertyValuesHolder(getTarget(), rotation6,rotation5);
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(-1);
animator.setDuration(2500);
animator.start();
animators.add(animator);
return animators;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<animation-list android:oneshot="false"
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:duration="100" android:drawable="@drawable/loading_01" />
<item android:duration="100" android:drawable="@drawable/loading_02" />
<item android:duration="100" android:drawable="@drawable/loading_03" />
<item android:duration="100" android:drawable="@drawable/loading_04" />
<item android:duration="100" android:drawable="@drawable/loading_05" />
<item android:duration="100" android:drawable="@drawable/loading_06" />
<item android:duration="100" android:drawable="@drawable/loading_07" />
<item android:duration="100" android:drawable="@drawable/loading_08" />
<item android:duration="100" android:drawable="@drawable/loading_09" />
<item android:duration="100" android:drawable="@drawable/loading_10" />
<item android:duration="100" android:drawable="@drawable/loading_11" />
<item android:duration="100" android:drawable="@drawable/loading_12" />
</animation-list>

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate android:drawable="@drawable/ic_loading_rotate" android:pivotX="50.0%" android:pivotY="50.0%"
xmlns:android="http://schemas.android.com/apk/res/android" />

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="3dp">
<ProgressBar
android:id="@+id/listview_foot_progress"
android:layout_width="30dip"
android:layout_height="30dip"
/>
<TextView
android:id="@+id/listview_foot_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="加载中..."/>
</LinearLayout>

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="bottom" >
<RelativeLayout
android:id="@+id/listview_header_content"
android:layout_width="fill_parent"
android:layout_height="80dp"
android:paddingTop="10dip"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="100dip"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical"
android:id="@+id/listview_header_text">
<TextView
android:id="@+id/refresh_status_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/listview_header_hint_normal" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_marginTop="3dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/listview_header_last_time"
android:textSize="12sp" />
<TextView
android:id="@+id/last_refresh_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
<ImageView
android:id="@+id/listview_header_arrow"
android:layout_width="20dp"
android:layout_height="40dp"
android:layout_centerVertical="true"
android:layout_marginLeft="35dp"
android:layout_marginRight="10dp"
android:layout_toLeftOf="@id/listview_header_text"
android:src="@drawable/ic_pulltorefresh_arrow" />
<com.rmondjone.xrecyclerview.SimpleViewSwitcher
android:id="@+id/listview_header_progressbar"
android:layout_width="30dip"
android:layout_height="30dip"
android:layout_toLeftOf="@id/listview_header_text"
android:layout_centerVertical="true"
android:layout_marginLeft="40dp"
android:layout_marginRight="10dp"
android:visibility="invisible" />
</RelativeLayout>
</LinearLayout>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:id="@+id/lock_linearlayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_gravity="center"
android:gravity="center"
android:id="@+id/lock_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/lock_recyclerview"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="@color/light_gray"
android:visibility="gone"/>
<com.rmondjone.locktableview.CustomHorizontalScrollView
android:scrollbars="none"
android:id="@+id/lockScrollView_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>
</com.rmondjone.locktableview.CustomHorizontalScrollView>
</LinearLayout>

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/transparent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/lockHeadView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/table_head"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/lockHeadView_Text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/beijin" />
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="@color/transparent" />
<com.rmondjone.locktableview.CustomHorizontalScrollView
android:id="@+id/lockHeadView_ScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none">
</com.rmondjone.locktableview.CustomHorizontalScrollView>
</LinearLayout>
<LinearLayout
android:id="@+id/unLockHeadView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/table_head"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<com.rmondjone.locktableview.CustomHorizontalScrollView
android:id="@+id/unlockHeadView_ScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none">
</com.rmondjone.locktableview.CustomHorizontalScrollView>
</LinearLayout>
<com.rmondjone.xrecyclerview.XRecyclerView
android:id="@+id/table_scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.rmondjone.xrecyclerview.XRecyclerView>
</LinearLayout>

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/head_contentLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingTop="10dip"
android:paddingBottom="15dip">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="30dip"
android:layout_marginRight="20dip">
<ImageView
android:id="@+id/head_arrowImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_pulltorefresh_arrow" />
</FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="100dip"
android:layout_marginRight="10dip">
<ImageView
android:id="@+id/head_progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/progressbar"
android:visibility="gone"
/>
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/head_tipsTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/listview_header_hint_normal"
android:textColor="#000000"/>
<TextView
android:id="@+id/head_lastUpdatedTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="10sp" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:id="@+id/unlock_linearlayout"
android:gravity="center"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,10 @@
<resources>
<string name="listview_header_hint_normal">下拉刷新</string>
<string name="listview_header_hint_release">释放立即刷新</string>
<string name="listview_loading">正在加载...</string>
<string name="nomore_loading">数据已全部加载结束</string>
<string name="refreshing">正在刷新...</string>
<string name="refresh_done">刷新完成</string>
<string name="loading_done">加载完成</string>
<string name="listview_header_last_time">上次更新时间:</string>
</resources>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="AVLoadingIndicatorView">
<attr name="indicator">
<flag name="BallPulse" value="0"/>
<flag name="BallGridPulse" value="1"/>
<flag name="BallClipRotate" value="2"/>
<flag name="BallClipRotatePulse" value="3"/>
<flag name="SquareSpin" value="4"/>
<flag name="BallClipRotateMultiple" value="5"/>
<flag name="BallPulseRise" value="6"/>
<flag name="BallRotate" value="7"/>
<flag name="CubeTransition" value="8"/>
<flag name="BallZigZag" value="9"/>
<flag name="BallZigZagDeflect" value="10"/>
<flag name="BallTrianglePath" value="11"/>
<flag name="BallScale" value="12"/>
<flag name="LineScale" value="13"/>
<flag name="LineScaleParty" value="14"/>
<flag name="BallScaleMultiple" value="15"/>
<flag name="BallPulseSync" value="16"/>
<flag name="BallBeat" value="17"/>
<flag name="LineScalePulseOut" value="18"/>
<flag name="LineScalePulseOutRapid" value="19"/>
<flag name="BallScaleRipple" value="20"/>
<flag name="BallScaleRippleMultiple" value="21"/>
<flag name="BallSpinFadeLoader" value="22"/>
<flag name="LineSpinFadeLoader" value="23"/>
<flag name="TriangleSkewSpin" value="24"/>
<flag name="Pacman" value="25"/>
<flag name="BallGridBeat" value="26"/>
<flag name="SemiCircleSpin" value="27"/>
</attr>
<attr name="indicator_color" format="color"/>
</declare-styleable>
</resources>

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 颜色 -->
<color name="color_hei_8">#00000000</color>
<color name="forget_pwd">#334E6C</color>
<color name="table_head">#E5EFFE</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="light_gray">#e6e6e6</color>
<color name="light_gray2">#fafafa</color>
<color name="deep_gray">#555555</color>
<color name="deep_red">#FF0033</color>
<color name="light_yellow2">#ADD8E6</color>
<color name="border_color">#817F80</color>
<color name="blue">#0000ff</color>
<color name="transparent">#00000000</color>
<color name="green">#0F0</color>
<color name="red">#FF0000</color>
<color name="jt1">#DDDDDD</color>
<color name="first">#b8b8b8</color>
<color name="first_dianji">#0cb9f5</color>
<color name="beijin">#2c8fd3</color>
<color name="orange">#ffa500</color>
<color name="tv_textblackcolor">#000000</color>
<color name="calendar_background">#e3eef4</color>
<color name="selection">#b1dce2ff</color>
<color name="calendar_zhe_day">#faedda</color>
<color name="event_center">#ff6bd697</color>
<color name="noMonth">#c0c0c0</color>
<color name="text_6">#FFf3feff</color>
<color name="text_7">#FFfff1f2</color>
<color name="Text">#603b07</color>
<color name="lv_cacheColorHint">#00000000</color>
<color name="ll_background_10501">#31abfe</color>
<color name="list_item_click">#76c120</color>
<color name="white_bg_10531M">#ffffffff</color>
<color name="txtToDay">#EE4000</color>
<color name="green_bg_10531M">#fff2f9ec</color>
<color name="ll_graybg">#EDEDE4</color>
<color name="search_editbg">#E8E8E8</color>
<color name="text_color">#ff434343</color>
<color name="review_bac">#FAFAFA</color>
<color name="review_pep">#3C70A6</color>
<color name="review_time">#C3C4C9</color>
<color name="review_content">#262B31</color>
<color name="horizontal_divider">#CED7DF</color>
<color name="comment_text">#7B7B7B</color>
<color name="comment_text_bottom">#949494</color>
<color name="horizontal_toutiao">#1989E0</color>
<color name="tabtitle_color">#CFEDF9</color>
<color name="tabitem_color1">#FFFFFF</color>
<color name="tabitem_color2">#F7F8F9</color>
<color name="dashline_color">#C2C0C2</color>
</resources>

View File

@@ -0,0 +1,4 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="textandiconmargin">10dp</dimen>
</resources>

View File

@@ -0,0 +1,10 @@
<resources>
<string name="listview_header_hint_normal">pull to refresh</string>
<string name="listview_header_hint_release">release to start refresh</string>
<string name="listview_loading">loading...</string>
<string name="nomore_loading">no more to be loaded</string>
<string name="refreshing">refreshing...</string>
<string name="refresh_done">refresh done</string>
<string name="loading_done">loading done</string>
<string name="listview_header_last_time">last update</string>
</resources>

View File

@@ -67,6 +67,8 @@ dependencies {
implementation project(':moduletablayout')
implementation libs.activity
implementation libs.constraintlayout
api 'androidx.activity:activity-compose:1.8.2'
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core

Binary file not shown.

View File

@@ -4,6 +4,7 @@ import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static com.blankj.utilcode.util.ActivityUtils.startActivity;
import android.graphics.Color;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
@@ -128,7 +129,7 @@ public class CirleListAdapter extends BaseQuickAdapter<CircleListBean, BaseViewH
//头像
// ImageUtils.loadHeadCC(item.getAvatar(), helper.getView(R.id.dy_head_image));
MeHeadView headView = helper.getView(R.id.dy_head_image);
headView.setData(item.getAvatar(), "", item.getSex() + "");
headView.setData(item.getAvatar(), "", item.getNobility_image());
//动态内容以富文本展示
String content = item.getContent();
if (content == null || content.length() == 0) {

View File

@@ -16,6 +16,7 @@ import android.widget.TextView;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.hjq.toast.ToastUtils;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.bean.RoonGiftModel;
import com.xscm.moduleutil.event.RoomGiftClickToEvent;
@@ -26,6 +27,8 @@ import org.greenrobot.eventbus.EventBus;
import java.lang.ref.WeakReference;
import java.util.List;
import static android.view.View.GONE;
public class GiftRoomAdapter extends BaseAdapter {
private final List<RoonGiftModel> mDatas;
private final LayoutInflater inflater;
@@ -110,39 +113,6 @@ public class GiftRoomAdapter extends BaseAdapter {
this.mDatas.addAll(newData);
}
// private static class MyGestureDetector extends GestureDetector {
// private GiftRoomAdapter mAdapter;
// private RoonGiftModel mGiftModel;
//
// public MyGestureDetector(Context context) {
// super(context, new SimpleOnGestureListener() {
// @Override
// public boolean onSingleTapConfirmed(MotionEvent e) {
// if (mAdapter != null && mGiftModel != null) {
// EventBus.getDefault().post(new RoomGiftClickToEvent(mAdapter, mGiftModel, 1));
// }
// return true;
// }
//
// @Override
// public boolean onDoubleTap(MotionEvent e) {
// if (mAdapter != null && mGiftModel != null) {
// EventBus.getDefault().post(new RoomGiftClickToEvent(mAdapter, mGiftModel, 2));
// }
// return true;
// }
// });
// setOnDoubleTapListener(getListener());
// }
//
// public void setGiftModel(GiftRoomAdapter adapter, RoonGiftModel giftModel) {
// this.mAdapter = adapter;
// this.mGiftModel = giftModel;
// }
// }
@Override
@SuppressLint({"SetTextI18n", "ClickableViewAccessibility"})
public View getView(int position, View convertView, ViewGroup parent) {
@@ -157,7 +127,7 @@ public class GiftRoomAdapter extends BaseAdapter {
viewHolder.item_layout = (ConstraintLayout) convertView.findViewById(R.id.cl_gift);
viewHolder.ivDownOn = (ImageView) convertView.findViewById(R.id.iv_down_on);
viewHolder.cl_iv_down_on = (ConstraintLayout) convertView.findViewById(R.id.cl_iv_down_on);
viewHolder.iv_gift_select= (ImageView) convertView.findViewById(R.id.iv_gift_select);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
@@ -165,10 +135,18 @@ public class GiftRoomAdapter extends BaseAdapter {
viewHolder.item_layout.setOnClickListener(v -> {
// RoonGiftModel clickedModel = (RoonGiftModel) v.getTag();
if (giftModel.getIs_lock()==0) {
EventBus.getDefault().post(new RoomGiftClickToEvent(this, giftModel, 1));
}else if (giftModel.getIs_lock()==1){
ToastUtils.show("当前属于爵位礼物,请开通爵位");
}
});
if (giftModel.getIs_lock()==0){
viewHolder.iv_gift_select.setVisibility(GONE);
}else {
viewHolder.iv_gift_select.setVisibility(View.VISIBLE);
}
/*
* 在给View绑定显示的数据时计算正确的position = position + curIndex * pageSize
*/
@@ -193,9 +171,9 @@ public class GiftRoomAdapter extends BaseAdapter {
if (giftModel.isChecked()) {//被选中
viewHolder.cl_iv_down_on.setBackgroundResource(R.mipmap.room_gift_bjx);
viewHolder.ivDownOn.setVisibility(View.GONE);
viewHolder.ivDownOn.setVisibility(GONE);
} else {
viewHolder.ivDownOn.setVisibility(View.GONE);
viewHolder.ivDownOn.setVisibility(GONE);
viewHolder.cl_iv_down_on.setBackgroundResource(0);
}
//设置
@@ -234,6 +212,7 @@ public class GiftRoomAdapter extends BaseAdapter {
public ImageView iv_gift_pic;
public TextView tv_gift_change_love_values;
public ImageView ivDownOn;
public ImageView iv_gift_select;
public ConstraintLayout cl_iv_down_on;
}
}

View File

@@ -164,7 +164,6 @@ public class CommonAppContext extends MultiDexApplication implements Applicatio
// 全局设置字体不缩放
adjustFontScale(getResources().getConfiguration());
CrashHandler.init(this);
// if (currentEnvironment.getShelf()==1){
if (SpUtil.getShelf()!=0) {
SpUtil.setShelf(1);
@@ -798,7 +797,7 @@ public class CommonAppContext extends MultiDexApplication implements Applicatio
@Override
public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) {
ClassicsHeader header = new ClassicsHeader(context);
header.setDrawableSize(20);
header.setDrawableSize(10);
header.setFinishDuration(0);
return header;//.setTimeFormat(new DynamicTimeFormat("更新于 %s"));//指定为经典Header默认是 贝塞尔雷达Header
// return new CustomRefreshHeader(context);//.setTimeFormat(new DynamicTimeFormat("更新于 %s"));//指定为经典Header默认是 贝塞尔雷达Header
@@ -809,7 +808,7 @@ public class CommonAppContext extends MultiDexApplication implements Applicatio
@Override
public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) {
ClassicsFooter classicsFooter = new ClassicsFooter(context);
classicsFooter.setDrawableSize(20);
classicsFooter.setDrawableSize(10);
classicsFooter.setFinishDuration(0);
//指定为经典Footer默认是 BallPulseFooter
return classicsFooter;

View File

@@ -146,57 +146,9 @@ public class RoomManager {
return;
}
isUserOnline(context, roomId, password, roomInfo,taskId);
// fetchAndJoinRoom(context, roomId, password,taskId);
}
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// Thread.currentThread().interrupt();
// }
// 如果是当前房间且用户在线,直接跳转到房间页面,仅更新数据
// // 获取房间数据
// MessageListenerSingleton.getInstance().joinGroup(roomId);
// // 等待一段时间确保退出完成
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// Thread.currentThread().interrupt();
// }
// RetrofitClient.getInstance().roomGetIn(roomId, password, new BaseObserver<RoomInfoResp>() {
//
// @Override
// public void onSubscribe(Disposable d) {
// }
//
// @Override
// public void onNext(RoomInfoResp resp) {
// String appId = CommonAppContext.getInstance().getCurrentEnvironment().getSwSdkAppId();
// String token = resp.getUser_info().getAgora_token(); // 如果启用了鉴权才需要
// String roomId = resp.getRoom_info().getRoom_id(); // 房间 ID
// String rtm_token=resp.getUser_info().getAgora_rtm_token();
// SpUtil.setRtmToken(rtm_token);
// int uid = SpUtil.getUserId(); // 0 表示由 Agora 自动生成 UID
// boolean enableMic = false; // 是否开启麦克风
// boolean enableJs=false; // 是否开启角色
// if (resp.getUser_info().getPit_number()!=0){
// enableJs=true;
// }
// LogUtils.e("token",token);
// LogUtils.e("roomId:",roomId);
//// 初始化 Agora 并加入房间
// AgoraManager.getInstance(context)
// .joinRoom(token, roomId, uid, enableMic,enableJs);
// cacheRoomData(roomId, resp);
// navigateToRoom(context, roomId, password, resp);
// }
// });
// 临时实现 - 直接跳转(因为缺少具体的网络请求代码)
// navigateToRoom(context, roomId, password, null);
}
private void upInfo(Context context, String roomId, String password, boolean isOnline, RoomInfoResp roomInfo, boolean isCurrentRoom,String taskId) {
@@ -265,8 +217,6 @@ public class RoomManager {
.joinRoom(token, roomId, uid, enableMic, enableJs);
cacheRoomData(roomId, resp);
navigateToRoom(context, roomId, password, resp, false, taskId);
}else {
}
}

View File

@@ -31,6 +31,10 @@ public class CircleListBean {
private String share_url;
private List<HeatedBean> title;//话题列表
private String nobility_image;//贵族图标
private String nickname_color;//昵称颜色
private String mic_cycle;//麦圈
private String read_num;//阅读数
private List<LikeList> like_list;

View File

@@ -20,5 +20,6 @@ public class ExpandColumnBean {
private int room_id;//房间id,当有参数的时候,就显示跟随,当没有的时候,就显示私信控件
private String agree;
private List<String> icon;
private String nobility_image;//贵族图标
private String nickname_color;//昵称颜色
}

View File

@@ -25,4 +25,8 @@ public class MusicSongBean implements Serializable {
private String dress;
private String charm;
private int is_hot;//是否是主持并且是在9号麦位上
private String nobility_image;//贵族图标
private String nickname_color;//昵称颜色
private String mic_cycle;//麦圈
}

View File

@@ -0,0 +1,82 @@
package com.xscm.moduleutil.bean
/**
*com.xscm.moduleutil.bean
*qx
*2025/11/8
*
*/
class NobilitDeatils {
var nobility_power_list = ArrayList<nobilityPowerItem>()
var user_info: UserInfo? = null
var nobility_info: NobilityInfo? = null
class UserInfo {
/*"user_info": { // 用户信息
"id": 20034, //用户Id
"nickname": "奋斗的石头", //用户昵称
"avatar": "http://test.vespa.qxyushen.top/data/avatar/head_pic.png" //用户头像
}*/
var id: Int = 0
var nickname: String = ""
var avatar: String = ""
}
class NobilityInfo {
/*"nobility_info": { // 爵位信息
"status": 0, //状态: 0去开通 1去续费
"lid": 0, //爵位ID
"name": "", // 爵位名称
"image": "", //爵位图片
"end_time": 0 //结束时间
}*/
var status: Int = 0
var name: String = ""
var lid: Int = 0
var image: String = ""
var end_time: String = ""
}
class nobilityPowerItem {
/*"lid": 0, //爵位ID
"name": "特权", //爵位名称
"power_ids": "", //权限ID
"nick_name_color": "无", //昵称颜色
"nick_name_color_name": "无", //昵称颜色名称
"nobility_list": [
{
"id": 1, //权限ID
"name": "专属徽章", //权限名称
"image": "", //权限图片
"status": 0 //权限状态 0 不显示 1显示
},
{
"id": 2,
"name": "昵称颜色",
"image": "",
"status": 0
}
]*/
var lid: Int = 0
var name: String = ""
var power_ids: String = ""
var nick_name_color: String = ""
var nick_name_color_name: String = ""
var nobility_list = ArrayList<nobilityPowerItem>()
class nobilityPowerItem {
/*"id": 1, //权限ID
"name": "专属徽章", //权限名称
"image": "", //权限图片
"status": 0 //权限状态 0 不显示 1显示*/
var id: Int = 0
var name: String = ""
var image: String = ""
var status: Int = 0
}
}
}

View File

@@ -0,0 +1,51 @@
package com.xscm.moduleutil.bean
/**
*com.xscm.moduleutil.bean
*qx
*2025/11/10
*
*/
class NobilitList {
var name: String = ""
var image: String = ""
var pay_price: String = ""
var power: Power? = Power()
var lid: Int = 0
var day : Int = 0
class Power {
var power_count: Int = 0
var this_power_count: Int = 0
var count_str: String = ""
var list = ArrayList<PowerItem>()
class PowerItem {
var id: Int = 0
var name: String = ""
var content: String = ""
var image: String = ""
}
}
/* {
"name": "骑士",
"image": "https://cos.xscmmidi.site/admin/ScreenShot_2025-11-05_175044_144_17623369241246.png",
"pay_price": "388.00",
"power": {
"power_count": 12,
"this_power_count": 1,
"count_str": "12/1",
"list": [
{
"id": 1,
"name": "专属徽章",
"content": "专属动态爵位徽章",
"image": ""
}
]
}
},
*/
}

View File

@@ -0,0 +1,49 @@
package com.xscm.moduleutil.bean
/**
*com.xscm.moduleutil.bean
*qx
*2025/11/10
*
*/
class NobilityPrice {
var lid : Int = 0
var nobility_name : String = ""
var nobility_image : String = ""
var price : String = ""
var pay_price : String = ""
var day : Int = 0
var end_time : String = ""
var power_list = ArrayList<PowerItem>()
class PowerItem {
var id : Int = 0
var content : String = ""
}
/* "lid": 2,
"nobility_name": "男爵",
"nobility_image": "https://cos.xscmmidi.site/admin/ScreenShot_2025-11-05_175121_076_17623369074684.png",
"price": "588.00", //实付价格
"pay_price": "588.00", //画线价格
"day": 30,
"power_list": [
{
"id": 1,
"content": "专属动态爵位徽章"
},
{
"id": 2,
"content": "设置昵称颜色字体"
},
{
"id": 3,
"content": "特殊入场动画音效"
},
{
"id": 4,
"content": "入场专属座驾动画"
}
],
"end_time": "2025-12-10 10:19:20"*/
}

View File

@@ -33,6 +33,7 @@ public class RoonGiftModel {
private int num;//礼物数量
private int activities_id;//4盲盒 5天空之境
private int gift_bag;//10天空之境 11岁月之城 12时空之巅
private int is_lock;//爵位礼物 0不锁 1
public boolean isCan_send_self() {
if ( isManghe()) {
return true;

View File

@@ -0,0 +1,12 @@
package com.xscm.moduleutil.bean
/**
*com.xscm.moduleutil.bean
*qx
*2025/11/8
*
*/
class TableCellData {
var title: String = ""
var color: String = ""
}

View File

@@ -68,6 +68,15 @@ public class UserInfo implements Serializable {
private String red_num;
private String ta;
private String nobility_image;//贵族图标
private String nickname_color;//昵称颜色
private String mic_cycle;//麦圈
private String is_hide;//0不能设置1可以设置
private String hide_status;//0-取消隐身1-设置隐身
private String enter_image;//爵位飘屏的背景
private String enter_text;//爵位飘屏的文字
// @Data

View File

@@ -6,6 +6,7 @@ data class EmotionDeatils(
var type_id: Int? = 0,
var name: String? = "",
var image: String? = "",
var is_lock: Int? = 0,//0:未锁定 1:锁定
var animate_image : String? = "",
var children: List<Children>? =ArrayList (),
)
@@ -17,4 +18,5 @@ data class Children(
var name: String? = "",
var image: String? = "",
var animate_image : String? = "",
var is_lock: Int? = 0,//0:未锁定 1:锁定
)

View File

@@ -37,6 +37,9 @@ public class RoomAuction implements Serializable {
private String base_image;//礼物图片
private long duration;//时间
private String charm;
private String nobility_image;//贵族图标
private String nickname_color;//昵称颜色
private String mic_cycle;//麦圈
}
@Data

View File

@@ -5,6 +5,7 @@ import com.xscm.moduleutil.bean.MusicSongBean;
import java.io.Serializable;
import java.util.List;
import com.xscm.moduleutil.bean.NobilitDeatils;
import lombok.Data;
/**
@@ -31,6 +32,7 @@ public class RoomInfoResp implements Serializable {
private FriendInfo friend_info;
private GiftXlh gift_cycle;
private int hour_ranking_open;//1:开启 0关闭
private NobilitDeatils.NobilityInfo nobility_info;
//弹出麦位操作弹出

View File

@@ -65,4 +65,8 @@ public class RoomPitBean implements Serializable {
private int heartId; // "heartId": 4,
private int heartNum; // "heartNum": 10510
private String nobility_image;//贵族图标
private String nickname_color;//昵称颜色
private String mic_cycle;//麦圈
}

Some files were not shown because too many files have changed in this diff Show More