@ -0,0 +1,148 @@ |
|||||||
|
package cc.niushuai.didicheck.base.activity; |
||||||
|
|
||||||
|
import android.annotation.SuppressLint; |
||||||
|
import android.os.Build; |
||||||
|
import android.os.Bundle; |
||||||
|
import android.view.View; |
||||||
|
import android.view.Window; |
||||||
|
import android.view.WindowManager; |
||||||
|
|
||||||
|
import androidx.annotation.Nullable; |
||||||
|
import androidx.appcompat.app.AppCompatActivity; |
||||||
|
|
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
|
||||||
|
/** |
||||||
|
* 基类 |
||||||
|
* Created by huanghaibin on 2017/11/16. |
||||||
|
*/ |
||||||
|
|
||||||
|
public abstract class BaseActivity extends AppCompatActivity { |
||||||
|
|
||||||
|
private static boolean isMiUi = false; |
||||||
|
|
||||||
|
protected void initWindow() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
protected abstract int getLayoutId(); |
||||||
|
|
||||||
|
protected abstract void initView(); |
||||||
|
|
||||||
|
protected abstract void initData(); |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onCreate(@Nullable Bundle savedInstanceState) { |
||||||
|
super.onCreate(savedInstanceState); |
||||||
|
initWindow(); |
||||||
|
setContentView(getLayoutId()); |
||||||
|
initView(); |
||||||
|
initData(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 设置小米黑色状态栏字体 |
||||||
|
*/ |
||||||
|
@SuppressLint("PrivateApi") |
||||||
|
private void setMIUIStatusBarDarkMode() { |
||||||
|
if (isMiUi) { |
||||||
|
Class<? extends Window> clazz = getWindow().getClass(); |
||||||
|
try { |
||||||
|
int darkModeFlag; |
||||||
|
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams"); |
||||||
|
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE"); |
||||||
|
darkModeFlag = field.getInt(layoutParams); |
||||||
|
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class); |
||||||
|
extraFlagField.invoke(getWindow(), darkModeFlag, darkModeFlag); |
||||||
|
} catch (Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* 静态域,获取系统版本是否基于MIUI |
||||||
|
*/ |
||||||
|
|
||||||
|
static { |
||||||
|
try { |
||||||
|
@SuppressLint("PrivateApi") Class<?> sysClass = Class.forName("android.os.SystemProperties"); |
||||||
|
Method getStringMethod = sysClass.getDeclaredMethod("get", String.class); |
||||||
|
String version = (String) getStringMethod.invoke(sysClass, "ro.miui.ui.version.name"); |
||||||
|
isMiUi = version.compareTo("V6") >= 0 && Build.VERSION.SDK_INT < 24; |
||||||
|
} catch (Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 设置魅族手机状态栏图标颜色风格 |
||||||
|
* 可以用来判断是否为Flyme用户 |
||||||
|
* |
||||||
|
* @param window 需要设置的窗口 |
||||||
|
* @param dark 是否把状态栏字体及图标颜色设置为深色 |
||||||
|
* @return boolean 成功执行返回true |
||||||
|
*/ |
||||||
|
@SuppressWarnings("JavaReflectionMemberAccess") |
||||||
|
public static boolean setMeiZuDarkMode(Window window, boolean dark) { |
||||||
|
boolean result = false; |
||||||
|
if (Build.VERSION.SDK_INT >= 24) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (window != null) { |
||||||
|
try { |
||||||
|
WindowManager.LayoutParams lp = window.getAttributes(); |
||||||
|
Field darkFlag = WindowManager.LayoutParams.class |
||||||
|
.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON"); |
||||||
|
Field meizuFlags = WindowManager.LayoutParams.class |
||||||
|
.getDeclaredField("meizuFlags"); |
||||||
|
darkFlag.setAccessible(true); |
||||||
|
meizuFlags.setAccessible(true); |
||||||
|
int bit = darkFlag.getInt(null); |
||||||
|
int value = meizuFlags.getInt(lp); |
||||||
|
if (dark) { |
||||||
|
value |= bit; |
||||||
|
} else { |
||||||
|
value &= ~bit; |
||||||
|
} |
||||||
|
meizuFlags.setInt(lp, value); |
||||||
|
window.setAttributes(lp); |
||||||
|
result = true; |
||||||
|
} catch (Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressLint("InlinedApi") |
||||||
|
private int getStatusBarLightMode() { |
||||||
|
int result = 0; |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { |
||||||
|
if (isMiUi) { |
||||||
|
result = 1; |
||||||
|
} else if (setMeiZuDarkMode(getWindow(), true)) { |
||||||
|
result = 2; |
||||||
|
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
||||||
|
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); |
||||||
|
result = 3; |
||||||
|
} |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("InlinedApi") |
||||||
|
protected void setStatusBarDarkMode() { |
||||||
|
int type = getStatusBarLightMode(); |
||||||
|
if (type == 1) { |
||||||
|
setMIUIStatusBarDarkMode(); |
||||||
|
} else if (type == 2) { |
||||||
|
setMeiZuDarkMode(getWindow(), true); |
||||||
|
} else if (type == 3) { |
||||||
|
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,139 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com> |
||||||
|
* WebSite https://github.com/MiracleTimes-Dev
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package cc.niushuai.didicheck.base.adapter; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.view.LayoutInflater; |
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewGroup; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* 基本的适配器 |
||||||
|
*/ |
||||||
|
@SuppressWarnings("unused") |
||||||
|
public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter { |
||||||
|
|
||||||
|
protected LayoutInflater mInflater; |
||||||
|
protected List<T> mItems; |
||||||
|
private OnItemClickListener onItemClickListener; |
||||||
|
private OnClickListener onClickListener; |
||||||
|
|
||||||
|
public BaseRecyclerAdapter(Context context) { |
||||||
|
this.mItems = new ArrayList<>(); |
||||||
|
mInflater = LayoutInflater.from(context); |
||||||
|
onClickListener = new OnClickListener() { |
||||||
|
@Override |
||||||
|
public void onClick(int position, long itemId) { |
||||||
|
if (onItemClickListener != null) |
||||||
|
onItemClickListener.onItemClick(position, itemId); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { |
||||||
|
final RecyclerView.ViewHolder holder = onCreateDefaultViewHolder(parent, viewType); |
||||||
|
holder.itemView.setTag(holder); |
||||||
|
holder.itemView.setOnClickListener(onClickListener); |
||||||
|
return holder; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { |
||||||
|
onBindViewHolder(holder, mItems.get(position), position); |
||||||
|
} |
||||||
|
|
||||||
|
protected abstract RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type); |
||||||
|
|
||||||
|
protected abstract void onBindViewHolder(RecyclerView.ViewHolder holder, T item, int position); |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getItemCount() { |
||||||
|
return mItems.size(); |
||||||
|
} |
||||||
|
|
||||||
|
void setOnItemClickListener(OnItemClickListener onItemClickListener) { |
||||||
|
this.onItemClickListener = onItemClickListener; |
||||||
|
} |
||||||
|
|
||||||
|
void addAll(List<T> items) { |
||||||
|
if (items != null && items.size() > 0) { |
||||||
|
mItems.addAll(items); |
||||||
|
notifyItemRangeInserted(mItems.size(), items.size()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
final void addItem(T item) { |
||||||
|
if (item != null) { |
||||||
|
this.mItems.add(item); |
||||||
|
notifyItemChanged(mItems.size()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
final List<T> getItems() { |
||||||
|
return mItems; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
final T getItem(int position) { |
||||||
|
if (position < 0 || position >= mItems.size()) |
||||||
|
return null; |
||||||
|
return mItems.get(position); |
||||||
|
} |
||||||
|
|
||||||
|
static abstract class OnClickListener implements View.OnClickListener { |
||||||
|
@Override |
||||||
|
public void onClick(View v) { |
||||||
|
RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder) v.getTag(); |
||||||
|
onClick(holder.getAdapterPosition(), holder.getItemId()); |
||||||
|
} |
||||||
|
|
||||||
|
public abstract void onClick(int position, long itemId); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
interface OnItemClickListener { |
||||||
|
void onItemClick(int position, long itemId); |
||||||
|
} |
||||||
|
|
||||||
|
public final void removeItem(T item) { |
||||||
|
if (this.mItems.contains(item)) { |
||||||
|
int position = mItems.indexOf(item); |
||||||
|
this.mItems.remove(item); |
||||||
|
notifyItemRemoved(position); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected final void removeItem(int position) { |
||||||
|
if (this.getItemCount() > position) { |
||||||
|
this.mItems.remove(position); |
||||||
|
notifyItemRemoved(position); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected final void clear(){ |
||||||
|
mItems.clear(); |
||||||
|
notifyDataSetChanged(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
package cc.niushuai.didicheck.base.fragment; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.os.Bundle; |
||||||
|
import android.view.LayoutInflater; |
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewGroup; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.annotation.Nullable; |
||||||
|
import androidx.fragment.app.Fragment; |
||||||
|
|
||||||
|
|
||||||
|
public abstract class BaseFragment extends Fragment { |
||||||
|
protected View mRootView; |
||||||
|
protected LayoutInflater mInflater; |
||||||
|
protected Context mContext; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onAttach(Context context) { |
||||||
|
mContext = context; |
||||||
|
super.onAttach(context); |
||||||
|
} |
||||||
|
|
||||||
|
@Nullable |
||||||
|
@Override |
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { |
||||||
|
if (mRootView != null) { |
||||||
|
ViewGroup parent = (ViewGroup) mRootView.getParent(); |
||||||
|
if (parent != null) |
||||||
|
parent.removeView(mRootView); |
||||||
|
} else { |
||||||
|
mRootView = inflater.inflate(getLayoutId(), container, false); |
||||||
|
mInflater = inflater; |
||||||
|
initView(); |
||||||
|
initData(); |
||||||
|
} |
||||||
|
return mRootView; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onDetach() { |
||||||
|
mContext = null; |
||||||
|
super.onDetach(); |
||||||
|
} |
||||||
|
|
||||||
|
protected abstract int getLayoutId(); |
||||||
|
|
||||||
|
protected abstract void initView(); |
||||||
|
|
||||||
|
protected abstract void initData(); |
||||||
|
} |
@ -0,0 +1,95 @@ |
|||||||
|
package cc.niushuai.didicheck.base.fragment; |
||||||
|
|
||||||
|
import android.view.ViewGroup; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.fragment.app.Fragment; |
||||||
|
import androidx.fragment.app.FragmentManager; |
||||||
|
import androidx.fragment.app.FragmentPagerAdapter; |
||||||
|
import androidx.fragment.app.FragmentTransaction; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
@SuppressWarnings("unused") |
||||||
|
public class FragmentAdapter extends FragmentPagerAdapter { |
||||||
|
private List<Fragment> mFragment = new ArrayList<>(); |
||||||
|
private final FragmentManager mFragmentManager; |
||||||
|
private boolean mUpdateFlag; |
||||||
|
private Fragment mCurFragment; |
||||||
|
private String[] mTitles; |
||||||
|
|
||||||
|
public FragmentAdapter(FragmentManager fm) { |
||||||
|
super(fm); |
||||||
|
this.mFragmentManager = fm; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isUpdateFlag() { |
||||||
|
return mUpdateFlag; |
||||||
|
} |
||||||
|
|
||||||
|
public void setUpdateFlag(boolean mUpdateFlag) { |
||||||
|
this.mUpdateFlag = mUpdateFlag; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getItemPosition(@NonNull Object object) { |
||||||
|
return POSITION_NONE; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public Object instantiateItem(@NonNull ViewGroup container, int position) { |
||||||
|
if (mUpdateFlag) { |
||||||
|
Fragment fragment = (Fragment) super.instantiateItem(container, position); |
||||||
|
String tag = fragment.getTag(); |
||||||
|
FragmentTransaction transaction = mFragmentManager.beginTransaction(); |
||||||
|
transaction.remove(fragment); |
||||||
|
fragment = getItem(position); |
||||||
|
if (!fragment.isAdded()) { |
||||||
|
transaction.add(container.getId(), fragment, tag) |
||||||
|
.attach(fragment) |
||||||
|
.commitAllowingStateLoss(); |
||||||
|
} |
||||||
|
return fragment; |
||||||
|
} |
||||||
|
return super.instantiateItem(container, position); |
||||||
|
} |
||||||
|
|
||||||
|
public void reset(List<Fragment> fragments) { |
||||||
|
mFragment.clear(); |
||||||
|
mFragment.addAll(fragments); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) { |
||||||
|
super.setPrimaryItem(container, position, object); |
||||||
|
if (object instanceof Fragment) { |
||||||
|
mCurFragment = (Fragment) object; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Fragment getCurFragment() { |
||||||
|
return mCurFragment; |
||||||
|
} |
||||||
|
|
||||||
|
public void reset(String[] titles) { |
||||||
|
this.mTitles = titles; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Fragment getItem(int position) { |
||||||
|
return mFragment.get(position); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getCount() { |
||||||
|
return mFragment.size(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public CharSequence getPageTitle(int position) { |
||||||
|
return mTitles[position]; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,283 @@ |
|||||||
|
package cc.niushuai.didicheck.ui.group; |
||||||
|
|
||||||
|
import android.annotation.SuppressLint; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.Paint; |
||||||
|
import android.graphics.Rect; |
||||||
|
import android.text.TextUtils; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* 分组浮动的ItemDecoration |
||||||
|
* Created by haibin on 2017/5/15. |
||||||
|
*/ |
||||||
|
@SuppressWarnings("all") |
||||||
|
public class GroupItemDecoration<Group, Child> extends RecyclerView.ItemDecoration { |
||||||
|
protected int mGroupHeight; |
||||||
|
protected int mGroutBackground; |
||||||
|
protected Paint mBackgroundPaint; |
||||||
|
protected Paint mTextPaint; |
||||||
|
protected float mTextBaseLine; |
||||||
|
protected int mPaddingLeft, mPaddingRight; |
||||||
|
protected boolean isCenter; |
||||||
|
protected boolean isHasHeader; |
||||||
|
protected int mChildItemOffset; |
||||||
|
@SuppressLint("UseSparseArrays") |
||||||
|
protected Map<Integer, Group> mGroup = new HashMap<>(); |
||||||
|
|
||||||
|
public GroupItemDecoration() { |
||||||
|
super(); |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
private void init() { |
||||||
|
mBackgroundPaint = new Paint(); |
||||||
|
mBackgroundPaint.setColor(0xFFf5f7f8); |
||||||
|
mBackgroundPaint.setStyle(Paint.Style.FILL); |
||||||
|
mBackgroundPaint.setAntiAlias(true); |
||||||
|
|
||||||
|
mTextPaint = new Paint(); |
||||||
|
mTextPaint.setColor(0xFF353535); |
||||||
|
mTextPaint.setAntiAlias(true); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 先于RecyclerView的Item onDraw调用 |
||||||
|
* |
||||||
|
* @param c RecyclerView canvas |
||||||
|
* @param parent RecyclerView |
||||||
|
* @param state stare |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { |
||||||
|
super.onDraw(c, parent, state); |
||||||
|
onDrawGroup(c, parent); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 绘制分组Group |
||||||
|
* |
||||||
|
* @param c Canvas |
||||||
|
* @param parent RecyclerView |
||||||
|
*/ |
||||||
|
protected void onDrawGroup(Canvas c, RecyclerView parent) { |
||||||
|
int paddingLeft = parent.getPaddingLeft(); |
||||||
|
int right = parent.getWidth() - parent.getPaddingRight(); |
||||||
|
int top, bottom; |
||||||
|
int count = parent.getChildCount(); |
||||||
|
for (int i = 0; i < parent.getChildCount(); i++) { |
||||||
|
View child = parent.getChildAt(i); |
||||||
|
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); |
||||||
|
int key = params.getViewLayoutPosition(); |
||||||
|
if (mGroup.containsKey(key)) { |
||||||
|
top = child.getTop() - params.topMargin - mGroupHeight; |
||||||
|
bottom = top + mGroupHeight; |
||||||
|
c.drawRect(paddingLeft, top, right, bottom, mBackgroundPaint); |
||||||
|
String group = mGroup.get(params.getViewLayoutPosition()).toString(); |
||||||
|
float x; |
||||||
|
float y = top + mTextBaseLine; |
||||||
|
if (isCenter) { |
||||||
|
x = parent.getMeasuredWidth() / 2 - getTextX(group); |
||||||
|
} else { |
||||||
|
x = mPaddingLeft; |
||||||
|
} |
||||||
|
c.drawText(group, x, y, mTextPaint); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 后于RecyclerView的Item onDraw调用 |
||||||
|
* |
||||||
|
* @param c RecyclerView canvas |
||||||
|
* @param parent RecyclerView |
||||||
|
* @param state stare |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { |
||||||
|
super.onDrawOver(c, parent, state); |
||||||
|
onDrawOverGroup(c, parent); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 绘制悬浮组 |
||||||
|
* |
||||||
|
* @param c Canvas |
||||||
|
* @param parent RecyclerView |
||||||
|
*/ |
||||||
|
protected void onDrawOverGroup(Canvas c, RecyclerView parent) { |
||||||
|
int firstVisiblePosition = ((LinearLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition(); |
||||||
|
if (firstVisiblePosition == RecyclerView.NO_POSITION) { |
||||||
|
return; |
||||||
|
} |
||||||
|
Group group = getCroup(firstVisiblePosition); |
||||||
|
if (group == null) |
||||||
|
return; |
||||||
|
String groupTitle = group.toString(); |
||||||
|
if (TextUtils.isEmpty(groupTitle)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
boolean isRestore = false; |
||||||
|
Group nextGroup = getCroup(firstVisiblePosition + 1); |
||||||
|
if (nextGroup != null && !group.equals(nextGroup)) { |
||||||
|
//说明是当前组最后一个元素,但不一定碰撞了
|
||||||
|
View child = parent.findViewHolderForAdapterPosition(firstVisiblePosition).itemView; |
||||||
|
if (child.getTop() + child.getMeasuredHeight() < mGroupHeight) { |
||||||
|
//进一步检测碰撞
|
||||||
|
c.save();//保存画布当前的状态
|
||||||
|
isRestore = true; |
||||||
|
c.translate(0, child.getTop() + child.getMeasuredHeight() - mGroupHeight); |
||||||
|
} |
||||||
|
} |
||||||
|
int left = parent.getPaddingLeft(); |
||||||
|
int right = parent.getWidth() - parent.getPaddingRight(); |
||||||
|
int top = parent.getPaddingTop(); |
||||||
|
int bottom = top + mGroupHeight; |
||||||
|
c.drawRect(left, top, right, bottom, mBackgroundPaint); |
||||||
|
float x; |
||||||
|
float y = top + mTextBaseLine; |
||||||
|
if (isCenter) { |
||||||
|
x = parent.getMeasuredWidth() / 2 - getTextX(groupTitle); |
||||||
|
} else { |
||||||
|
x = mPaddingLeft; |
||||||
|
} |
||||||
|
c.drawText(groupTitle, x, y, mTextPaint); |
||||||
|
if (isRestore) { |
||||||
|
//还原画布为初始状态
|
||||||
|
c.restore(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 设置item的上下左右偏移量 |
||||||
|
* |
||||||
|
* @param outRect rect |
||||||
|
* @param view item |
||||||
|
* @param parent RecyclerView |
||||||
|
* @param state stare |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { |
||||||
|
super.getItemOffsets(outRect, view, parent, state); |
||||||
|
getItemOffsets(outRect, view, parent, parent.getChildViewHolder(view).getAdapterPosition()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 设置item的上下左右偏移量,不做任何处理就是默认状态 |
||||||
|
* |
||||||
|
* @param outRect outRect |
||||||
|
* @param view view |
||||||
|
* @param parent RecyclerView |
||||||
|
* @param adapterPosition position |
||||||
|
*/ |
||||||
|
protected void getItemOffsets(Rect outRect, View view, RecyclerView parent, int adapterPosition) { |
||||||
|
if (mGroup.containsKey(adapterPosition)) { |
||||||
|
outRect.set(0, mGroupHeight, 0, mGroup.containsKey(adapterPosition + 1) ? 0 : mChildItemOffset); |
||||||
|
} else { |
||||||
|
outRect.set(0, 0, 0, mGroup.containsKey(adapterPosition + 1) ? 0 : mChildItemOffset); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获得当前ViewPosition所在的组 |
||||||
|
* |
||||||
|
* @param position 当前View的position |
||||||
|
* @return 当前ViewPosition所在的组 |
||||||
|
*/ |
||||||
|
protected Group getCroup(int position) { |
||||||
|
while (position >= 0) { |
||||||
|
if (mGroup.containsKey(position)) { |
||||||
|
return mGroup.get(position); |
||||||
|
} |
||||||
|
position--; |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 通知更新分组信息 |
||||||
|
* |
||||||
|
* @param adapter GroupRecyclerAdapter |
||||||
|
*/ |
||||||
|
public void notifyDataSetChanged(GroupRecyclerAdapter<Group, Child> adapter) { |
||||||
|
mGroup.clear(); |
||||||
|
if (adapter == null) return; |
||||||
|
int key = 0; |
||||||
|
for (int i = 0; i < adapter.getGroupCount(); i++) { |
||||||
|
if (i == 0) { |
||||||
|
mGroup.put(isHasHeader ? 1 : 0, adapter.getGroup(i)); |
||||||
|
key += adapter.getChildCount(i) + (isHasHeader ? 1 : 0); |
||||||
|
; |
||||||
|
} else { |
||||||
|
mGroup.put(key, adapter.getGroup(i)); |
||||||
|
key += adapter.getChildCount(i); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void setChildItemOffset(int childItemOffset){ |
||||||
|
this.mChildItemOffset = childItemOffset; |
||||||
|
} |
||||||
|
|
||||||
|
public void setBackground(int groupBackground) { |
||||||
|
mBackgroundPaint.setColor(groupBackground); |
||||||
|
} |
||||||
|
|
||||||
|
public void setTextColor(int textColor) { |
||||||
|
mTextPaint.setColor(textColor); |
||||||
|
} |
||||||
|
|
||||||
|
public void setTextSize(float textSize) { |
||||||
|
mTextPaint.setTextSize(textSize); |
||||||
|
Paint.FontMetrics metrics = mTextPaint.getFontMetrics(); |
||||||
|
mTextBaseLine = mGroupHeight / 2 - metrics.descent + (metrics.bottom - metrics.top) / 2; |
||||||
|
} |
||||||
|
|
||||||
|
public void setGroupHeight(int groupHeight) { |
||||||
|
mGroupHeight = groupHeight; |
||||||
|
Paint.FontMetrics metrics = mTextPaint.getFontMetrics(); |
||||||
|
mTextBaseLine = mGroupHeight / 2 - metrics.descent + (metrics.bottom - metrics.top) / 2; |
||||||
|
} |
||||||
|
|
||||||
|
public void setPadding(int mPaddingLeft, int mPaddingRight) { |
||||||
|
this.mPaddingLeft = mPaddingLeft; |
||||||
|
this.mPaddingRight = mPaddingRight; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCenter(boolean isCenter) { |
||||||
|
this.isCenter = isCenter; |
||||||
|
} |
||||||
|
|
||||||
|
public void setHasHeader(boolean hasHeader) { |
||||||
|
isHasHeader = hasHeader; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取文本的x坐标起点 |
||||||
|
* |
||||||
|
* @param str 文本 |
||||||
|
* @return x |
||||||
|
*/ |
||||||
|
protected float getTextX(String str) { |
||||||
|
Rect bounds = new Rect(); |
||||||
|
mTextPaint.getTextBounds(str, 0, str.length(), bounds); |
||||||
|
return bounds.width() / 2; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取文本的长度像素 |
||||||
|
* @param str 文本 |
||||||
|
* @return px |
||||||
|
*/ |
||||||
|
protected float getTextLenghtPx(String str) { |
||||||
|
Rect bounds = new Rect(); |
||||||
|
mTextPaint.getTextBounds(str, 0, str.length(), bounds); |
||||||
|
return bounds.width(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,135 @@ |
|||||||
|
package cc.niushuai.didicheck.ui.group; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.LinkedHashMap; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import cc.niushuai.didicheck.base.adapter.BaseRecyclerAdapter; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 分组的RecyclerAdapter |
||||||
|
* Created by haibin on 2017/5/15. |
||||||
|
*/ |
||||||
|
@SuppressWarnings("unused") |
||||||
|
public abstract class GroupRecyclerAdapter<Parent, Child> extends BaseRecyclerAdapter<Child> { |
||||||
|
private LinkedHashMap<Parent, List<Child>> mGroups; |
||||||
|
private List<Parent> mGroupTitles; |
||||||
|
|
||||||
|
public GroupRecyclerAdapter(Context context) { |
||||||
|
super(context); |
||||||
|
mGroups = new LinkedHashMap<>(); |
||||||
|
mGroupTitles = new ArrayList<>(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 返回特定的标题 |
||||||
|
*/ |
||||||
|
Parent getGroup(int groupPosition) { |
||||||
|
return mGroupTitles.get(groupPosition); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获得分组的数量 |
||||||
|
* |
||||||
|
* @return 组的数量 |
||||||
|
*/ |
||||||
|
int getGroupCount() { |
||||||
|
return mGroupTitles.size(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取某一组的数量 |
||||||
|
* |
||||||
|
* @param groupPosition groupPosition |
||||||
|
* @return 某一组的数量 |
||||||
|
*/ |
||||||
|
int getChildCount(int groupPosition) { |
||||||
|
if (mGroupTitles == null || mGroups.size() == 0) |
||||||
|
return 0; |
||||||
|
if (mGroups.get(mGroupTitles.get(groupPosition)) == null) |
||||||
|
return 0; |
||||||
|
return mGroups.get(mGroupTitles.get(groupPosition)).size(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 重置分组数据 |
||||||
|
* |
||||||
|
* @param groups groups |
||||||
|
* @param titles titles |
||||||
|
*/ |
||||||
|
protected void resetGroups(LinkedHashMap<Parent, List<Child>> groups, List<Parent> titles) { |
||||||
|
if (groups == null || titles == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
mGroups.clear(); |
||||||
|
mGroupTitles.clear(); |
||||||
|
mGroups.putAll(groups); |
||||||
|
mGroupTitles.addAll(titles); |
||||||
|
mItems.clear(); |
||||||
|
for (Parent key : mGroups.keySet()) { |
||||||
|
mItems.addAll(mGroups.get(key)); |
||||||
|
} |
||||||
|
notifyDataSetChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 清除分组数据 |
||||||
|
*/ |
||||||
|
public final void clearGroup() { |
||||||
|
mGroupTitles.clear(); |
||||||
|
mGroups.clear(); |
||||||
|
clear(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 从分组移除数据 |
||||||
|
* |
||||||
|
* @param position 下标 |
||||||
|
* @return 分组是否为空,要移除分组 |
||||||
|
*/ |
||||||
|
public boolean removeGroupItem(int position) { |
||||||
|
int group = getGroupIndex(position); |
||||||
|
removeGroupChildren(group); |
||||||
|
int count = getChildCount(group); |
||||||
|
removeItem(position); |
||||||
|
if (count <= 0) { |
||||||
|
mGroupTitles.remove(group); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取所在分组 |
||||||
|
* |
||||||
|
* @param position 下标 |
||||||
|
* @return 获取所在分组 |
||||||
|
*/ |
||||||
|
private int getGroupIndex(int position) { |
||||||
|
int count = 0; |
||||||
|
if (position <= count) |
||||||
|
return 0; |
||||||
|
int i = 0; |
||||||
|
for (Parent parent : mGroups.keySet()) { |
||||||
|
count += mGroups.get(parent).size(); |
||||||
|
if (position < count) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
i++; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
private void removeGroupChildren(int groupPosition) { |
||||||
|
if (groupPosition >= mGroupTitles.size()) |
||||||
|
return; |
||||||
|
List<Child> childList = mGroups.get(mGroupTitles.get(groupPosition)); |
||||||
|
if (childList != null && childList.size() != 0) { |
||||||
|
childList.remove(childList.size() - 1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,92 @@ |
|||||||
|
package cc.niushuai.didicheck.ui.group; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.content.res.TypedArray; |
||||||
|
import android.util.AttributeSet; |
||||||
|
|
||||||
|
import androidx.annotation.Nullable; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
|
||||||
|
import cc.niushuai.didicheck.R; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 带分组浮动的RecyclerView |
||||||
|
* Created by haibin on 2017/5/15. |
||||||
|
*/ |
||||||
|
@SuppressWarnings("all") |
||||||
|
public class GroupRecyclerView extends RecyclerView { |
||||||
|
private GroupItemDecoration mItemDecoration; |
||||||
|
private int mGroupHeight; |
||||||
|
private int mGroutBackground, mTextColor; |
||||||
|
private int mTextSize; |
||||||
|
private int mPaddingLeft, mPaddingRight; |
||||||
|
private boolean isCenter; |
||||||
|
protected int mChildItemOffset; |
||||||
|
private boolean isHasHeader; |
||||||
|
private OnGroupChangeListener mListener; |
||||||
|
|
||||||
|
public GroupRecyclerView(Context context) { |
||||||
|
super(context); |
||||||
|
} |
||||||
|
|
||||||
|
public GroupRecyclerView(Context context, @Nullable AttributeSet attrs) { |
||||||
|
super(context, attrs); |
||||||
|
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.GroupRecyclerView); |
||||||
|
mTextSize = array.getDimensionPixelSize(R.styleable.GroupRecyclerView_group_text_size, 16); |
||||||
|
mGroupHeight = (int) array.getDimension(R.styleable.GroupRecyclerView_group_height, 52); |
||||||
|
mChildItemOffset = (int) array.getDimension(R.styleable.GroupRecyclerView_group_child_offset, 20); |
||||||
|
mTextColor = array.getColor(R.styleable.GroupRecyclerView_group_text_color, 0xFFFFFFFF); |
||||||
|
mGroutBackground = array.getColor(R.styleable.GroupRecyclerView_group_background, 0x80000000); |
||||||
|
isCenter = array.getBoolean(R.styleable.GroupRecyclerView_group_center, false); |
||||||
|
isHasHeader = array.getBoolean(R.styleable.GroupRecyclerView_group_has_header, true); |
||||||
|
mPaddingLeft = (int) array.getDimension(R.styleable.GroupRecyclerView_group_padding_left, 16); |
||||||
|
mPaddingRight = (int) array.getDimension(R.styleable.GroupRecyclerView_group_padding_right, 16); |
||||||
|
array.recycle(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void setAdapter(Adapter adapter) { |
||||||
|
if (adapter instanceof GroupRecyclerAdapter) { |
||||||
|
super.setAdapter(adapter); |
||||||
|
} else { |
||||||
|
throw new IllegalStateException("Adapter must instanceof " + |
||||||
|
"GroupRecyclerAdapter or extends GroupRecyclerAdapter"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void addItemDecoration(ItemDecoration decor) { |
||||||
|
if (decor instanceof GroupItemDecoration) |
||||||
|
super.addItemDecoration(decor); |
||||||
|
else |
||||||
|
throw new IllegalStateException("ItemDecoration must instanceof " + |
||||||
|
"GroupItemDecoration or extends GroupItemDecoration"); |
||||||
|
mItemDecoration = (GroupItemDecoration) decor; |
||||||
|
mItemDecoration.setTextSize(mTextSize); |
||||||
|
mItemDecoration.setBackground(mGroutBackground); |
||||||
|
mItemDecoration.setTextColor(mTextColor); |
||||||
|
mItemDecoration.setGroupHeight(mGroupHeight); |
||||||
|
mItemDecoration.setPadding(mPaddingLeft, mPaddingRight); |
||||||
|
mItemDecoration.setCenter(isCenter); |
||||||
|
mItemDecoration.setHasHeader(isHasHeader); |
||||||
|
mItemDecoration.setChildItemOffset(mChildItemOffset); |
||||||
|
//mItemDecoration.notifyDataSetChanged((GroupRecyclerAdapter) getAdapter());
|
||||||
|
} |
||||||
|
|
||||||
|
public void notifyDataSetChanged() { |
||||||
|
mItemDecoration.notifyDataSetChanged((GroupRecyclerAdapter) getAdapter()); |
||||||
|
} |
||||||
|
|
||||||
|
public void setOnGroupChangeListener(OnGroupChangeListener listener) { |
||||||
|
this.mListener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 分组最上面改变通知 |
||||||
|
*/ |
||||||
|
public interface OnGroupChangeListener { |
||||||
|
void onGroupChange(int groupPosition, String group); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
package cc.niushuai.didicheck.ui.index; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.Paint; |
||||||
|
|
||||||
|
import com.haibin.calendarview.Calendar; |
||||||
|
import com.haibin.calendarview.MonthView; |
||||||
|
|
||||||
|
/** |
||||||
|
* 下标标记的日历控件 |
||||||
|
* Created by huanghaibin on 2017/11/15. |
||||||
|
*/ |
||||||
|
|
||||||
|
public class IndexMonthView extends MonthView { |
||||||
|
private Paint mSchemeBasicPaint = new Paint(); |
||||||
|
private int mPadding; |
||||||
|
private int mH, mW; |
||||||
|
|
||||||
|
public IndexMonthView(Context context) { |
||||||
|
super(context); |
||||||
|
|
||||||
|
mSchemeBasicPaint.setAntiAlias(true); |
||||||
|
mSchemeBasicPaint.setStyle(Paint.Style.FILL); |
||||||
|
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER); |
||||||
|
mSchemeBasicPaint.setColor(0xff333333); |
||||||
|
mSchemeBasicPaint.setFakeBoldText(true); |
||||||
|
mPadding = dipToPx(getContext(), 4); |
||||||
|
mH = dipToPx(getContext(), 2); |
||||||
|
mW = dipToPx(getContext(), 8); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) { |
||||||
|
mSelectedPaint.setStyle(Paint.Style.FILL); |
||||||
|
canvas.drawRect(x + mPadding, y + mPadding, x + mItemWidth - mPadding, y + mItemHeight - mPadding, mSelectedPaint); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* onDrawSelected |
||||||
|
* @param canvas canvas |
||||||
|
* @param calendar 日历calendar |
||||||
|
* @param x 日历Card x起点坐标 |
||||||
|
* @param y 日历Card y起点坐标 |
||||||
|
*/ |
||||||
|
@SuppressWarnings("IntegerDivisionInFloatingPointContext") |
||||||
|
@Override |
||||||
|
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) { |
||||||
|
mSchemeBasicPaint.setColor(calendar.getSchemeColor()); |
||||||
|
canvas.drawRect(x + mItemWidth / 2 - mW / 2, |
||||||
|
y + mItemHeight - mH * 2 - mPadding, |
||||||
|
x + mItemWidth / 2 + mW / 2, |
||||||
|
y + mItemHeight - mH - mPadding, mSchemeBasicPaint); |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings("IntegerDivisionInFloatingPointContext") |
||||||
|
@Override |
||||||
|
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) { |
||||||
|
int cx = x + mItemWidth / 2; |
||||||
|
int top = y - mItemHeight / 6; |
||||||
|
if (hasScheme) { |
||||||
|
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top, |
||||||
|
calendar.isCurrentDay() ? mCurDayTextPaint : |
||||||
|
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint); |
||||||
|
|
||||||
|
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, |
||||||
|
calendar.isCurrentDay() ? mCurDayLunarTextPaint : |
||||||
|
mCurMonthLunarTextPaint); |
||||||
|
|
||||||
|
} else { |
||||||
|
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top, |
||||||
|
calendar.isCurrentDay() ? mCurDayTextPaint : |
||||||
|
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint); |
||||||
|
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mCurMonthLunarTextPaint); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* dp转px |
||||||
|
* |
||||||
|
* @param context context |
||||||
|
* @param dpValue dp |
||||||
|
* @return px |
||||||
|
*/ |
||||||
|
private static int dipToPx(Context context, float dpValue) { |
||||||
|
final float scale = context.getResources().getDisplayMetrics().density; |
||||||
|
return (int) (dpValue * scale + 0.5f); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,103 @@ |
|||||||
|
package cc.niushuai.didicheck.ui.index; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.Paint; |
||||||
|
|
||||||
|
import com.haibin.calendarview.Calendar; |
||||||
|
import com.haibin.calendarview.WeekView; |
||||||
|
|
||||||
|
/** |
||||||
|
* 下标周视图 |
||||||
|
* Created by huanghaibin on 2017/11/29. |
||||||
|
*/ |
||||||
|
|
||||||
|
public class IndexWeekView extends WeekView { |
||||||
|
private Paint mSchemeBasicPaint = new Paint(); |
||||||
|
private int mPadding; |
||||||
|
private int mH, mW; |
||||||
|
|
||||||
|
public IndexWeekView(Context context) { |
||||||
|
super(context); |
||||||
|
mSchemeBasicPaint.setAntiAlias(true); |
||||||
|
mSchemeBasicPaint.setStyle(Paint.Style.FILL); |
||||||
|
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER); |
||||||
|
mSchemeBasicPaint.setColor(0xff333333); |
||||||
|
mSchemeBasicPaint.setFakeBoldText(true); |
||||||
|
mPadding = dipToPx(getContext(), 4); |
||||||
|
mH = dipToPx(getContext(), 2); |
||||||
|
mW = dipToPx(getContext(), 8); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onPreviewHook() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 如果这里和 onDrawScheme 是互斥的,则 return false, |
||||||
|
* return true 会先绘制 onDrawSelected,再绘制onDrawSelected |
||||||
|
* |
||||||
|
* @param canvas canvas |
||||||
|
* @param calendar 日历日历calendar |
||||||
|
* @param x 日历Card x起点坐标 |
||||||
|
* @param hasScheme hasScheme 非标记的日期 |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) { |
||||||
|
mSelectedPaint.setStyle(Paint.Style.FILL); |
||||||
|
canvas.drawRect(x + mPadding, mPadding, x + mItemWidth - mPadding, mItemHeight - mPadding, mSelectedPaint); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 绘制下标标记 |
||||||
|
* |
||||||
|
* @param canvas canvas |
||||||
|
* @param calendar 日历calendar |
||||||
|
* @param x 日历Card x起点坐标 |
||||||
|
*/ |
||||||
|
@SuppressWarnings("IntegerDivisionInFloatingPointContext") |
||||||
|
@Override |
||||||
|
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) { |
||||||
|
mSchemeBasicPaint.setColor(calendar.getSchemeColor()); |
||||||
|
canvas.drawRect(x + mItemWidth / 2 - mW / 2, |
||||||
|
mItemHeight - mH * 2 - mPadding, |
||||||
|
x + mItemWidth / 2 + mW / 2, |
||||||
|
mItemHeight - mH - mPadding, mSchemeBasicPaint); |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings("IntegerDivisionInFloatingPointContext") |
||||||
|
@Override |
||||||
|
protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) { |
||||||
|
int cx = x + mItemWidth / 2; |
||||||
|
int top = -mItemHeight / 6; |
||||||
|
if (hasScheme) { |
||||||
|
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top, |
||||||
|
calendar.isCurrentDay() ? mCurDayTextPaint : |
||||||
|
calendar.isCurrentMonth() ? mSchemeTextPaint : mCurMonthTextPaint); |
||||||
|
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, |
||||||
|
calendar.isCurrentDay() ? mCurDayLunarTextPaint : |
||||||
|
mCurMonthLunarTextPaint); |
||||||
|
} else { |
||||||
|
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top, |
||||||
|
calendar.isCurrentDay() ? mCurDayTextPaint : |
||||||
|
calendar.isCurrentMonth() ? mCurMonthTextPaint : mCurMonthTextPaint); |
||||||
|
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, |
||||||
|
calendar.isCurrentDay() ? mCurDayLunarTextPaint : |
||||||
|
mCurMonthLunarTextPaint); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* dp转px |
||||||
|
* |
||||||
|
* @param context context |
||||||
|
* @param dpValue dp |
||||||
|
* @return px |
||||||
|
*/ |
||||||
|
private static int dipToPx(Context context, float dpValue) { |
||||||
|
final float scale = context.getResources().getDisplayMetrics().density; |
||||||
|
return (int) (dpValue * scale + 0.5f); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
package cc.niushuai.didicheck.ui.index; |
||||||
|
|
||||||
|
public class x { |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:color="#d4d4d4" > |
||||||
|
<item> |
||||||
|
<shape> |
||||||
|
<solid android:color="@color/content_background" /> |
||||||
|
</shape> |
||||||
|
</item> |
||||||
|
</ripple> |
@ -0,0 +1,3 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:color="#d4d4d4" /> |
@ -0,0 +1,13 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<item android:state_pressed="true"> |
||||||
|
<shape> |
||||||
|
<solid android:color="#cfcfcf" /> |
||||||
|
</shape> |
||||||
|
</item> |
||||||
|
<item> |
||||||
|
<shape> |
||||||
|
<solid android:color="#00000000" /> |
||||||
|
</shape> |
||||||
|
</item> |
||||||
|
</selector> |
@ -0,0 +1,3 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:color="#d4d4d4" /> |
@ -1,50 +1,146 @@ |
|||||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||||
xmlns:tools="http://schemas.android.com/tools" |
xmlns:tools="http://schemas.android.com/tools" |
||||||
android:id="@+id/HomeFragmentRootLayout" |
android:id="@+id/HomeFragmentRootLayout" |
||||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||||
android:layout_height="match_parent" |
android:layout_height="match_parent" |
||||||
tools:context=".ui.main.home.HomeFragment"> |
android:background="#ffffff" |
||||||
|
android:fitsSystemWindows="true" |
||||||
|
android:orientation="vertical" |
||||||
|
tools:context=".ui.main.home.HomeFragment" |
||||||
|
tools:ignore="RtlHardcoded,HardcodedText,RtlSymmetry,SmallSp"> |
||||||
|
|
||||||
<!--标题view--> |
<RelativeLayout |
||||||
<TextView |
android:id="@+id/rl_tool" |
||||||
android:id="@+id/home_title_textView" |
|
||||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||||
|
android:layout_height="52dp" |
||||||
|
android:background="@color/colorPrimary"> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_month_day" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:gravity="center_vertical" |
||||||
|
android:paddingLeft="16dp" |
||||||
|
android:textColor="#000000" |
||||||
|
android:textSize="26sp" |
||||||
|
android:textStyle="bold" |
||||||
|
tools:ignore="RtlSymmetry" /> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_toRightOf="@+id/tv_month_day" |
||||||
|
android:orientation="vertical" |
||||||
|
android:paddingLeft="6dp" |
||||||
|
android:paddingTop="12dp" |
||||||
|
android:paddingRight="6dp" |
||||||
|
android:paddingBottom="12dp" |
||||||
|
tools:ignore="RelativeOverlap"> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_year" |
||||||
|
android:layout_width="wrap_content" |
||||||
android:layout_height="0dp" |
android:layout_height="0dp" |
||||||
app:layout_constraintHeight_percent="0.05" |
android:layout_weight="1" |
||||||
app:layout_constraintLeft_toLeftOf="parent" |
android:gravity="center" |
||||||
app:layout_constraintTop_toTopOf="parent" /> |
android:textColor="#000000" |
||||||
<!-- |
android:textSize="10sp" /> |
||||||
|
|
||||||
<!–日历组件view–> |
<TextView |
||||||
<CalendarView |
android:id="@+id/tv_lunar" |
||||||
android:id="@+id/home_main_calendar" |
android:layout_width="wrap_content" |
||||||
android:layout_width="match_parent" |
|
||||||
android:layout_height="0dp" |
android:layout_height="0dp" |
||||||
app:layout_constraintHeight_percent="0.45" |
android:layout_weight="1" |
||||||
app:layout_constraintLeft_toLeftOf="@id/home_title_textView" |
android:gravity="center" |
||||||
app:layout_constraintTop_toBottomOf="@id/home_title_textView" /> |
android:textColor="#000000" |
||||||
|
android:textSize="10sp" |
||||||
|
tools:ignore="SmallSp" /> |
||||||
|
</LinearLayout> |
||||||
|
|
||||||
--> |
<FrameLayout |
||||||
|
android:id="@+id/fl_current" |
||||||
|
android:layout_width="32dp" |
||||||
|
android:layout_height="32dp" |
||||||
|
android:layout_alignParentRight="true" |
||||||
|
android:layout_centerVertical="true" |
||||||
|
android:layout_marginRight="12dp" |
||||||
|
android:background="@drawable/bg_ripple"> |
||||||
|
|
||||||
<com.haibin.calendarview.CalendarView |
<ImageView |
||||||
android:id="@+id/home_main_calendar" |
android:id="@+id/ib_calendar" |
||||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||||
android:layout_height="0dp" |
android:layout_height="match_parent" |
||||||
app:layout_constraintHeight_percent="0.45" |
android:contentDescription="@string/app_name" |
||||||
app:layout_constraintLeft_toLeftOf="@id/home_title_textView" |
android:scaleType="centerInside" |
||||||
app:layout_constraintTop_toBottomOf="@id/home_title_textView"> |
android:src="@mipmap/ic_calendar" |
||||||
|
app:tint="#000000" /> |
||||||
|
|
||||||
</com.haibin.calendarview.CalendarView> |
<TextView |
||||||
|
android:id="@+id/tv_current_day" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_gravity="center" |
||||||
|
android:layout_marginTop="2dp" |
||||||
|
android:gravity="center" |
||||||
|
android:text="13" |
||||||
|
android:textColor="#000000" |
||||||
|
android:textSize="12sp" /> |
||||||
|
</FrameLayout> |
||||||
|
</RelativeLayout> |
||||||
|
|
||||||
<!--数据展示view--> |
<com.haibin.calendarview.CalendarLayout |
||||||
<androidx.recyclerview.widget.RecyclerView |
android:id="@+id/calendarLayout" |
||||||
android:id="@+id/home_dataZone_recyclerView" |
|
||||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||||
android:layout_height="0dp" |
android:layout_height="match_parent" |
||||||
app:layout_constraintHeight_percent="0.5" |
android:background="#fff" |
||||||
app:layout_constraintLeft_toLeftOf="@id/home_main_calendar" |
android:orientation="vertical" |
||||||
app:layout_constraintTop_toBottomOf="@+id/home_main_calendar" /> |
app:calendar_content_view_id="@+id/recyclerView"> |
||||||
|
|
||||||
|
<com.haibin.calendarview.CalendarView |
||||||
|
android:id="@+id/calendarView" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginLeft="12dp" |
||||||
|
android:layout_marginRight="12dp" |
||||||
|
android:background="#fff" |
||||||
|
app:current_month_lunar_text_color="#CFCFCF" |
||||||
|
app:current_month_text_color="#333333" |
||||||
|
app:day_text_size="16sp" |
||||||
|
app:lunar_text_size="8sp" |
||||||
|
app:min_year="2004" |
||||||
|
app:month_view="cc.niushuai.didicheck.ui.index.IndexMonthView" |
||||||
|
app:month_view_show_mode="mode_fix" |
||||||
|
app:other_month_text_color="#e1e1e1" |
||||||
|
app:scheme_text="假" |
||||||
|
app:scheme_text_color="#333" |
||||||
|
app:scheme_theme_color="#128c4b" |
||||||
|
app:selected_lunar_text_color="#CFCFCF" |
||||||
|
app:selected_text_color="#333" |
||||||
|
app:selected_theme_color="#80cfcfcf" |
||||||
|
app:week_background="#fff" |
||||||
|
app:week_text_color="#111" |
||||||
|
app:week_view="cc.niushuai.didicheck.ui.index.IndexWeekView" |
||||||
|
app:year_view_day_text_color="#333333" |
||||||
|
app:year_view_day_text_size="9sp" |
||||||
|
app:year_view_month_text_color="#ff0000" |
||||||
|
app:year_view_month_text_size="20sp" |
||||||
|
app:year_view_scheme_color="#f17706" /> |
||||||
|
|
||||||
|
<cc.niushuai.didicheck.ui.group.GroupRecyclerView |
||||||
|
android:id="@+id/recyclerView" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:background="@color/content_background" |
||||||
|
app:group_background="@color/content_background" |
||||||
|
app:group_center="false" |
||||||
|
app:group_has_header="false" |
||||||
|
app:group_height="42dp" |
||||||
|
app:group_padding_left="16dp" |
||||||
|
app:group_padding_right="16dp" |
||||||
|
app:group_text_color="#555555" |
||||||
|
app:group_text_size="14sp" /> |
||||||
|
</com.haibin.calendarview.CalendarLayout> |
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout> |
</LinearLayout> |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 832 B |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 853 B |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 11 KiB |
@ -0,0 +1,15 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
<declare-styleable name="GroupRecyclerView"> |
||||||
|
<attr name="group_height" format="dimension" /> |
||||||
|
<attr name="group_child_offset" format="dimension" /> |
||||||
|
<attr name="group_background" format="color" /> |
||||||
|
<attr name="group_text_color" format="color" /> |
||||||
|
<attr name="group_text_size" format="dimension" /> |
||||||
|
<attr name="group_center" format="boolean" /> |
||||||
|
<attr name="group_padding_left" format="dimension" /> |
||||||
|
<attr name="group_padding_right" format="dimension" /> |
||||||
|
<attr name="group_has_header" format="boolean" /> |
||||||
|
</declare-styleable> |
||||||
|
|
||||||
|
</resources> |