Commit a4c16dbc authored by 贾海然's avatar 贾海然

首次提交代码到gitlab

parents
Pipeline #145 canceled with stages

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

*.iml
.gradle
/.idea
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
/AlivcLongVideo/build
/Aliyunplayer/AlivcPlayerTools/build
/AliyunVideoCommon/build
\ No newline at end of file
apply plugin: 'com.android.library'
android {
compileSdkVersion externalCompileSdkVersion
buildToolsVersion externalBuildToolsVersion
defaultConfig {
minSdkVersion externalMinSdkVersion
targetSdkVersion externalTargetSdkVersion
}
}
dependencies {
implementation (externalGlide){
exclude group: "com.android.support"
}
implementation externalAndroidSupportV4
implementation externalAndroidAppCompatV7
implementation externalAndroidRecyclerView
implementation externalOKHTTP
implementation externalGSON
}
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.aliyun.svideo.common"
>
<!--网络/网络状态-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<!--Sdcard读写权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--摄像头录音权限-->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!--电话状态权限-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--蓝牙权限-->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!--自动更新URI跳转安装时需要-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application>
<!-- FileProvider配置访问路径,适配7.0及其以上 -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.aliyun.svideo.common.fileprovider"
android:exported="false"
android:grantUriPermissions="true"
android:banner="@string/alivc_common_cancel"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"
tools:replace="android:resource"/>
</provider>
</application>
</manifest>
package com.aliyun.svideo.common;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.util.Log;
import com.aliyun.svideo.common.utils.FileUtils;
import com.aliyun.svideo.common.utils.PermissionUtils;
/**
* @author cross_ly DATE 2019/01/24
* <p>描述:
*/
public class SdcardUtils {
private static final String TAG = SdcardUtils.class.getSimpleName();
/**
* 检测sdcard剩余有效内存,低于参数时弹出内存不足提示
* @param tagSize 单位M
*/
public static void checkAvailableSize(Context context, int tagSize) {
boolean isHasPermission = PermissionUtils.checkPermissionsGroup(context, PermissionUtils.PERMISSION_STORAGE);
if (isHasPermission) {
long availableSize = FileUtils.getSdcardAvailableSize() / 1024 / 1024;
Log.e(TAG, "log_common_SdcardUtils_availableSize : " + availableSize);
if (availableSize < tagSize) {
showAlertDialog(context);
}
}
}
/**
* 显示警告框
* @param context Context
*/
private static void showAlertDialog(Context context) {
final AlertDialog.Builder alertDialog =
new AlertDialog.Builder(context);
alertDialog.setTitle(context.getResources().getString(R.string.alivc_common_note));
alertDialog.setMessage(context.getResources().getString(R.string.alivc_common_device_memory_not_enough));
alertDialog.setPositiveButton(context.getResources().getString(R.string.aliyun_common_confirm),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//nothing to do
}
});
alertDialog.setCancelable(false);
// 显示
alertDialog.show();
}
}
package com.aliyun.svideo.common.base;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.aliyun.svideo.common.R;
import com.aliyun.svideo.common.widget.WheelView;
/**
* 滑动选择对话框
*/
public class AlivcWheelDialogFragment extends BaseDialogFragment implements WheelView.OnValueChangeListener {
private WheelView mWheelView;
private TextView mTvLeft, mTvRight;
public FragmentManager mFragmentManager;
/**
* 数据源
*/
private String[] mDialogWheel;
/**
* 左边文字
*/
private String mDialogLeft;
/**
* 右边文字
*/
private String mDialogRight;
/**
* 数据接口回调
*/
private OnWheelDialogListener mOnWheelDialogListener;
/**
* 点击外部是否可以取消
*/
public boolean mIsCancelableOutside = true;
/**
* 弹窗动画
*/
public int mDialogAnimationRes = 0;
@Override
protected int getLayoutRes() {
return R.layout.alivc_common_dialogfragment_wheelview;
}
@Override
protected void bindView(View view) {
mTvLeft = (TextView) view.findViewById(R.id.alivc_tv_cancel);
mTvRight = (TextView) view.findViewById(R.id.alivc_tv_sure);
mWheelView = (WheelView) view.findViewById(R.id.alivc_wheelView_dialog);
mTvLeft.setText(mDialogLeft);
mTvRight.setText(mDialogRight);
mWheelView.refreshByNewDisplayedValues(mDialogWheel);
//设置是否可以上下无限滑动
mWheelView.setWrapSelectorWheel(false);
mWheelView.setDividerColor(ContextCompat.getColor(getContext(), R.color.alivc_common_bg_white_gray));
mWheelView.setSelectedTextColor(ContextCompat.getColor(getContext(), R.color.alivc_common_bg_black));
mWheelView.setNormalTextColor(ContextCompat.getColor(getContext(), R.color.alivc_common_font_gray_333333));
initEvent();
}
protected void initEvent() {
//左边按钮
mTvLeft.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnWheelDialogListener != null) {
mOnWheelDialogListener.onClickLeft(AlivcWheelDialogFragment.this, getWheelValue());
}
}
});
//右边按钮
mTvRight.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnWheelDialogListener != null) {
mOnWheelDialogListener.onClickRight(AlivcWheelDialogFragment.this, getWheelValue());
}
}
});
}
/**
* 获取当前值
*
* @return
*/
private String getWheelValue() {
String[] content = mWheelView.getDisplayedValues();
return content == null ? null : content[mWheelView.getValue() - mWheelView.getMinValue()];
}
@Override
public void onValueChange(WheelView picker, int oldVal, int newVal) {
String[] content = mWheelView.getDisplayedValues();
if (content != null && mOnWheelDialogListener != null) {
mOnWheelDialogListener.onValueChanged(AlivcWheelDialogFragment.this, content[newVal - mWheelView.getMinValue()]);
}
}
@Override
protected boolean isCancelableOutside() {
return mIsCancelableOutside;
}
@Override
protected int getDialogAnimationRes() {
return mDialogAnimationRes;
}
public AlivcWheelDialogFragment show() {
Log.d("Dialog", "show");
try {
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.remove(this);
ft.add(this, tag);
ft.commitAllowingStateLoss();
} catch (Exception e) {
Log.e("Dialog", e.toString());
}
return this;
}
/**
* 对外开放的方法
*
* @param onWheelDialogListener
*/
public void setWheelDialogListener(OnWheelDialogListener onWheelDialogListener) {
this.mOnWheelDialogListener = onWheelDialogListener;
}
public static final class Builder {
private AlivcWheelDialogFragment mDialogFragment = new AlivcWheelDialogFragment();
public Builder(FragmentManager fragmentManager) {
mDialogFragment.mFragmentManager = fragmentManager;
}
/**
* 设置数据源
*/
public Builder setWheelData(String[] data) {
mDialogFragment.mDialogWheel = data;
return this;
}
/**
* 设置左边文字
*/
public Builder cancelString(String cancel) {
mDialogFragment.mDialogLeft = cancel;
return this;
}
/**
* 设置右边文字
*/
public Builder sureString(String sure) {
mDialogFragment.mDialogRight = sure;
return this;
}
/**
* 设置回调
*/
public Builder onWheelDialogListener(OnWheelDialogListener onWheelDialogListener) {
mDialogFragment.mOnWheelDialogListener = onWheelDialogListener;
return this;
}
/**
* 设置点击外部是否可以取消
*/
public Builder isCancelableOutside(boolean outSide) {
mDialogFragment.mIsCancelableOutside = outSide;
return this;
}
/**
* 设置动画
*/
public Builder dialogAnimationRes(int animation) {
mDialogFragment.mDialogAnimationRes = animation;
return this;
}
/**
* 真正创建
*/
public AlivcWheelDialogFragment create() {
return mDialogFragment;
}
}
public interface OnWheelDialogListener {
/**
* 左边按钮单击事件回调
*
* @param dialog
* @param value
*/
void onClickLeft(DialogFragment dialog, String value);
/**
* 右边按钮单击事件回调
*
* @param dialog
* @param value
*/
void onClickRight(DialogFragment dialog, String value);
/**
* 滑动停止时的回调
*
* @param dialog
* @param value
*/
void onValueChanged(DialogFragment dialog, String value);
}
}
package com.aliyun.svideo.common.base;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.Nullable;
/**
* 所有自定义对话框的基类
* 用来实现复杂的弹框样式
*/
public abstract class BaseDialogFragment extends DialogFragment {
protected String tag = getClass().getSimpleName();
//默认透明度
private static final float DEFAULT_DIMAMOUNT = 0.2F;
//填充视图
protected abstract int getLayoutRes();
//设置视图内容
protected abstract void bindView(View view);
@Override
public void onStart() {
super.onStart();
Window window = getDialog().getWindow();
if (window != null) {
//设置窗体背景色透明
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
//设置宽高
WindowManager.LayoutParams layoutParams = window.getAttributes();
if (getDialogWidth() > 0) {
layoutParams.width = getDialogWidth();
} else {
layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
}
if (getDialogHeight() > 0) {
layoutParams.height = getDialogHeight();
} else {
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
}
//透明度
layoutParams.dimAmount = getDimAmount();
//位置
layoutParams.gravity = getGravity();
window.setAttributes(layoutParams);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
View view = null;
if (getLayoutRes() > 0) {
view = inflater.inflate(getLayoutRes(), container, false);
}
bindView(view);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//去除Dialog默认头部
Dialog dialog = getDialog();
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCanceledOnTouchOutside(isCancelableOutside());
if (dialog.getWindow() != null && getDialogAnimationRes() > 0) {
dialog.getWindow().setWindowAnimations(getDialogAnimationRes());
}
if (getOnKeyListener() != null) {
dialog.setOnKeyListener(getOnKeyListener());
}
}
protected DialogInterface.OnKeyListener getOnKeyListener() {
return null;
}
//默认弹窗位置为中心
public int getGravity() {
return Gravity.BOTTOM;
}
//默认宽高为包裹内容
public int getDialogHeight() {
return WindowManager.LayoutParams.WRAP_CONTENT;
}
public int getDialogWidth() {
return WindowManager.LayoutParams.MATCH_PARENT;
}
//默认透明度为0.2
public float getDimAmount() {
return DEFAULT_DIMAMOUNT;
}
public String getFragmentTag() {
return tag;
}
public void show(FragmentManager fragmentManager) {
show(fragmentManager, getFragmentTag());
}
protected boolean isCancelableOutside() {
return true;
}
//获取弹窗显示动画,子类实现
protected int getDialogAnimationRes() {
return 0;
}
//获取设备屏幕宽度
public static final int getScreenWidth(Context context) {
return context.getResources().getDisplayMetrics().widthPixels;
}
//获取设备屏幕高度
public static final int getScreenHeight(Context context) {
return context.getResources().getDisplayMetrics().heightPixels;
}
}
\ No newline at end of file
package com.aliyun.svideo.common.baseAdapter;
import android.view.ViewGroup;
import com.aliyun.svideo.common.baseAdapter.entity.SectionEntity;
import java.util.List;
public abstract class BaseSectionQuickAdapter<T extends SectionEntity, K extends BaseViewHolder> extends BaseQuickAdapter<T, K> {
protected int mSectionHeadResId;
protected static final int SECTION_HEADER_VIEW = 0x00000444;
/**
* Same as QuickAdapter#QuickAdapter(Context,int) but with
* some initialization data.
*
* @param sectionHeadResId The section head layout id for each item
* @param layoutResId The layout resource id of each item.
* @param data A new list is created out of this one to avoid mutable list
*/
public BaseSectionQuickAdapter(int layoutResId, int sectionHeadResId, List<T> data) {
super(layoutResId, data);
this.mSectionHeadResId = sectionHeadResId;
}
@Override
protected int getDefItemViewType(int position) {
return mData.get(position).isHeader ? SECTION_HEADER_VIEW : 0;
}
@Override
protected K onCreateDefViewHolder(ViewGroup parent, int viewType) {
if (viewType == SECTION_HEADER_VIEW) {
return createBaseViewHolder(getItemView(mSectionHeadResId, parent));
}
return super.onCreateDefViewHolder(parent, viewType);
}
@Override
protected boolean isFixedViewType(int type) {
return super.isFixedViewType(type) || type == SECTION_HEADER_VIEW;
}
@Override
public void onBindViewHolder(K holder, int position) {
switch (holder.getItemViewType()) {
case SECTION_HEADER_VIEW:
setFullSpan(holder);
convertHead(holder, getItem(position - getHeaderLayoutCount()));
break;
default:
super.onBindViewHolder(holder, position);
break;
}
}
protected abstract void convertHead(K helper, T item);
}
\ No newline at end of file
package com.aliyun.svideo.common.baseAdapter;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
/**
* BaseQuickAdapter的加载更多的状态,实现类SimpleLoadMoreView,可自定义
*/
public abstract class LoadMoreView {
public static final int STATUS_DEFAULT = 1;
public static final int STATUS_LOADING = 2;
public static final int STATUS_FAIL = 3;
public static final int STATUS_END = 4;
private int mLoadMoreStatus = STATUS_DEFAULT;
private boolean mLoadMoreEndGone = false;
public void setLoadMoreStatus(int loadMoreStatus) {
this.mLoadMoreStatus = loadMoreStatus;
}
public int getLoadMoreStatus() {
return mLoadMoreStatus;
}
public void convert(BaseViewHolder holder) {
switch (mLoadMoreStatus) {
case STATUS_LOADING:
visibleLoading(holder, true);
visibleLoadFail(holder, false);
visibleLoadEnd(holder, false);
break;
case STATUS_FAIL:
visibleLoading(holder, false);
visibleLoadFail(holder, true);
visibleLoadEnd(holder, false);
break;
case STATUS_END:
visibleLoading(holder, false);
visibleLoadFail(holder, false);
visibleLoadEnd(holder, true);
break;
case STATUS_DEFAULT:
visibleLoading(holder, false);
visibleLoadFail(holder, false);
visibleLoadEnd(holder, false);
break;
default:
break;
}
}
private void visibleLoading(BaseViewHolder holder, boolean visible) {
holder.setGone(getLoadingViewId(), visible);
}
private void visibleLoadFail(BaseViewHolder holder, boolean visible) {
holder.setGone(getLoadFailViewId(), visible);
}
private void visibleLoadEnd(BaseViewHolder holder, boolean visible) {
final int loadEndViewId = getLoadEndViewId();
if (loadEndViewId != 0) {
holder.setGone(loadEndViewId, visible);
}
}
public final void setLoadMoreEndGone(boolean loadMoreEndGone) {
this.mLoadMoreEndGone = loadMoreEndGone;
}
public final boolean isLoadEndMoreGone() {
if (getLoadEndViewId() == 0) {
return true;
}
return mLoadMoreEndGone;
}
/**
* No more data is hidden
*
* @return true for no more data hidden load more
* @deprecated Use {@link BaseQuickAdapter#loadMoreEnd(boolean)} instead.
*/
@Deprecated
public boolean isLoadEndGone() {
return mLoadMoreEndGone;
}
/**
* load more layout
*
* @return
*/
public abstract
@LayoutRes
int getLayoutId();
/**
* loading view
*
* @return
*/
protected abstract
@IdRes
int getLoadingViewId();
/**
* load fail view
*
* @return
*/
protected abstract
@IdRes
int getLoadFailViewId();
/**
* load end view, you can return 0
*
* @return
*/
protected abstract
@IdRes
int getLoadEndViewId();
}
\ No newline at end of file
package com.aliyun.svideo.common.baseAdapter;
import android.util.SparseArray;
import android.view.View;
import androidx.annotation.Nullable;
import com.aliyun.svideo.common.baseAdapter.delegate.MultiTypeDelegate;
import com.aliyun.svideo.common.baseAdapter.provider.BaseItemProvider;
import com.aliyun.svideo.common.baseAdapter.utils.ProviderDelegate;
import java.util.List;
/**
* 当有多种条目的时候,避免在convert()中做太多的业务逻辑,把逻辑放在对应的ItemProvider中
* @date 2018/3/21 9:55
*/
public abstract class MultipleItemRvAdapter<T, V extends BaseViewHolder> extends BaseQuickAdapter<T, V> {
private SparseArray<BaseItemProvider> mItemProviders;
protected ProviderDelegate mProviderDelegate;
public MultipleItemRvAdapter(@Nullable List<T> data) {
super(data);
}
/**
* 用于adapter构造函数完成参数的赋值后调用
* Called after the assignment of the argument to the adapter constructor
*/
public void finishInitialize() {
mProviderDelegate = new ProviderDelegate();
setMultiTypeDelegate(new MultiTypeDelegate<T>() {
@Override
protected int getItemType(T t) {
return getViewType(t);
}
});
registerItemProvider();
mItemProviders = mProviderDelegate.getItemProviders();
for (int i = 0; i < mItemProviders.size(); i++) {
int key = mItemProviders.keyAt(i);
BaseItemProvider provider = mItemProviders.get(key);
provider.mData = mData;
getMultiTypeDelegate().registerItemType(key, provider.layout());
}
}
protected abstract int getViewType(T t);
public abstract void registerItemProvider();
@Override
protected void convert(V helper, T item) {
int itemViewType = helper.getItemViewType();
BaseItemProvider provider = mItemProviders.get(itemViewType);
provider.mContext = helper.itemView.getContext();
int position = helper.getLayoutPosition() - getHeaderLayoutCount();
provider.convert(helper, item, position);
bindClick(helper, item, position, provider);
}
private void bindClick(final V helper, final T item, final int position, final BaseItemProvider provider) {
OnItemClickListener clickListener = getOnItemClickListener();
OnItemLongClickListener longClickListener = getOnItemLongClickListener();
if (clickListener != null && longClickListener != null) {
//如果已经设置了子条目点击监听和子条目长按监听
// If you have set up a sub-entry click monitor and sub-entries long press listen
return;
}
View itemView = helper.itemView;
if (clickListener == null) {
//如果没有设置点击监听,则回调给itemProvider
//Callback to itemProvider if no click listener is set
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
provider.onClick(helper, item, position);
}
});
}
if (longClickListener == null) {
//如果没有设置长按监听,则回调给itemProvider
// If you do not set a long press listener, callback to the itemProvider
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return provider.onLongClick(helper, item, position);
}
});
}
}
}
package com.aliyun.svideo.common.baseAdapter;
import com.aliyun.svideo.common.R;
/**
* 配合BaseQuickAdapter的加载更多布局,如需修改请自定义
*/
public final class SimpleLoadMoreView extends LoadMoreView {
@Override
public int getLayoutId() {
return R.layout.alivc_quick_view_load_more;
}
@Override
protected int getLoadingViewId() {
return R.id.load_more_loading_view;
}
@Override
protected int getLoadFailViewId() {
return R.id.load_more_load_fail_view;
}
@Override
protected int getLoadEndViewId() {
return R.id.load_more_load_end_view;
}
}
package com.aliyun.svideo.common.baseAdapter.animation;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.view.View;
/**
*alpha动画
*/
public class AlphaInAnimation implements BaseAnimation {
private static final float DEFAULT_ALPHA_FROM = 0f;
private final float mFrom;
public AlphaInAnimation() {
this(DEFAULT_ALPHA_FROM);
}
public AlphaInAnimation(float from) {
mFrom = from;
}
@Override
public Animator[] getAnimators(View view) {
return new Animator[] {ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f)};
}
}
\ No newline at end of file
package com.aliyun.svideo.common.baseAdapter.animation;
import android.animation.Animator;
import android.view.View;
/**
* 基recyclervView的item础动画接口
*/
public interface BaseAnimation {
Animator[] getAnimators(View view);
}
\ No newline at end of file
package com.aliyun.svideo.common.baseAdapter.decoration;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.View;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class GridItemDecoration extends RecyclerView.ItemDecoration {
private Drawable dividerDrawable;
private int orientation = LinearLayoutManager.VERTICAL;
public GridItemDecoration(Drawable divider) {
dividerDrawable = divider;
}
public GridItemDecoration(Context context, int resId) {
dividerDrawable = context.getResources().getDrawable(resId);
}
public GridItemDecoration(Context context, int resId, int orientation) {
dividerDrawable = context.getResources().getDrawable(resId);
this.orientation = orientation;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (dividerDrawable == null) {
return;
}
if (parent.getChildLayoutPosition(view) < 1) {
return;
}
if (orientation == LinearLayoutManager.VERTICAL) {
outRect.top = dividerDrawable.getIntrinsicHeight();
} else if (orientation == LinearLayoutManager.HORIZONTAL) {
outRect.left = dividerDrawable.getIntrinsicWidth();
}
}
/**
* @param c
* @param parent
* @param state
*/
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (dividerDrawable == null) {
return;
}
int childCount = parent.getChildCount();
int rightV = parent.getWidth();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int leftV = parent.getPaddingLeft() + child.getPaddingLeft();
int bottomV = child.getTop() - params.topMargin;
int topV = bottomV - dividerDrawable.getIntrinsicHeight();
int topH = child.getTop() + params.topMargin;
int bottomH = child.getBottom() + params.bottomMargin;
int rightH = child.getLeft() - params.leftMargin;
int leftH = rightH - dividerDrawable.getIntrinsicWidth();
dividerDrawable.setBounds(leftH, topH, rightH, bottomH);
dividerDrawable.draw(c);
dividerDrawable.setBounds(leftV, topV, rightV, bottomV);
dividerDrawable.draw(c);
}
}
}
package com.aliyun.svideo.common.baseAdapter.decoration;
import android.graphics.Rect;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.aliyun.svideo.common.baseAdapter.BaseSectionQuickAdapter;
import com.aliyun.svideo.common.baseAdapter.BaseViewHolder;
import com.aliyun.svideo.common.baseAdapter.entity.SectionEntity;
import java.util.ArrayList;
import java.util.List;
/**
* 应用于RecyclerView的GridLayoutManager,水平方向上固定间距大小,从而使条目宽度自适应。<br>
* 配合Brvah的Section使用,不对Head生效,仅对每个Head的子Grid列表生效<br>
* Section Grid中Item的宽度应设为MATCH_PARAENT
*/
public class GridSectionAverageGapItemDecoration extends RecyclerView.ItemDecoration {
private class Section {
public int startPos = 0;
public int endPos = 0;
public int getCount() {
return endPos - startPos + 1;
}
public boolean contains(int pos) {
return pos >= startPos && pos <= endPos;
}
@Override
public String toString() {
return "Section{" +
"startPos=" + startPos +
", endPos=" + endPos +
'}';
}
}
private float gapHorizontalDp;
private float gapVerticalDp;
private float sectionEdgeHPaddingDp;
private float sectionEdgeVPaddingDp;
private int gapHSizePx = -1;
private int gapVSizePx = -1;
private int sectionEdgeHPaddingPx;
private int eachItemHPaddingPx; //每个条目应该在水平方向上加的padding 总大小,即=paddingLeft+paddingRight
private int sectionEdgeVPaddingPx;
private List<Section> mSectionList = new ArrayList<>();
private BaseSectionQuickAdapter mAdapter;
private RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
markSections();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
markSections();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
markSections();
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
markSections();
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
markSections();
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
markSections();
}
};
/**
* @param gapHorizontalDp item之间的水平间距
* @param gapVerticalDp item之间的垂直间距
* @param sectionEdgeHPaddingDp section左右两端的padding大小
* @param sectionEdgeVPaddingDp section上下两端的padding大小
*/
public GridSectionAverageGapItemDecoration(float gapHorizontalDp, float gapVerticalDp, float sectionEdgeHPaddingDp, float sectionEdgeVPaddingDp) {
this.gapHorizontalDp = gapHorizontalDp;
this.gapVerticalDp = gapVerticalDp;
this.sectionEdgeHPaddingDp = sectionEdgeHPaddingDp;
this.sectionEdgeVPaddingDp = sectionEdgeVPaddingDp;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getLayoutManager() instanceof GridLayoutManager && parent.getAdapter() instanceof BaseSectionQuickAdapter) {
GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
BaseSectionQuickAdapter<SectionEntity, BaseViewHolder> adapter = (BaseSectionQuickAdapter) parent.getAdapter();
if (mAdapter != adapter) {
setUpWithAdapter(adapter);
}
int spanCount = layoutManager.getSpanCount();
int position = parent.getChildAdapterPosition(view);
SectionEntity entity = adapter.getItem(position);
if (entity != null && entity.isHeader) {
//不处理header
outRect.set(0, 0, 0, 0);
// Log.w("GridAverageGapItem", "pos=" + position + "," + outRect.toShortString());
return;
}
Section section = findSectionLastItemPos(position);
if (gapHSizePx < 0 || gapVSizePx < 0) {
transformGapDefinition(parent, spanCount);
}
outRect.top = gapVSizePx;
outRect.bottom = 0;
//下面的visualPos为单个Section内的视觉Pos
int visualPos = position + 1 - section.startPos;
if (visualPos % spanCount == 1) {
//第一列
outRect.left = sectionEdgeHPaddingPx;
outRect.right = eachItemHPaddingPx - sectionEdgeHPaddingPx;
} else if (visualPos % spanCount == 0) {
//最后一列
outRect.left = eachItemHPaddingPx - sectionEdgeHPaddingPx;
outRect.right = sectionEdgeHPaddingPx;
} else {
outRect.left = gapHSizePx - (eachItemHPaddingPx - sectionEdgeHPaddingPx);
outRect.right = eachItemHPaddingPx - outRect.left;
}
if (visualPos - spanCount <= 0) {
//第一行
outRect.top = sectionEdgeVPaddingPx;
}
if (isLastRow(visualPos, spanCount, section.getCount())) {
//最后一行
outRect.bottom = sectionEdgeVPaddingPx;
// Log.w("GridAverageGapItem", "last row pos=" + position);
}
// Log.w("GridAverageGapItem", "pos=" + position + ",vPos=" + visualPos + "," + outRect.toShortString());
} else {
super.getItemOffsets(outRect, view, parent, state);
}
}
private void setUpWithAdapter(BaseSectionQuickAdapter<SectionEntity, BaseViewHolder> adapter) {
if (mAdapter != null) {
mAdapter.unregisterAdapterDataObserver(mDataObserver);
}
mAdapter = adapter;
mAdapter.registerAdapterDataObserver(mDataObserver);
markSections();
}
private void markSections() {
if (mAdapter != null) {
BaseSectionQuickAdapter<SectionEntity, BaseViewHolder> adapter = mAdapter;
mSectionList.clear();
SectionEntity sectionEntity = null;
Section section = new Section();
for (int i = 0, size = adapter.getItemCount(); i < size; i++) {
sectionEntity = adapter.getItem(i);
if (sectionEntity != null && sectionEntity.isHeader) {
//找到新Section起点
if (section != null && i != 0) {
//已经有待添加的section
section.endPos = i - 1;
mSectionList.add(section);
}
section = new Section();
section.startPos = i + 1;
} else {
section.endPos = i;
}
}
//处理末尾情况
if (!mSectionList.contains(section)) {
mSectionList.add(section);
}
// Log.w("GridAverageGapItem", "section list=" + mSectionList);
}
}
private void transformGapDefinition(RecyclerView parent, int spanCount) {
DisplayMetrics displayMetrics = new DisplayMetrics();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
parent.getDisplay().getMetrics(displayMetrics);
}
gapHSizePx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, gapHorizontalDp, displayMetrics);
gapVSizePx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, gapVerticalDp, displayMetrics);
sectionEdgeHPaddingPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, sectionEdgeHPaddingDp, displayMetrics);
sectionEdgeVPaddingPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, sectionEdgeVPaddingDp, displayMetrics);
eachItemHPaddingPx = (sectionEdgeHPaddingPx * 2 + gapHSizePx * (spanCount - 1)) / spanCount;
}
private Section findSectionLastItemPos(int curPos) {
for (Section section : mSectionList) {
if (section.contains(curPos)) {
return section;
}
}
return null;
}
private boolean isLastRow(int visualPos, int spanCount, int sectionItemCount) {
int lastRowCount = sectionItemCount % spanCount;
lastRowCount = lastRowCount == 0 ? spanCount : lastRowCount;
return visualPos > sectionItemCount - lastRowCount;
}
}
package com.aliyun.svideo.common.baseAdapter.delegate;
import android.util.SparseIntArray;
import androidx.annotation.LayoutRes;
import java.util.List;
public abstract class MultiTypeDelegate<T> {
private static final int DEFAULT_VIEW_TYPE = -0xff;
public static final int TYPE_NOT_FOUND = -404;
private SparseIntArray layouts;
private boolean autoMode, selfMode;
public MultiTypeDelegate(SparseIntArray layouts) {
this.layouts = layouts;
}
public MultiTypeDelegate() {
}
public final int getDefItemViewType(List<T> data, int position) {
T item = data.get(position);
return item != null ? getItemType(item) : DEFAULT_VIEW_TYPE;
}
/**
* get the item type from specific entity.
*
* @param t entity
* @return item type
*/
protected abstract int getItemType(T t);
public final int getLayoutId(int viewType) {
return this.layouts.get(viewType, TYPE_NOT_FOUND);
}
private void addItemType(int type, @LayoutRes int layoutResId) {
if (this.layouts == null) {
this.layouts = new SparseIntArray();
}
this.layouts.put(type, layoutResId);
}
/**
* auto increase type vale, start from 0.
*
* @param layoutResIds layout id arrays
* @return MultiTypeDelegate
*/
public MultiTypeDelegate registerItemTypeAutoIncrease(@LayoutRes int... layoutResIds) {
autoMode = true;
checkMode(selfMode);
for (int i = 0; i < layoutResIds.length; i++) {
addItemType(i, layoutResIds[i]);
}
return this;
}
/**
* set your own type one by one.
*
* @param type type value
* @param layoutResId layout id
* @return MultiTypeDelegate
*/
public MultiTypeDelegate registerItemType(int type, @LayoutRes int layoutResId) {
selfMode = true;
checkMode(autoMode);
addItemType(type, layoutResId);
return this;
}
private void checkMode(boolean mode) {
if (mode) {
throw new IllegalArgumentException("Don't mess two register mode");
}
}
}
package com.aliyun.svideo.common.baseAdapter.entity;
import java.io.Serializable;
/**
* 带section布局的列表,需要继承该类,并使用BaseSectionQuickAdapter的二次封装适配器
* 具体例子可看longvideo
*/
public abstract class SectionEntity<T> implements Serializable {
public boolean isHeader;
public T t;
public String header;
public SectionEntity(boolean isHeader, String header) {
this.isHeader = isHeader;
this.header = header;
this.t = null;
}
public SectionEntity(T t) {
this.isHeader = false;
this.header = null;
this.t = t;
}
public void setT(T t){
this.t = t;
}
}
package com.aliyun.svideo.common.baseAdapter.provider;
import android.content.Context;
import com.aliyun.svideo.common.baseAdapter.BaseViewHolder;
import java.util.List;
public abstract class BaseItemProvider<T, V extends BaseViewHolder> {
public Context mContext;
public List<T> mData;
//子类须重写该方法返回viewType
//Rewrite this method to return viewType
public abstract int viewType();
//子类须重写该方法返回layout
//Rewrite this method to return layout
public abstract int layout();
public abstract void convert(V helper, T data, int position);
//子类若想实现条目点击事件则重写该方法
//Subclasses override this method if you want to implement an item click event
public void onClick(V helper, T data, int position) {
}
//子类若想实现条目长按事件则重写该方法
//Subclasses override this method if you want to implement an item long press event
public boolean onLongClick(V helper, T data, int position) {
return false;
}
}
package com.aliyun.svideo.common.baseAdapter.utils;
public class ItemProviderException extends NullPointerException {
public ItemProviderException(String message) {
super(message);
}
}
package com.aliyun.svideo.common.baseAdapter.utils;
import android.util.SparseIntArray;
import androidx.annotation.LayoutRes;
import java.util.List;
import static com.aliyun.svideo.common.baseAdapter.delegate.MultiTypeDelegate.TYPE_NOT_FOUND;
public abstract class MultiTypeDelegate<T> {
private static final int DEFAULT_VIEW_TYPE = -0xff;
private SparseIntArray layouts;
private boolean autoMode, selfMode;
public MultiTypeDelegate(SparseIntArray layouts) {
this.layouts = layouts;
}
public MultiTypeDelegate() {
}
public final int getDefItemViewType(List<T> data, int position) {
T item = data.get(position);
return item != null ? getItemType(item) : DEFAULT_VIEW_TYPE;
}
/**
* get the item type from specific entity.
*
* @param t entity
* @return item type
*/
protected abstract int getItemType(T t);
public final int getLayoutId(int viewType) {
return this.layouts.get(viewType, TYPE_NOT_FOUND);
}
private void addItemType(int type, @LayoutRes int layoutResId) {
if (this.layouts == null) {
this.layouts = new SparseIntArray();
}
this.layouts.put(type, layoutResId);
}
/**
* auto increase type vale, start from 0.
*
* @param layoutResIds layout id arrays
* @return MultiTypeDelegate
*/
public MultiTypeDelegate registerItemTypeAutoIncrease(@LayoutRes int... layoutResIds) {
autoMode = true;
checkMode(selfMode);
for (int i = 0; i < layoutResIds.length; i++) {
addItemType(i, layoutResIds[i]);
}
return this;
}
/**
* set your own type one by one.
*
* @param type type value
* @param layoutResId layout id
* @return MultiTypeDelegate
*/
public MultiTypeDelegate registerItemType(int type, @LayoutRes int layoutResId) {
selfMode = true;
checkMode(autoMode);
addItemType(type, layoutResId);
return this;
}
private void checkMode(boolean mode) {
if (mode) {
throw new IllegalArgumentException("Don't mess two register mode");
}
}
}
package com.aliyun.svideo.common.baseAdapter.utils;
import android.util.SparseArray;
import com.aliyun.svideo.common.baseAdapter.provider.BaseItemProvider;
public class ProviderDelegate {
private SparseArray<BaseItemProvider> mItemProviders = new SparseArray<>();
public void registerProvider(BaseItemProvider provider) {
if (provider == null) {
throw new ItemProviderException("ItemProvider can not be null");
}
int viewType = provider.viewType();
if (mItemProviders.get(viewType) == null) {
mItemProviders.put(viewType, provider);
}
}
public SparseArray<BaseItemProvider> getItemProviders() {
return mItemProviders;
}
}
package com.aliyun.svideo.common.bottomnavigationbar;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.aliyun.svideo.common.R;
import java.util.ArrayList;
import java.util.List;
/**
* 自定义底部导航栏
*/
public class BottomNavigationBar extends LinearLayout implements View.OnClickListener {
private IBnbItemSelectListener bnbItemSelectListener;
private IBnbItemDoubleClickListener bnbItemDoubleClickListener;
private List<BottomNavigationEntity> entities = new ArrayList<>();
//这里是-1主要是为了第一次比较
private int mCurrentPosition = -1;
//选中的color
private int mTextSelectedColor;
//未选中的color
private int mTextUnSelectedColor;
//单个布局
private int mItemLayout;
//是否需要缩放动画
private boolean isAnim;
//缩放的比例
private float scaleRatio;
private static final String DEFAULT_SELECTED_COLOR = "#000000";
private static final String DEFAULT_UNSELECTED_COLOR = "#999999";
public BottomNavigationBar(Context context) {
this(context, null);
}
public BottomNavigationBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BottomNavigationBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, 0);
init(context, attrs);
}
public void setEntities(List<BottomNavigationEntity> list) {
entities.clear();
entities.addAll(list);
addItems();
}
/**
* 初始化
*/
private void init(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.BottomNavigationBar);
mTextSelectedColor = array.getColor(R.styleable.BottomNavigationBar_bnb_selectedColor, Color.parseColor(DEFAULT_SELECTED_COLOR));
mTextUnSelectedColor = array.getColor(R.styleable.BottomNavigationBar_bnb_unSelectedColor, Color.parseColor(DEFAULT_UNSELECTED_COLOR));
isAnim = array.getBoolean(R.styleable.BottomNavigationBar_bnb_anim, false);
scaleRatio = array.getFloat(R.styleable.BottomNavigationBar_bnb_scale_ratio, 1.1f);
mItemLayout = array.getResourceId(R.styleable.BottomNavigationBar_bnb_layoutId, -1);
array.recycle();
}
/**
* 添加item
*/
private void addItems() {
if (entities.isEmpty()) {
return;
}
LayoutParams params = new LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT);
params.weight = 1;
BottomNavigationItemView item;
for (int i = 0; i < entities.size(); i++) {
BottomNavigationEntity entity = entities.get(i);
item = new BottomNavigationItemView(getContext());
item.setLayoutId(mItemLayout);
item.setAnim(isAnim);
item.setScaleRatio(scaleRatio);
item.setBottomNavigationEntity(entity);
item.setTextSelectedColor(mTextSelectedColor);
item.setTextUnSelectedColor(mTextUnSelectedColor);
item.setTag(i);
addView(item, params);
item.setOnClickListener(this);
item.setDefaultState();
}
}
@Override
public void onClick(View view) {
int position = (int) view.getTag();
if (position == mCurrentPosition && bnbItemDoubleClickListener != null) {
bnbItemDoubleClickListener.onBnbItemDoubleClick(position);
return;
}
if (position != mCurrentPosition) {
setCurrentPosition(position);
}
}
public void setBnbItemSelectListener(IBnbItemSelectListener listener) {
this.bnbItemSelectListener = listener;
}
public void setBnbItemDoubleClickListener(IBnbItemDoubleClickListener listener) {
this.bnbItemDoubleClickListener = listener;
}
/**
* 设置当前选中位置
*
* @param position 当前选中的item位置索引
*/
public void setCurrentPosition(int position) {
int count = getChildCount();
if (count == 0 || position > count) {
return;
}
if (position == mCurrentPosition) {
return;
}
BottomNavigationItemView lastItem = (BottomNavigationItemView) getChildAt(mCurrentPosition);
BottomNavigationItemView currentItem = (BottomNavigationItemView) getChildAt(position);
if (lastItem != null) {
lastItem.setSelected(false);
}
if (currentItem != null) {
currentItem.setSelected(true);
}
mCurrentPosition = position;
if (bnbItemSelectListener != null) {
bnbItemSelectListener.onBnbItemSelect(position);
}
}
/**
* 刷新的目的是:
* 1.更新budge
* 2.后续添加功能
*
* @param index 刷新index
*/
public void refreshItem(int index) {
if (index < 0) {
return;
}
if (index >= getChildCount()) {
return;
}
BottomNavigationItemView itemView = (BottomNavigationItemView) getChildAt(index);
itemView.refresh();
}
/**
* 设置是否开启切换动画
*
* @param anim
*/
public void setAnim(boolean anim) {
isAnim = anim;
}
public interface IBnbItemSelectListener {
void onBnbItemSelect(int position);
}
public interface IBnbItemDoubleClickListener {
void onBnbItemDoubleClick(int position);
}
}
package com.aliyun.svideo.common.bottomnavigationbar;
/**
* 状态栏Item实体类
*/
public class BottomNavigationEntity {
private String text;
private int selectedIcon;
private int unSelectIcon;
private int badgeNum;
//need text
public BottomNavigationEntity(String text, int unSelectIcon, int selectedIcon) {
this.text = text;
this.unSelectIcon = unSelectIcon;
this.selectedIcon = selectedIcon;
}
//need text
public BottomNavigationEntity(String text, int unSelectIcon, int selectedIcon, int badgeNum) {
this.text = text;
this.unSelectIcon = unSelectIcon;
this.selectedIcon = selectedIcon;
this.badgeNum = badgeNum;
}
//do not need text
public BottomNavigationEntity(int unSelectIcon, int selectedIcon) {
this.unSelectIcon = unSelectIcon;
this.selectedIcon = selectedIcon;
}
//do not need text
public BottomNavigationEntity(int unSelectIcon, int selectedIcon, int badgeNum) {
this.unSelectIcon = unSelectIcon;
this.selectedIcon = selectedIcon;
this.badgeNum = badgeNum;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getSelectedIcon() {
return selectedIcon;
}
public void setSelectedIcon(int selectedIcon) {
this.selectedIcon = selectedIcon;
}
public int getUnSelectIcon() {
return unSelectIcon;
}
public void setUnSelectIcon(int unSelectIcon) {
this.unSelectIcon = unSelectIcon;
}
public int getBadgeNum() {
return badgeNum;
}
public void setBadgeNum(int badgeNum) {
this.badgeNum = badgeNum;
}
}
package com.aliyun.svideo.common.bottomnavigationbar;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.aliyun.svideo.common.R;
/**
* BottomNavigationItemView
*/
class BottomNavigationItemView extends LinearLayout {
private BottomNavigationEntity mBottomNavigationEntity;
private int mTextSelectedColor;
private int mTextUnSelectedColor;
private ImageView mItemIcon;
private TextView mItemText;
private TextView mItemBadge;
private boolean isAnim;
private float scaleRatio;
private int mLayoutId;
private static final float SCALE_MAX = 1.1f;
protected BottomNavigationItemView(Context context) {
this(context, null);
}
protected BottomNavigationItemView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
protected BottomNavigationItemView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setOrientation(VERTICAL);
setGravity(Gravity.CENTER);
}
protected void setScaleRatio(float scaleRatio) {
this.scaleRatio = Math.abs(scaleRatio);
}
/*unused*/
public float getScaleRatio() {
return scaleRatio;
}
protected void setAnim(boolean anim) {
isAnim = anim;
}
/**
* //set item layout
*
* @param layoutId 布局ID
*/
protected void setLayoutId(int layoutId) {
mLayoutId = layoutId;
LayoutInflater.from(getContext()).inflate(mLayoutId, this, true);
mItemIcon = findViewById(R.id.bnb_item_icon);
mItemText = findViewById(R.id.bnb_item_text);
mItemBadge = findViewById(R.id.bnb_item_badge);
}
/*unused*/
public boolean isAnim() {
return isAnim;
}
/**
* 设置
*/
protected void setBottomNavigationEntity(BottomNavigationEntity bottomNavigationEntity) {
mBottomNavigationEntity = bottomNavigationEntity;
setDefaultState();
}
protected void setTextSelectedColor(int textSelectedColor) {
this.mTextSelectedColor = textSelectedColor;
}
protected void setTextUnSelectedColor(int textUnSelectedColor) {
this.mTextUnSelectedColor = textUnSelectedColor;
}
@Override
public void setSelected(boolean selected) {
super.setSelected(selected);
rendingItemText(selected);
rendingItemIcon(selected);
if (isAnim) {
if (selected) {
scale(1f, scaleRatio > SCALE_MAX ? scaleRatio : SCALE_MAX);
} else {
scale(scaleRatio > SCALE_MAX ? scaleRatio : SCALE_MAX, 1f);
}
}
}
/**
* 设置为初始状态
* 默认未选中
*/
protected void setDefaultState() {
rendingItemText(false);
rendingItemIcon(false);
rendingItemBadge();
}
/**
* 目前刷新只是刷新badge
*/
protected void refresh() {
rendingItemBadge();
}
/**
* rendind ICON only
*/
private void rendingItemText(boolean select) {
if (mItemText == null || mBottomNavigationEntity == null) {
return;
}
String text = mBottomNavigationEntity.getText();
if (TextUtils.isEmpty(text)) {
mItemText.setVisibility(GONE);
} else {
mItemText.setText(text);
mItemText.setVisibility(View.VISIBLE);
if (select) {
mItemText.setTextColor(mTextSelectedColor);
} else {
mItemText.setTextColor(mTextUnSelectedColor);
}
}
}
private void rendingItemIcon(boolean select) {
if (mItemIcon == null || mBottomNavigationEntity == null) {
return;
}
if (select) {
mItemIcon.setImageResource(mBottomNavigationEntity.getSelectedIcon());
} else {
mItemIcon.setImageResource(mBottomNavigationEntity.getUnSelectIcon());
}
}
@SuppressLint("SetTextI18n")
private void rendingItemBadge() {
if (mItemBadge == null || mBottomNavigationEntity == null) {
return;
}
int num = mBottomNavigationEntity.getBadgeNum();
if (num > 0) {
if (num < 99) {
mItemBadge.setText(String.valueOf(num));
} else {
mItemBadge.setText("99+");
}
mItemBadge.setVisibility(VISIBLE);
} else {
mItemBadge.setVisibility(INVISIBLE);
}
}
private ValueAnimator valueAnimator;
private void scale(float from, float to) {
valueAnimator = ValueAnimator.ofFloat(from, to);
valueAnimator.setDuration(200);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float value = (float) valueAnimator.getAnimatedValue();
setScaleX(value);
setScaleY(value);
}
});
valueAnimator.start();
}
@Override
protected void onDetachedFromWindow() {
if (null != valueAnimator) {
valueAnimator.cancel();
}
super.onDetachedFromWindow();
}
}
package com.aliyun.svideo.common.okhttp;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.aliyun.svideo.common.okhttp.interceptor.LoggingIntcepetor;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
/**
* okhttp简易封装
*/
public class AlivcOkHttpClient {
private static AlivcOkHttpClient alivcOkHttpClient;
private OkHttpClient okHttpClient;
private OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder().addNetworkInterceptor(new LoggingIntcepetor());
private Handler handler;
private AlivcOkHttpClient() {
handler = new Handler(Looper.getMainLooper());
build();
}
public static AlivcOkHttpClient getInstance() {
if (alivcOkHttpClient == null) {
synchronized (AlivcOkHttpClient.class) {
if (alivcOkHttpClient == null) {
alivcOkHttpClient = new AlivcOkHttpClient();
}
}
}
return alivcOkHttpClient;
}
private void build() {
okHttpBuilder.connectTimeout(10, TimeUnit.SECONDS);
okHttpBuilder.writeTimeout(10, TimeUnit.SECONDS);
okHttpBuilder.readTimeout(10, TimeUnit.SECONDS);
okHttpClient = okHttpBuilder.build();
}
class StringCallBack implements Callback {
private HttpCallBack httpCallBack;
private Request request;
public StringCallBack(Request request, HttpCallBack httpCallBack) {
this.request = request;
this.httpCallBack = httpCallBack;
}
@Override
public void onFailure(Call call, IOException e) {
final IOException fe = e;
if (httpCallBack != null) {
handler.post(new Runnable() {
@Override
public void run() {
httpCallBack.onError(request, fe);
}
});
}
}
@Override
public void onResponse(final Call call, okhttp3.Response response) throws IOException {
final String result = response.body().string();
try {
JSONObject jsonObject = new JSONObject(result);
if ("200".equals(jsonObject.getString("code"))) {
if (httpCallBack != null) {
handler.post(new Runnable() {
@Override
public void run() {
httpCallBack.onSuccess(request, result);
}
});
} else {
handler.post(new Runnable() {
@Override
public void run() {
httpCallBack.onError(request, new IOException("json error"));
}
});
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
/**
* 构建POS请求的参数体。
*
* @return 组装参数后的FormBody。
*/
public FormBody formBody(Map<String, String> param) {
FormBody.Builder builder = new FormBody.Builder();
if (param != null) {
Set<String> keys = param.keySet();
if (!keys.isEmpty()) {
for (String key : keys) {
String value = param.get(key);
if (value != null) {
builder.add(key, value);
}
}
}
}
return builder.build();
}
/**
* 当GET请求携带参数的时候,将参数以key=value的形式拼装到GET请求URL的后面,并且中间以?符号隔开。
*
* @return 携带参数的URL请求地址。
*/
public String urlWithParam(String url, Map<String, String> params) {
if (params != null) {
Set<String> keys = params.keySet();
if (!keys.isEmpty()) {
StringBuilder paramsBuilder = new StringBuilder();
boolean needAnd = false;
for (String key : keys) {
if (needAnd) {
paramsBuilder.append("&");
}
paramsBuilder.append(key).append("=").append(params.get(key));
needAnd = true;
}
return url + "?" + paramsBuilder.toString();
}
}
return url;
}
public void get(String url, HttpCallBack httpCallBack) {
Request request = new Request.Builder().url(url).build();
okHttpClient.newCall(request).enqueue(new StringCallBack(request, httpCallBack));
}
/**
* 带参数带get请求
*/
public void get(String url, HashMap<String, String> params, HttpCallBack httpCallBack) {
Request request = new Request.Builder().url(urlWithParam(url, params)).build();
okHttpClient.newCall(request).enqueue(new StringCallBack(request, httpCallBack));
}
/**
* post请求
*/
public void post(String url, Map<String, String> params, HttpCallBack httpCallBack) {
Request request = new Request.Builder().url(url).post(formBody(params)).build();
okHttpClient.newCall(request).enqueue(new StringCallBack(request, httpCallBack));
}
public interface HttpCallBack {
/**
* 错误回调
*/
void onError(Request request, IOException e);
/**
* 成功回调
*/
void onSuccess(Request request, String result);
}
}
\ No newline at end of file
package com.aliyun.svideo.common.okhttp.interceptor;
import android.util.Log;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* OkHttp网络请求日志拦截器,通过日志记录OkHttp所有请求以及响应的细节。
*/
public class LoggingIntcepetor implements Interceptor {
private final String TAG = getClass().getSimpleName();
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Log.d(TAG, "Sending request: " + request.url() + "\n" + request.headers());
Response response = chain.proceed(request);
long t2 = System.nanoTime();
Log.d(TAG, "Received response for " + response.request().url() + " in "
+ (t2 - t1) / 1e6 + "ms\n" + response.headers());
return response;
}
}
package com.aliyun.svideo.common.utils;
import android.annotation.SuppressLint;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 时长、时间转换工具类
*/
public class DateTimeUtils {
/**
* 格式化毫秒数为 xx:xx:xx这样的时间格式。
*
* @param ms 毫秒数
* @return 格式化后的字符串
*/
public static String formatMs(long ms) {
int seconds = (int) (ms / 1000);
int finalSec = seconds % 60;
int finalMin = seconds / 60 % 60;
int finalHour = seconds / 3600;
StringBuilder msBuilder = new StringBuilder("");
if (finalHour > 9) {
msBuilder.append(finalHour).append(":");
} else if (finalHour > 0) {
msBuilder.append("0").append(finalHour).append(":");
}
if (finalMin > 9) {
msBuilder.append(finalMin).append(":");
} else if (finalMin > 0) {
msBuilder.append("0").append(finalMin).append(":");
} else {
msBuilder.append("00").append(":");
}
if (finalSec > 9) {
msBuilder.append(finalSec);
} else if (finalSec > 0) {
msBuilder.append("0").append(finalSec);
} else {
msBuilder.append("00");
}
return msBuilder.toString();
}
/**
* 将毫秒转化成固定格式的时间
* 时间格式: yyyy-MM-dd-HHmmssSSS
*
* @param millisecond 时间毫秒
* @return 时间格式: yyyy-MM-dd-HHmmssSSS
*/
public static String getDateTimeFromMillisecond(Long millisecond) {
@SuppressLint("SimpleDateFormat")
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HHmmssSSS");
Date date = new Date(millisecond);
return simpleDateFormat.format(date);
}
}
package com.aliyun.svideo.common.utils;
import android.content.Context;
/*
* Copyright (C) 2010-2018 Alibaba Group Holding Limited.
* 手机分辨率工具类
*/
public class DensityUtils {
/**
* 根据手机的分辨率从 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);
}
/**
* 根据手机的分辨率从 sp转换px(像素)
*/
public static int sp2px(Context context, int spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
}
package com.aliyun.svideo.common.utils;
import android.util.Log;
import androidx.annotation.NonNull;
/**
* 限制快速点击多次触发的工具类
*
* 注意:如果第一次点击涉及到阻塞主线程/主线程耗时的情况则FastClickUtil的判断并不靠谱
*/
public class FastClickUtil {
private static final String TAG = FastClickUtil.class.getSimpleName();
/**
* 两次点击间隔不能少于300ms
*/
private static final int MIN_DELAY_TIME = 500;
/**
* activity两次点击间隔不能少于800ms
*/
private static final int MIN_DELAY_TIME_ACTIVITY = 800;
private static long sLastClickTime;
private static String sLastActivitySimpleName;
public static boolean isFastClick() {
long currentClickTime = System.currentTimeMillis();
boolean isFastClick = (currentClickTime - sLastClickTime) <= MIN_DELAY_TIME;
Log.e(TAG, "log_common_FastClickUtil : " + (currentClickTime - sLastClickTime));
sLastClickTime = currentClickTime;
return isFastClick;
}
/**
* fix连续点击弹出多个activity
* 1.设置android:launchMode="singleTop"在这个场景下并不管用
* 2.部分手机可能因为activity的阻塞耗时不同会导致计算的间隔超出500ms,这里定位800毫秒能处理绝大部分的手机和情况
* 3.通过记录activitySimpleName,避免出现用户熟练连续进入多个页面的时候需要等待
*
* @param activitySimpleName Activity.class.getSimpleName()
* @return boolean
*/
public static boolean isFastClickActivity(@NonNull String activitySimpleName) {
long currentClickTime = System.currentTimeMillis();
boolean isFastClick = (currentClickTime - sLastClickTime) <= MIN_DELAY_TIME_ACTIVITY;
sLastClickTime = currentClickTime;
if (!activitySimpleName.equals(sLastActivitySimpleName)) {
//如果两次的activity不是同一个,不是快速点击
isFastClick = false;
sLastActivitySimpleName = activitySimpleName;
}
return isFastClick;
}
}
package com.aliyun.svideo.common.utils.image;
/**
* @author cross_ly
* @date 2018/12/06
* <p>描述: imageLoader listener
*/
public interface ImageLoaderRequestListener<R> {
boolean onLoadFailed(String exception, boolean isFirstResource);
boolean onResourceReady(R resource, boolean isFirstResource);
}
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_longAnimTime"
android:fromYDelta="100%p"
android:toYDelta="0" />
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment