maven内容提交

This commit is contained in:
姜珂 2025-06-30 13:49:41 +08:00
parent 1fc8978e1e
commit 6e83eb74a2
822 changed files with 33614 additions and 78 deletions

49
.gitignore vendored
View File

@ -1,35 +1,16 @@
# ---> Android
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Log/OS Files
*.log
# Android Studio generated files and folders
captures/
.externalNativeBuild/
.cxx/
*.apk
output.json
# IntelliJ
*.iml
.idea/
misc.xml
deploymentTargetDropDown.xml
render.experimental.xml
# Keystore files
*.jks
*.keystore
# Google Services (e.g. APIs or Firebase)
google-services.json
# Android Profiling
*.hprof
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
/.idea/

1
BaseLibrary/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

60
BaseLibrary/build.gradle Normal file
View File

@ -0,0 +1,60 @@
apply plugin: 'com.android.library'
android {
namespace "com.tfq.library"
compileSdkVersion 34
defaultConfig {
minSdkVersion 21
targetSdkVersion 34
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
// api 'androidx.constraintlayout:constraintlayout:1.1.3'
api 'androidx.appcompat:appcompat:1.7.0'
api 'com.google.android.material:material:1.11.0'
// api 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
// api 'androidx.core:core-ktx:1.10.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
//
api 'com.gyf.immersionbar:immersionbar:3.0.0-beta05'
//
api 'com.github.getActivity:XXPermissions:18.63'
api 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.28'
api 'androidx.activity:activity:1.8.0'
api 'com.google.code.gson:gson:2.10.1'
api 'com.alibaba:fastjson:1.2.55'
//
api 'com.squareup.okhttp3:okhttp:3.4.2'
api 'com.squareup.okhttp3:logging-interceptor:3.5.0'
//
api 'com.github.bumptech.glide:glide:3.7.0'
api 'com.google.android:flexbox:0.3.1'
api 'com.github.bumptech.glide:glide:4.14.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.14.1'
// Glide图形转换工具
api 'jp.wasabeef:glide-transformations:2.0.1'
// https://github.com/getActivity/Toaster
api 'com.github.getActivity:Toaster:12.8'
//
api 'com.github.centerzx:ShapeBlurView:1.0.5'
}

View File

21
BaseLibrary/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# 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

View File

@ -0,0 +1,26 @@
package com.tfq.library;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.tfq.library.test", appContext.getPackageName());
}
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:supportsRtl="true">
</application>
</manifest>

View File

@ -0,0 +1,30 @@
package com.tfq.library.adapter;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.List;
public class MyFragmentStateAdapter extends FragmentStateAdapter {
private final List<Fragment> mFragmentList;
public MyFragmentStateAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle, List<Fragment> fragments) {
super(fragmentManager, lifecycle);
mFragmentList = fragments;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return mFragmentList.get(position);
}
@Override
public int getItemCount() {
return mFragmentList.size();
}
}

View File

@ -0,0 +1,33 @@
package com.tfq.library.adapter;
import android.view.ViewGroup;
import java.util.List;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
public class TabFragmentPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mlist;
public TabFragmentPagerAdapter(FragmentManager fm, List<Fragment> list) {
super(fm);
this.mlist = list;
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
}
@Override
public Fragment getItem(int arg0) {
return mlist.get(arg0);//显示第几个页面
}
@Override
public int getCount() {
return mlist.size();//有几个页面
}
}

View File

@ -0,0 +1,51 @@
package com.tfq.library.app;
public class BaseConstants {
public static final int URL_REQUEST_ERROR = 401;
public static boolean BASE_APP_DEBUG_PRINT;
public static String APP_ID = "";
public static String CSJ_ID = "";
public static String APP_NAME = "";
public static String CHANNEL = "";
public static String csjIdFeed1;
public static String csjIdFeed2;
public static boolean _isShow;
// 1.开屏 2.激励视频 3.信息流 4.插全屏 5.banner 6.draw信息流
public static boolean AD_SPLASH = false;//开屏广告
public static boolean AD_REWARD = false;//激励视频
public static boolean AD_CQP = false;//插全屏广告
public static boolean AD_NATIVE = false;//原生信息流广告
public static boolean AD_BANNER = false;//banner广告
public static boolean AD_DRAW = false;//draw信息流广告
public static int ADV_Wait = 60;//插全屏两个相差时间
public static boolean adv_csj = true;//穿山甲正常
public static boolean NO_AD = true;//穿山甲正常
public static long request_splash_time = 30;
public static boolean AD_Switch_Requested = false;//请求过广告开关
public static String CODE_AD_SPLASH;
public static String CODE_AD_CQP;
public static String CODE_AD_FEED1;
public static String CODE_AD_FEED2;
public static String CODE_AD_FEED3;
public static String CODE_AD_BANNER;
public static String CODE_AD_REWARD;
public static String CODE_AD_DRAW;
public static boolean PRE_AD = true;
public static int appSplash;
/**
* 底部导航栏颜色 默认白色
*/
public static String navigationBarColor = "#FFFFFF";
/**
* 自定义dialog使用的layout类型
*/
public static int dialog_layout = 2;
}

View File

@ -0,0 +1,8 @@
package com.tfq.library.app;
import android.app.Application;
public interface IConstituteApp {
//初始化
void onCreate(Application application);
}

View File

@ -0,0 +1,116 @@
package com.tfq.library.app;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import com.hjq.toast.Toaster;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Created by Administrator on 2016/10/28.
*/
public class LibraryApp implements IConstituteApp {
public static Activity activityTop;
private static Context mContext;
private static LibraryApp instance;
public Application application;
public static LibraryApp getInstance() {
return instance;
}
public static Context getContext() {
return mContext;
}
public static Activity getActivityTop() {
return activityTop;
}
public static String getChannel() {
try {
PackageManager pm = mContext.getPackageManager();
ApplicationInfo appInfo = pm.getApplicationInfo(mContext.getPackageName(), PackageManager.GET_META_DATA);
return appInfo.metaData.getString("UMENG_CHANNEL");
} catch (PackageManager.NameNotFoundException ignored) {
}
return "other";
}
public static String getJson(String fileName, Context context) {
StringBuilder stringBuilder = new StringBuilder();
try {
InputStream is = context.getAssets().open(fileName);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
@Override
public void onCreate(Application application) {
mContext = application.getApplicationContext();
instance = this;
this.application = application;
register();
// 初始化 Toast 框架
Toaster.init(application);
}
private void register() {
application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) {
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
activityTop = activity;
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) {
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
}
});
}
}

View File

@ -0,0 +1,85 @@
package com.tfq.library.base;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import com.gyf.immersionbar.ImmersionBar;
import com.tfq.library.app.BaseConstants;
import com.tfq.library.utils.AppUtil;
import androidx.annotation.LayoutRes;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
/**
* Created by JiangKe on 2025/02/20.
*/
public abstract class BaseActivity extends AppCompatActivity {
/****************************abstract area*************************************/
@LayoutRes
protected abstract int getLayoutId();
/**
* 初始化零件
*/
protected abstract void initView();
protected abstract void initData(Bundle savedInstanceState);
/**
* 初始化点击事件
*/
protected void initClick() {
}
/**
* 初始化沉浸式
*/
protected void initImmersionBar() {
}
/**
* 逻辑使用区
*/
protected void processLogic() {
}
private boolean statusBarDarkFont;
public void setStatusBarDarkFont(boolean statusBarDarkFont){
this.statusBarDarkFont = statusBarDarkFont;
}
/*************************lifecycle area*****************************************************/
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
initView();
initData(savedInstanceState);
initClick();
processLogic();
ImmersionBar.with((Activity) this)
.transparentStatusBar() //不写也可以默认就是透明色
.statusBarDarkFont(statusBarDarkFont)
.navigationBarColor(BaseConstants.navigationBarColor)
// .keyboardEnable(true)
.init();
initImmersionBar();
}
/**************************used method area*******************************************/
protected void startActivity(Class<? extends AppCompatActivity> activity) {
Intent intent = new Intent(this, activity);
startActivity(intent);
}
@Override
protected void onPause() {
super.onPause();
AppUtil.closeKeyBoard(this);
}
}

View File

@ -0,0 +1,177 @@
package com.tfq.library.base;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.hjq.permissions.OnPermissionCallback;
import com.hjq.permissions.XXPermissions;
import com.tfq.library.utils.PermissionDialog;
import java.util.List;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
/**
* Created by JiangKe on 2025/02/20.
*/
public abstract class BaseFragment extends Fragment {
private View root = null;
private String content = "当前操作需要您授权相应权限,否则可能无法正常使用此功能";
@LayoutRes
protected abstract int getLayoutId();
/**
* 初始化零件
*/
protected abstract void initView();
protected abstract void initData(Bundle savedInstanceState);
/**
* 初始化点击事件
*/
protected void initClick() {
}
/**
* 逻辑使用区
*/
protected void processLogic() {
}
/**
* 权限请求
*/
protected void requestPermission(String[] per, Listener listener) {
requestPermission(per, content, listener);
}
protected void requestPermission(String[] per, String content, Listener listener) {
if (!TextUtils.isEmpty(content)) {
this.content = content;
}
requestPermission(per, content, true, false, listener);
}
protected void requestPermission(String[] per, String content, boolean show_doNotAskAgain, Listener listener) {
if (!TextUtils.isEmpty(content)) {
this.content = content;
}
requestPermission(per, content, true, show_doNotAskAgain, listener);
}
protected void requestPermission(String[] per, String content, boolean req_permission, boolean show_doNotAskAgain, Listener listener) {
if (!TextUtils.isEmpty(content)) {
this.content = content;
}
requestPermission(per, req_permission, show_doNotAskAgain, listener);
}
/**
* 申请权限
*
* @param permission 权限集合
* @param req_permission 申请权限之前是否提示默认false不提示
* @param show_doNotAskAgain 权限申请失败是否调整到设置页,默认false不关闭
* @param listener 监听
*/
protected void requestPermission(String[] permission, boolean req_permission, boolean show_doNotAskAgain, Listener listener) {
if (!req_permission) {//不弹窗直接申请权限
requestPermission(permission, show_doNotAskAgain, listener);
} else {//先弹窗,再去申请
PermissionDialog permissionDialog = new PermissionDialog(getActivity(), "request_per", "权限申请"
, content, new PermissionDialog.Listener_Result() {
@Override
public void success(boolean b) {
if (b) {//同意申请权限,去申请
requestPermission(permission, show_doNotAskAgain, listener);
} else {//不同意申请权限
}
}
});
permissionDialog.setCanceledOnTouchOutside(false);
permissionDialog.setCancelable(false);
permissionDialog.show();
}
}
private void requestPermission(String[] permission, boolean show_doNotAskAgain, Listener listener) {
XXPermissions.with(getActivity())
.permission(permission)
.request(new OnPermissionCallback() {
@Override
public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
if (!allGranted) {
//获取部分权限成功但部分权限未正常授予
return;
}
listener.success();
}
@Override
public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
if (show_doNotAskAgain) {
if (doNotAskAgain) {
//如果是被永久拒绝就跳转到应用权限系统设置页面
XXPermissions.startPermissionActivity(getActivity(), permissions);
} else {
//获取权限失败
}
}
}
});
}
/******************************lifecycle area*****************************************/
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
int resId = getLayoutId();
root = inflater.inflate(resId, container, false);
return root;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initView();
initData(savedInstanceState);
initClick();
processLogic();
}
@Override
public void onDetach() {
super.onDetach();
}
/**************************公共类*******************************************/
public String getName() {
return getClass().getName();
}
protected <VT> VT findViewBy_Id(int id) {
if (root == null) {
return null;
}
return (VT) root.findViewById(id);
}
public interface Listener {
void success();
}
}

View File

@ -0,0 +1,177 @@
package com.tfq.library.utils;
import static androidx.core.content.ContextCompat.getSystemService;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
import android.text.InputFilter;
import android.text.InputType;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import com.tfq.library.R;
public class AddTextDialog {
boolean isClick = false;
private String name;
private String title;
private String type;
private Context mContext;
private Listener listener;
private ListenerFail listenerFail;
private AlertDialog dialog;
public AddTextDialog(Context context, Listener listener) {
this.mContext = context;
this.listener = listener;
}
public AddTextDialog(Context context, ListenerFail listenerFail) {
this.mContext = context;
this.listenerFail = listenerFail;
}
public AddTextDialog(Context context, String name, Listener listener) {
this.mContext = context;
this.listener = listener;
this.name = name;
}
public AddTextDialog(Context context, String name, String title, String type, Listener listener) {
this.mContext = context;
this.listener = listener;
this.name = name;
this.title = title;
this.type = type;
}
@SuppressLint("ClickableViewAccessibility")
public void show() {
// 创建编辑框视图
LayoutInflater inflater = LayoutInflater.from(mContext);
View inputView = inflater.inflate(R.layout.dialog_add_text_layout, null);
EditText et_text = inputView.findViewById(R.id.et_name);
if (!TextUtils.isEmpty(name)) {
et_text.setText(name);
et_text.setSelection(et_text.getText().toString().length());
}
if (!TextUtils.isEmpty(type) && type.equals("budgets")){
// 设置输入类型为带小数点的数字
et_text.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
// 添加输入过滤器
et_text.setFilters(new InputFilter[]{new DecimalInputFilter()});
// 焦点丢失时格式化显示
et_text.setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
String text = et_text.getText().toString();
if (!text.isEmpty()) {
try {
double value = Double.parseDouble(text);
et_text.setText(String.format("%.2f", value));
} catch (NumberFormatException e) {
et_text.setText("");
}
}
}
});
}else if (!TextUtils.isEmpty(type) && type.equals("nickname")){
et_text.setFilters(new InputFilter[]{new InputFilter.LengthFilter(20)});
}
et_text.requestFocus();
et_text.postDelayed(() -> {
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
// 强制显示软键盘
imm.showSoftInput(et_text, InputMethodManager.SHOW_FORCED);
}, 100); // 延迟200ms等待布局渲染完成
// 创建对话框
dialog = new AlertDialog.Builder(mContext)
.setTitle(TextUtils.isEmpty(title) ? "创建记账项目" : title)
.setView(inputView)
.setPositiveButton("创建", null)
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
AppUtil.closeKeyBoard(et_text);
if (listenerFail != null) {
listenerFail.callCancel();
}
}
})
.create();
// 设置对话框所属的Activity
if (mContext instanceof Activity) {
dialog.setOwnerActivity((Activity) mContext);
}
// 使用工具类设置模糊背景和圆角
DialogUtils.setBlurBackground(dialog);
dialog.show();
Button confirmButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
confirmButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String trim = et_text.getText().toString().trim();
if (TextUtils.isEmpty(trim)) {
if (TextUtils.isEmpty(type)) {
ToasterUtil.show("请先输入记账名称");
} else if (type.equals("budgets")){
ToasterUtil.show("请先输入本月预算金额");
}else if (type.equals("nickname")){
ToasterUtil.show("用户昵称不能为空");
}
} else {
if (listener != null && !isClick) {
AppUtil.closeKeyBoard(et_text);
isClick = true;
listener.success(trim);
dialog.dismiss();
}
if (listenerFail != null && !isClick) {
AppUtil.closeKeyBoard(et_text);
isClick = true;
listenerFail.success(trim);
dialog.dismiss();
}
}
}
});
dialog.setOnCancelListener(dialog -> {
new Handler().postDelayed(() -> {
InputMethodManager imm2 = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
imm2.hideSoftInputFromWindow(((Activity)mContext).getWindow().getDecorView().getWindowToken(), 0);
}, 100); // 延迟100ms避免窗口令牌销毁
if (listenerFail != null) {
listenerFail.callCancel();
}
});
}
public interface Listener {
void success(String name);
}
public interface ListenerFail {
void success(String name);
void callCancel();
}
}

View File

@ -0,0 +1,146 @@
package com.tfq.library.utils;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import com.tfq.library.utils.LogK;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
public class AppSigning {
public final static String MD5 = "MD5";
public final static String SHA1 = "SHA1";
public final static String SHA256 = "SHA256";
private static final HashMap<String, ArrayList<String>> mSignMap = new HashMap<>();
/**
* 返回一个签名的对应类型的字符串
*
* @param context
* @param type
* @return 因为一个安装包可以被多个签名文件签名所以返回一个签名信息的list
*/
public static ArrayList<String> getSignInfo(Context context, String type) {
if (context == null || type == null) {
return null;
}
String packageName = context.getPackageName();
if (packageName == null) {
return null;
}
if (mSignMap.get(type) != null) {
return mSignMap.get(type);
}
ArrayList<String> mList = new ArrayList<String>();
try {
Signature[] signs = getSignatures(context, packageName);
for (Signature sig : signs) {
String tmp = "error!";
if (MD5.equals(type)) {
tmp = getSignatureByteString(sig, MD5);
} else if (SHA1.equals(type)) {
tmp = getSignatureByteString(sig, SHA1);
} else if (SHA256.equals(type)) {
tmp = getSignatureByteString(sig, SHA256);
}
mList.add(tmp);
}
} catch (Exception e) {
LogK.e(e.toString());
}
mSignMap.put(type, mList);
return mList;
}
/**
* 获取签名sha1值
*
* @param context
* @return
*/
public static String getSha1(Context context) {
String res = "";
ArrayList<String> mlist = getSignInfo(context, SHA1);
if (mlist != null && mlist.size() != 0) {
res = mlist.get(0);
}
return res;
}
/**
* 返回对应包的签名信息
*
* @param context
* @param packageName
* @return
*/
private static Signature[] getSignatures(Context context, String packageName) {
PackageInfo packageInfo = null;
try {
packageInfo = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
return packageInfo.signatures;
} catch (Exception e) {
LogK.e(e.toString());
}
return null;
}
/**
* 获取相应的类型的字符串把签名的byte[]信息转换成16进制
*
* @param sig
* @param type
* @return
*/
private static String getSignatureString(Signature sig, String type) {
byte[] hexBytes = sig.toByteArray();
String fingerprint = "error!";
try {
MessageDigest digest = MessageDigest.getInstance(type);
if (digest != null) {
byte[] digestBytes = digest.digest(hexBytes);
StringBuilder sb = new StringBuilder();
for (byte digestByte : digestBytes) {
sb.append((Integer.toHexString((digestByte & 0xFF) | 0x100)).substring(1, 3));
}
fingerprint = sb.toString();
}
} catch (Exception e) {
LogK.e(e.toString());
}
return fingerprint;
}
/**
* 获取相应的类型的字符串把签名的byte[]信息转换成 95:F4:D4:FG 这样的字符串形式
*
* @param sig
* @param type
* @return
*/
private static String getSignatureByteString(Signature sig, String type) {
byte[] hexBytes = sig.toByteArray();
String fingerprint = "error!";
try {
MessageDigest digest = MessageDigest.getInstance(type);
if (digest != null) {
byte[] digestBytes = digest.digest(hexBytes);
StringBuilder sb = new StringBuilder();
for (byte digestByte : digestBytes) {
sb.append(((Integer.toHexString((digestByte & 0xFF) | 0x100)).substring(1, 3)).toUpperCase());
sb.append(":");
}
fingerprint = sb.substring(0, sb.length() - 1);
}
} catch (Exception e) {
LogK.e(e.toString());
}
return fingerprint;
}
}

View File

@ -0,0 +1,722 @@
package com.tfq.library.utils;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.text.TextUtils;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import androidx.core.content.FileProvider;
import com.gyf.immersionbar.BarHide;
import com.gyf.immersionbar.ImmersionBar;
import com.tfq.library.app.LibraryApp;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.lang.reflect.Field;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class AppUtil {
/**
* 获取屏幕分辨率?
*
* @param context
* @return
*/
public static int[] getScreenDispaly(Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
@SuppressWarnings("deprecation") int width = windowManager.getDefaultDisplay().getWidth();
@SuppressWarnings("deprecation") int height = windowManager.getDefaultDisplay().getHeight();
int[] result = {width, height};
return result;
}
/**
* 获取app的名称
*
* @param context
* @return
*/
public static String getAppName(Context context) {
String appName = "";
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
int labelRes = packageInfo.applicationInfo.labelRes;
appName = context.getResources().getString(labelRes);
} catch (Throwable e) {
e.printStackTrace();
}
return appName;
}
/**
* 获取app的名称
*
* @param context
* @return
*/
public static String getAppVersionNameCode(Context context) {
String appCode = "";
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
String versionName = packageInfo.versionName;
String versionCode = packageInfo.versionCode + "";
appCode = "versionName=" + versionName + " versionCode=" + versionCode;
} catch (Throwable e) {
e.printStackTrace();
}
return appCode;
}
/**
* 获取app的名称
*
* @param context
* @return
*/
public static String getPackageName(Context context) {
String name = "";
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
name = packageInfo.applicationInfo.packageName;
} catch (Throwable e) {
e.printStackTrace();
}
return name;
}
/**
* 获取app的名称
*
* @return
*/
public static String getPackageName() {
String name = "";
try {
PackageManager packageManager = LibraryApp.getContext().getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(LibraryApp.getContext().getPackageName(), 0);
name = packageInfo.applicationInfo.packageName;
} catch (Throwable e) {
e.printStackTrace();
}
return name;
}
/**
* @param mContext 上下文
* @param title title
* @param message message
* @param ok 确定按钮
* @param cancel 返回按钮
* @param orNull 是否可以为空false设置为默认title message ok cancel
*/
public static void securitySD(Activity mContext, String title, String message, String ok, String cancel, boolean orNull) {
if (mContext != null) {
mContext.runOnUiThread(new Runnable() {
@Override
public void run() {
String s_title = title;
String s_message = message;
String s_ok = ok;
String s_cancel = cancel;
if (!orNull) {
s_title = "温馨提示";
if (!TextUtils.isEmpty(title)) {
s_title = title;
}
s_message = "请在应用详情页面权限列表进行设置。";
if (!TextUtils.isEmpty(message)) {
s_message = message;
}
s_ok = "确定";
if (!TextUtils.isEmpty(ok)) {
s_ok = ok;
}
s_cancel = "返回";
if (!TextUtils.isEmpty(cancel)) {
s_cancel = cancel;
}
}
AlertDialog alertDialog = new AlertDialog.Builder(mContext).setTitle(s_title).setMessage(s_message).setPositiveButton(s_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).setNegativeButton(s_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).setCancelable(false).create();
alertDialog.show();
}
});
}
}
public static void securitySD(Activity mContext, String title, String message, String ok, String cancel) {
if (mContext != null) {
mContext.runOnUiThread(new Runnable() {
@Override
public void run() {
String s_title = "温馨提示";
if (!TextUtils.isEmpty(title)) {
s_title = title;
}
String s_message = "请在应用详情页面权限列表进行设置。";
if (!TextUtils.isEmpty(message)) {
s_message = message;
}
String s_ok = "确定";
if (!TextUtils.isEmpty(ok)) {
s_ok = ok;
}
String s_cancel = "返回";
if (!TextUtils.isEmpty(cancel)) {
s_cancel = cancel;
}
AlertDialog alertDialog = new AlertDialog.Builder(mContext).setTitle(s_title).setMessage(s_message).setPositiveButton(s_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", mContext.getPackageName(), null));
mContext.startActivity(intent);
}
}).setNegativeButton(s_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).setCancelable(false).create();
alertDialog.show();
}
});
}
}
public static void securitySD(Activity mContext, String title, String message, String ok) {
if (mContext != null) {
mContext.runOnUiThread(new Runnable() {
@Override
public void run() {
String s_title = "温馨提示";
if (!TextUtils.isEmpty(title)) {
s_title = title;
}
String s_message = "";
if (!TextUtils.isEmpty(message)) {
s_message = message;
}
String s_ok = "";
if (!TextUtils.isEmpty(ok)) {
s_ok = ok;
}
AlertDialog alertDialog = new AlertDialog.Builder(mContext).setTitle(s_title).setMessage(s_message).setPositiveButton(s_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mContext.finish();
}
}).setCancelable(false).create();
alertDialog.show();
}
});
}
}
public static void installApk(Context mContext, String downloadApk) {
Intent intent = new Intent(Intent.ACTION_VIEW);
File file = new File(downloadApk);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//这里要注意FileProvider一定要在AndroidManifest中去声明哦
//同时com.mc.mcplatform代表你自己的包名
Uri apkUri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + ".provider", file);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(file);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
}
mContext.startActivity(intent);
}
public static boolean connectStatus(Context context) {
boolean isConnect = true;
try {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
NetworkCapabilities networkCapabilities = manager.getNetworkCapabilities(manager.getActiveNetwork());
if (networkCapabilities != null) {
isConnect = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return isConnect;
}
public static boolean connectStatus() {
boolean isConnect = true;
try {
ConnectivityManager manager = (ConnectivityManager) LibraryApp.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
NetworkCapabilities networkCapabilities = manager.getNetworkCapabilities(manager.getActiveNetwork());
if (networkCapabilities != null) {
isConnect = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return isConnect;
}
public static boolean isRunningForeground(Context mContext) {
try {
ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(mContext.getPackageName())) {
return appProcess.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
}
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return false;
}
public static ActivityInfo[] getAllActivity(Context mContext) {
ActivityInfo[] activities = null;
PackageManager packageManager = mContext.getPackageManager();
PackageInfo packageInfo = null;
try {
packageInfo = packageManager.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
//所有的Activity
activities = packageInfo.activities;
// for (ActivityInfo activity : activities) {
// Class<?> aClass = Class.forName(activity.name);
// }
} catch (Exception e) {
e.printStackTrace();
}
return activities;
}
public static void exitActivity(Context mContext) {
ActivityInfo[] activities = getAllActivity(mContext);
if (activities != null && activities.length > 0) {
for (int i = 0; i < activities.length; i++) {
ActivityInfo activity = activities[i];
String name = activity.name;
LogK.e("mContext.getPackageName()=" + mContext.getPackageName());
if (name.startsWith(mContext.getPackageName())) {
Activity currentActivity = getCurrentActivity(name);
if (currentActivity != null) currentActivity.finish();
LogK.e("name=" + name);
}
}
}
}
private static Activity getCurrentActivity(String name) {
try {
Class activityThreadClass = Class.forName(name);
Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);
Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
activitiesField.setAccessible(true);
Map activities = (Map) activitiesField.get(activityThread);
for (Object activityRecord : activities.values()) {
Class activityRecordClass = activityRecord.getClass();
Field pausedField = activityRecordClass.getDeclaredField("paused");
pausedField.setAccessible(true);
if (!pausedField.getBoolean(activityRecord)) {
Field activityField = activityRecordClass.getDeclaredField("activity");
activityField.setAccessible(true);
Activity activity = (Activity) activityField.get(activityRecord);
return activity;
}
}
return null;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取app的VersionName
*
* @param context
* @return
*/
public static String getAppVersionName(Context context) {
String appVersionName = "1";
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
appVersionName = packageInfo.versionName;
} catch (Throwable e) {
e.printStackTrace();
}
return appVersionName;
}
/**
* 获取app的VersionName
*
* @return
*/
public static String getAppVersionName() {
String appVersionName = "1";
try {
PackageManager packageManager = LibraryApp.getContext().getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(LibraryApp.getContext().getPackageName(), 0);
appVersionName = packageInfo.versionName;
} catch (Throwable e) {
e.printStackTrace();
}
return appVersionName;
}
/**
* 获取app的VersionCode
*
* @param context
* @return
*/
public static String getAppVersionCode(Context context) {
String appVersionCode = "1";
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
appVersionCode = packageInfo.versionCode + "";
} else {
appVersionCode = packageInfo.getLongVersionCode() + "";
}
} catch (Exception e) {
e.printStackTrace();
}
return appVersionCode;
}
/**
* 获取app的VersionCode
*
* @return
*/
public static String getAppVersionCode() {
String appVersionCode = "1";
try {
PackageManager packageManager = LibraryApp.getContext().getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(LibraryApp.getContext().getPackageName(), 0);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
appVersionCode = packageInfo.versionCode + "";
} else {
appVersionCode = packageInfo.getLongVersionCode() + "";
}
} catch (Exception e) {
e.printStackTrace();
}
return appVersionCode;
}
public static boolean regexPhoneNum(String phone) {
String telRegex = "^1[3-9]\\d{9}$";
if (TextUtils.isEmpty(phone)) {
return false;
} else {
return phone.matches(telRegex);
}
}
/**
* 正则是不是纯数字
*
* @param string
* @return
*/
public static boolean regexIsNumber(String string) {
String str = "[0-9]*";
boolean matches = string.matches(str);
return matches;
}
/**
* 判断字符串是否为整数或小数含正负数
* @param input 待检测字符串
* @return true-是数字false-不是数字
*/
public static boolean isNumeric(String input) {
if (input == null || input.isEmpty()) return false;
// 正则解释
// ^-? : 可选负号开头
// \\d+ : 至少一位整数
// (\\.\\d+)?: 可选小数部分
return input.matches("^-?\\d+(\\.\\d+)?$");
}
// 扩展方法区分整数和小数
public static boolean isInteger(String input) {
return input != null && input.matches("^-?\\d+$");
}
public static boolean isDecimal(String input) {
return input != null && input.matches("^-?\\d+\\.\\d+$");
}
public static void getActivityName(Context context) {
Activity activityByContext = getActivityByContext(context);
if (activityByContext != null) {
String localClassName = activityByContext.getLocalClassName();
LogK.e("localClassName=" + localClassName);
}
}
private static Activity getActivityByContext(Context context) {
while (context instanceof ContextWrapper) {
if (context instanceof Activity) {
return (Activity) context;
}
context = ((ContextWrapper) context).getBaseContext();
}
return null;
}
public static String getTopActivityName(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> listTask = activityManager.getRunningTasks(0);
String activityName = "";
if (listTask != null && !listTask.isEmpty()) {
ActivityManager.RunningTaskInfo runningTaskInfo = listTask.get(1);
activityName = runningTaskInfo.topActivity.getClassName();
}
return activityName;
}
public static String getTopActivity(Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> runningTaskInfos = manager.getRunningTasks(1);
if (runningTaskInfos != null) {
return (runningTaskInfos.get(0).topActivity.getClassName());
} else return null;
}
public static String getPublicKey(byte[] signature) {
try {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(signature));
LogK.i("监听2" + " 22");
String publickey = cert.getPublicKey().toString();
LogK.d("-------密码TRACK " + publickey);
// publickey = publickey.substring(publickey.indexOf("modulus:") + 9,publickey.indexOf("\n", publickey.indexOf("modulus:")));
LogK.d("-------密码TRACK " + publickey);
return publickey;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] getSign(Context context) {
PackageManager pm = context.getPackageManager();
List<PackageInfo> apps = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);
Iterator<PackageInfo> iter = apps.iterator();
LogK.i("签名1 " + iter + "");
LogK.i("监听1 " + "----------");
while (iter.hasNext()) {
PackageInfo info = iter.next();
String packageName = info.packageName;
//按包名 取签名
if (packageName.equals(AppUtil.getPackageName(context))) {
LogK.i("监听1 " + info.signatures[0].toByteArray() + "----------");
return info.signatures[0].toByteArray();
}
}
return null;
}
/**
* 格式化时间
*/
public static String stringForTime(int timeMs) {
int totalSeconds = timeMs / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
if (hours > 0) {
return String.format(Locale.getDefault(), "%d:%02d:%02d", hours, minutes, seconds);
} else {
return String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
}
}
/**
* 根据给定的大小返回合适的单位KBMBGB
*
* @param sizeInBytes 字节数
* @return 格式化后的字符串
*/
public static String getSizeInUnit(long sizeInBytes) {
if (sizeInBytes < 1024) {
return sizeInBytes + " B";
} else if (sizeInBytes < 1024 * 1024) {
return String.format("%.2f KB", sizeInBytes / 1024.0);
} else if (sizeInBytes < 1024 * 1024 * 1024) {
return String.format("%.2f MB", sizeInBytes / (1024.0 * 1024.0));
} else {
return String.format("%.2f GB", sizeInBytes / (1024.0 * 1024.0 * 1024.0));
}
}
/**
* 清除缓存
*
* @param context
*/
public static void clearApplicationCache(Context context) {
File cache = context.getCacheDir();
if (cache != null && cache.isDirectory()) {
deleteDir(cache);
}
}
/**
* 执行循环清除
*
* @param dir
* @return
*/
private static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// The directory is now empty so delete it
return dir.delete();
}
/**
* 手机存储百分比
*/
public static void queryStorage(TextView textView) {
StatFs statFs = new StatFs(Environment.getExternalStorageDirectory().getPath());
//存储块总数量
long blockCount = statFs.getBlockCount();
//块大小
long blockSize = statFs.getBlockSize();
//可用块数量
long availableCount = statFs.getAvailableBlocks();
//剩余块数量这个包含保留块including reserved blocks即应用无法使用的空间
long freeBlocks = statFs.getFreeBlocks();
//这两个方法是直接输出总内存和可用空间也有getFreeBytes//API level 18JELLY_BEAN_MR2引入
long totalSize = statFs.getTotalBytes();
long availableSize = statFs.getAvailableBytes();
long all = totalSize + availableSize;
int percentage = (int) (totalSize * 100 / (totalSize + availableSize));
textView.setText(getUnit(totalSize) + "/" + getUnit(all));
}
/*** 单位转换*/
private static String getUnit(float size) {
String[] units = {"B", "KB", "MB", "GB", "TB"};
int index = 0;
while (size > 1024 && index < 4) {
size = size / 1024;
index++;
}
return String.format(Locale.getDefault(), " %.2f %s", size, units[index]);
}
/**
* 隐藏状态栏和导航栏
*/
public static void setHideBar_StatusAndNavigation(Context mContext) {
ImmersionBar.with((Activity) mContext)
.hideBar(BarHide.FLAG_HIDE_STATUS_BAR)
.hideBar(BarHide.FLAG_HIDE_NAVIGATION_BAR)
.init();
}
/**
* 关闭软键盘
*/
public static void closeKeyBoard(View currentFocus) {
try {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
InputMethodManager imm = (InputMethodManager) LibraryApp.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 关闭软键盘
*/
public static void closeKeyBoard(Activity activity) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
View focusView = activity.getCurrentFocus();
// 优先使用当前焦点视图的窗口令牌
if (focusView != null) {
imm.hideSoftInputFromWindow(focusView.getWindowToken(), 0);
} else {
// 无焦点视图时使用Activity的窗口令牌
imm.hideSoftInputFromWindow(activity.getWindow().getDecorView().getWindowToken(), 0);
}
}
}

View File

@ -0,0 +1,54 @@
package com.tfq.library.utils;
import android.app.Dialog;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import com.tfq.library.R;
public class BigPhotoDialog extends Dialog {
private final Context mContext;
private final LayoutInflater inflater;
private final String url;
private View contentView;
public BigPhotoDialog(Context context, String url) {
super(context, R.style.CustomDialog);
this.mContext = context;
this.url = url;
inflater = LayoutInflater.from(context);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setViews();
}
private void setViews() {
contentView = inflater.inflate(R.layout.layout_dialog_bigphoto, null);
setContentView(contentView);
ImageView imageView = contentView.findViewById(R.id.image_view);
try {
imageView.setImageBitmap(BitmapFactory.decodeFile(url));
} catch (Exception e) {
e.printStackTrace();
GlideLoadUtils.loadResource(mContext, url, imageView);
}
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
}
public interface Listener {
void callBack();
}
}

View File

@ -0,0 +1,54 @@
package com.tfq.library.utils;
import java.io.Closeable;
import java.io.IOException;
/**
* <pre>
* author: Blankj
* blog : http://blankj.com
* time : 2016/10/09
* desc : 关闭相关工具类
* </pre>
*/
public final class CloseUtils {
private CloseUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* 关闭 IO
*
* @param closeables closeables
*/
public static void closeIO(final Closeable... closeables) {
if (closeables == null) return;
for (Closeable closeable : closeables) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 安静关闭 IO
*
* @param closeables closeables
*/
public static void closeIOQuietly(final Closeable... closeables) {
if (closeables == null) return;
for (Closeable closeable : closeables) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException ignored) {
}
}
}
}
}

View File

@ -0,0 +1,41 @@
package com.tfq.library.utils;
import com.chad.library.adapter.base.loadmore.LoadMoreView;
import com.tfq.library.R;
public class CustomLoadMoreView extends LoadMoreView {
@Override
public int getLayoutId() {
return R.layout.quick_view_load_more;
}
/**
* 如果返回true,数据全部加载完毕后会隐藏加载更多
* 如果返回false,数据全部加载完毕后会显示getLoadEndViewId()布局
*
* @return
*/
@Override
public boolean isLoadEndGone() {
return true;
}
@Override
protected int getLoadingViewId() {
return R.id.load_more_loading_view;
}
@Override
protected int getLoadFailViewId() {
return R.id.load_more_load_fail_view;
}
/**
* isLoadEndGone(为true, 可以返回0
* isLoadEndGone 0为false,不能返回0
*/
@Override
protected int getLoadEndViewId() {
return 0;
}
}

View File

@ -0,0 +1,79 @@
package com.tfq.library.utils;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtils {
/**
* @param l_str 精确到秒的字符串
* @param format 时间戳转换成日期格式字符串
* @return
*/
public static String timeStamp2Date(String l_str, String format) {
if (l_str == null || l_str.isEmpty() || l_str.equals("null")) {
return "";
}
if (format == null || format.isEmpty()) {
format = "yyyy-MM-dd HH:mm:ss";
}
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.format(new Date(Long.valueOf(l_str + "000")));
}
/**
* 日期格式字符串转换成时间戳
*
* @param date_str 字符串日期
* @param format yyyy-MM-dd HH:mm:ss
* @return
*/
public static String date2TimeStamp(String date_str, String format) {
try {
SimpleDateFormat sdf = new SimpleDateFormat(format);
return String.valueOf(sdf.parse(date_str).getTime() / 1000);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 取得当前时间戳精确到秒
*
* @return
*/
public static String timeStamp() {
long time = System.currentTimeMillis();
String t = String.valueOf(time / 1000);
return t;
}
public static void main(String[] args) {
String timeStamp = timeStamp();
System.out.println("timeStamp=" + timeStamp); //运行输出:timeStamp=1470278082
System.out.println(System.currentTimeMillis());//运行输出:1470278082980
//该方法的作用是返回当前的计算机时间时间的表达格式为当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数
String date = timeStamp2Date(timeStamp, "yyyy-MM-dd HH:mm:ss");
System.out.println("date=" + date);//运行输出:date=2016-08-04 10:34:42
String timeStamp2 = date2TimeStamp(date, "yyyy-MM-dd HH:mm:ss");
System.out.println(timeStamp2); //运行输出:1470278082
}
public static String gapMin(Date start_date, Date end_date) {
if (end_date.getTime() > start_date.getTime()) {
long nd = 1000 * 24 * 60 * 60;//每天毫秒数
long nh = 1000 * 60 * 60;//每小时毫秒数
long nm = 1000 * 60;//每分钟毫秒数
long diff = end_date.getTime() - start_date.getTime(); // 获得两个时间的毫秒时间差异
long day = diff / nd; // 计算差多少天
long hour = diff % nd / nh; // 计算差多少小时
long min = diff % nd % nh / nm; // 计算差多少分钟
// return day + "" + hour + "小时" + min + "分钟";
return diff / nm + "";
} else {
return "-1";
}
}
}

View File

@ -0,0 +1,27 @@
package com.tfq.library.utils;
import android.text.InputFilter;
import android.text.Spanned;
import java.util.regex.Pattern;
public class DecimalInputFilter implements InputFilter {
private final Pattern decimalPattern = Pattern.compile("^-?\\d*\\.?\\d{0,2}$");
@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
String newText = dest.toString().substring(0, dstart)
+ source.toString()
+ dest.toString().substring(dend);
// 允许空输入或单个负号
if (newText.isEmpty() || newText.equals("-")) return null;
// 验证格式并限制小数点后两位
if (!decimalPattern.matcher(newText).matches()) {
return "";
}
return null;
}
}

View File

@ -0,0 +1,89 @@
package com.tfq.library.utils;
import android.app.Dialog;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import com.tfq.library.R;
/**
* 对话框工具类
*/
public class DialogUtils {
/**
* 为对话框设置模糊背景
* @param dialog 要设置的对话框
* @return 返回添加的模糊背景视图用于后续移除
*/
public static View setBlurBackground(@NonNull Dialog dialog) {
if (dialog.getOwnerActivity() == null) {
return null;
}
// 获取根视图
ViewGroup rootView = (ViewGroup) dialog.getOwnerActivity().getWindow().getDecorView();
// 加载模糊背景
View blurContainer = LayoutInflater.from(dialog.getContext())
.inflate(R.layout.blur_background, rootView, false);
rootView.addView(blurContainer);
// 创建圆角背景
if (dialog.getWindow() != null) {
// 创建圆角矩形
GradientDrawable shape = new GradientDrawable();
shape.setShape(GradientDrawable.RECTANGLE);
// 使用colors.xml中定义的颜色
// int backgroundColor = ContextCompat.getColor(dialog.getContext(), Color.parseColor("#FFFFFFFF"));
int backgroundColor = Color.parseColor("#FFFFFFFF");
shape.setColor(backgroundColor);
shape.setCornerRadius(25f); // 设置圆角半径
// 应用到对话框窗口
dialog.getWindow().setBackgroundDrawable(shape);
// 确保窗口外部是透明的
dialog.getWindow().setDimAmount(0.5f);
}
// 设置对话框消失监听自动移除模糊背景
dialog.setOnDismissListener(dialogInterface -> rootView.removeView(blurContainer));
return blurContainer;
}
/**
* 检查当前是否处于暗黑模式
* @param context 上下文
* @return 是否为暗黑模式
*/
private static boolean isDarkModeEnabled(Context context) {
int nightModeFlags = context.getResources().getConfiguration().uiMode &
Configuration.UI_MODE_NIGHT_MASK;
return nightModeFlags == Configuration.UI_MODE_NIGHT_YES;
}
/**
* 移除模糊背景
* @param dialog 对话框
* @param blurView 之前添加的模糊背景视图
*/
public static void removeBlurBackground(@NonNull Dialog dialog, View blurView) {
if (dialog.getOwnerActivity() != null && blurView != null) {
ViewGroup rootView = (ViewGroup) dialog.getOwnerActivity().getWindow().getDecorView();
rootView.removeView(blurView);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,72 @@
package com.tfq.library.utils;
import android.content.Context;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.tfq.library.R;
public class GlideLoadUtils {
public static void loadResource(Context context, Object url) {
if (url != null && url.toString() != null) {
new BigPhotoDialog(context, url.toString()).show();
}
}
public static void loadResource(Context context, Object url, ImageView imageView) {
try {
if (context != null) {
Glide.with(context)
.load(url)
.placeholder(R.mipmap.ic_loading)
// .error(R.mipmap.image_load_error)
.into(imageView);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void loadResource(Context context, Object url, ImageView imageView, int id) {
try {
if (context != null) {
Glide.with(context)
.load(url)
.placeholder(id)
// .error(R.mipmap.image_load_error)
.into(imageView);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void loadResource(Context context, Object url, Object error_url, ImageView imageView) {
try {
if (context != null) {
Glide.with(context)
.load(url)
.error(error_url)
.into(imageView);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void loadResource(Context context, Object url, ImageView imageView, int id, boolean anim) {
try {
if (context != null) {
Glide.with(context)
.load(url)
.placeholder(id)
// .error(R.mipmap.image_load_error)
// .transition(GenericTransitionOptions.with(R.anim.slide_right_in))
.into(imageView);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,33 @@
package com.tfq.library.utils;
import android.util.Log;
import com.tfq.library.app.BaseConstants;
public class LogK {
public static void d(String msg) {
if (BaseConstants.BASE_APP_DEBUG_PRINT)
Log.d("LogK", "LogK.d http data: " + msg);
}
public static void e(String msg) {
if (BaseConstants.BASE_APP_DEBUG_PRINT)
Log.e("LogK", "LogK.e http data: " + msg);
}
public static void i(String msg) {
if (BaseConstants.BASE_APP_DEBUG_PRINT)
Log.i("LogK", "LogK.i http data: " + msg);
}
public static void w(String msg) {
if (BaseConstants.BASE_APP_DEBUG_PRINT)
Log.w("LogK", "LogK.w http data: " + msg);
}
public static void v(String msg) {
if (BaseConstants.BASE_APP_DEBUG_PRINT)
Log.v("LogK", "LogK.v http data: " + msg);
}
}

View File

@ -0,0 +1,185 @@
package com.tfq.library.utils;
import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
@SuppressLint("NewApi")
public class NetworkUtils {
/**
* Indicates this network uses a Cellular transport.
*/
public static final int TRANSPORT_CELLULAR = 0;
/**
* Indicates this network uses a Wi-Fi transport.
*/
public static final int TRANSPORT_WIFI = 1;
/**
* Indicates this network uses a Bluetooth transport.
*/
public static final int TRANSPORT_BLUETOOTH = 2;
/**
* Indicates this network uses an Ethernet transport.
*/
public static final int TRANSPORT_ETHERNET = 3;
/**
* Indicates this network uses a VPN transport.
*/
public static final int TRANSPORT_VPN = 4;
/**
* Indicates this network uses a Wi-Fi Aware transport.
*/
public static final int TRANSPORT_WIFI_AWARE = 5;
/**
* Indicates this network uses a LoWPAN transport.
*/
public static final int TRANSPORT_LOWPAN = 6;
/**
* Indicates this network uses a Test-only virtual interface as a transport.
*
* @hide
*/
public static final int TRANSPORT_TEST = 7;
/**
* Indicates this network uses a USB transport.
*/
public static final int TRANSPORT_USB = 8;
private static final String TAG = "ConnectManager";
/**
* >= Android 10Q版本推荐
* <p>
* 当前使用MOBILE流量上网
*/
public static boolean isMobileNetwork(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network network = cm.getActiveNetwork();
if (null == network) {
return false;
}
NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
if (null == capabilities) {
return false;
}
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
/**
* >= Android 10Q版本推荐
* <p>
* 当前使用WIFI上网
*/
public static boolean isWifiNetwork(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network network = cm.getActiveNetwork();
if (null == network) {
return false;
}
NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
if (null == capabilities) {
return false;
}
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
/**
* >= Android 10Q版本推荐
* <p>
* 当前使用以太网上网
*/
public static boolean isEthernetNetwork(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network network = cm.getActiveNetwork();
if (null == network) {
return false;
}
NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
if (null == capabilities) {
return false;
}
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
/**
* >= Android 10Q版本推荐
* <p>
* NetworkCapabilities.NET_CAPABILITY_INTERNET表示此网络应该(maybe)能够访问internet
* <p>
* 判断当前网络可以正常上网
* 表示此连接此网络并且能成功上网 例如对于具有NET_CAPABILITY_INTERNET的网络这意味着已成功检测到INTERNET连接
*/
public static boolean isConnectedAvailableNetwork(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network network = cm.getActiveNetwork();
if (null == network) {
return false;
}
NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
if (null == capabilities) {
return false;
}
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
/**
* >= Android 10Q版本推荐
* <p>
* 获取成功上网的网络类型
* value = {
* TRANSPORT_CELLULAR, 0 表示此网络使用蜂窝传输
* TRANSPORT_WIFI, 1 表示此网络使用Wi-Fi传输
* TRANSPORT_BLUETOOTH, 2 表示此网络使用蓝牙传输
* TRANSPORT_ETHERNET, 3 表示此网络使用以太网传输
* TRANSPORT_VPN, 4 表示此网络使用VPN传输
* TRANSPORT_WIFI_AWARE, 5 表示此网络使用Wi-Fi感知传输
* TRANSPORT_LOWPAN, 6 表示此网络使用LoWPAN传输
* TRANSPORT_TEST, 7 指示此网络使用仅限测试的虚拟接口作为传输
* TRANSPORT_USB, 8 表示此网络使用USB传输
* }
*/
public static int getConnectedNetworkType(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network network = cm.getActiveNetwork();
if (null == network) {
return -1;
}
NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
if (null == capabilities) {
return -1;
}
if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return NetworkCapabilities.TRANSPORT_CELLULAR;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return NetworkCapabilities.TRANSPORT_WIFI;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
return NetworkCapabilities.TRANSPORT_BLUETOOTH;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
return NetworkCapabilities.TRANSPORT_ETHERNET;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
return NetworkCapabilities.TRANSPORT_VPN;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {
return NetworkCapabilities.TRANSPORT_WIFI_AWARE;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN)) {
return NetworkCapabilities.TRANSPORT_LOWPAN;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_USB)) {
return NetworkCapabilities.TRANSPORT_USB;
}
}
return -1;
}
}

View File

@ -0,0 +1,228 @@
package com.tfq.library.utils;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import com.tfq.library.R;
public class PermissionDialog extends Dialog {
private final Context mContext;
private final LayoutInflater inflater;
private Listener listener;
private Listener_Location listener_location;
private View contentView;
private String type;
private String content;
private String title;
private Listener_Intent listener_intent;
private Listener_Result listener_result;
public PermissionDialog(Context context, Listener listener) {
super(context, R.style.CustomDialog);
this.listener = listener;
this.mContext = context;
inflater = LayoutInflater.from(context);
}
public PermissionDialog(Context context, String type, String title, String content, Listener_Location listener_location) {
super(context, R.style.CustomDialog);
this.listener_location = listener_location;
this.mContext = context;
this.type = type;
this.title = title;
this.content = content;
inflater = LayoutInflater.from(context);
}
public PermissionDialog(Context context, String type) {
super(context, R.style.CustomDialog);
this.mContext = context;
this.type = type;
this.title = title;
this.content = content;
inflater = LayoutInflater.from(context);
}
public PermissionDialog(Context context, String title, String content, Listener listener) {
super(context, R.style.CustomDialog);
this.mContext = context;
this.title = title;
this.content = content;
this.listener = listener;
inflater = LayoutInflater.from(context);
}
public PermissionDialog(Context context, String type, String title, String content) {
super(context, R.style.CustomDialog);
this.mContext = context;
this.type = type;
this.title = title;
this.content = content;
inflater = LayoutInflater.from(context);
}
public PermissionDialog(Context context, String type, String title, String content, Listener_Result listener_result) {
super(context, R.style.CustomDialog);
this.listener_result = listener_result;
this.mContext = context;
this.type = type;
this.title = title;
this.content = content;
inflater = LayoutInflater.from(context);
}
public PermissionDialog(Context context, String type, String title, String content, Listener listener) {
super(context, R.style.CustomDialog);
this.listener = listener;
this.mContext = context;
this.type = type;
this.title = title;
this.content = content;
inflater = LayoutInflater.from(context);
}
public PermissionDialog(Context context, String type, String title, String content, Listener listener, Listener_Intent listener_intent) {
super(context, R.style.CustomDialog);
this.listener = listener;
this.listener_intent = listener_intent;
this.mContext = context;
this.type = type;
this.title = title;
this.content = content;
inflater = LayoutInflater.from(context);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setViews();
}
private void setViews() {
contentView = inflater.inflate(R.layout.layout_dialog_permission, null);
setContentView(contentView);
TextView tv_title = contentView.findViewById(R.id.tv_title);
TextView tv_content = contentView.findViewById(R.id.tv_content);
TextView tv_left = contentView.findViewById(R.id.tv_left);
TextView tv_right = contentView.findViewById(R.id.tv_right);
if ("cancel_authorization".equals(type)) {
tv_left.setVisibility(View.GONE);
tv_content.setText(content);
tv_title.setText(title);
tv_content.setGravity(Gravity.CENTER);
} else if ("reject_authorization".equals(type)) {
tv_content.setText(content);
tv_title.setText(title);
// tv_right.setImageDrawable(App.getContext().getDrawable(R.mipmap.ic_confirm));
} else if ("isLocServiceEnable".equals(type)) {
tv_content.setText(content);
tv_title.setText(title);
// tv_right.setImageDrawable(App.getContext().getDrawable(R.mipmap.ic_confirm));
} else if ("request_per".equals(type)) {
tv_content.setText(content);
tv_title.setText(title);
// tv_right.setImageDrawable(App.getContext().getDrawable(R.mipmap.ic_confirm));
// this.setCanceledOnTouchOutside(false);
// this.setCancelable(false);
}else if ("del_project".equals(type)) {
tv_content.setText(content);
tv_title.setText(title);
tv_right.setTextColor(mContext.getResources().getColor(R.color.gold));
}else if ("export_data".equals(type)) {
tv_content.setText(content);
tv_title.setText(title);
tv_right.setTextColor(mContext.getResources().getColor(R.color.gold));
} else {
tv_content.setText(content);
tv_title.setText(title);
}
tv_left.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if ("isLocServiceEnable".equals(type)) {
listener_location.success(false);
} else if ("reject_authorization".equals(type)) {
if (listener != null) {
listener.success();
}
if (listener_result != null) {
listener_result.success(false);
}
} else if ("request_per".equals(type)) {
if (listener_result != null) {
listener_result.success(false);
}
}
dismiss();
}
});
tv_right.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if ("reject_authorization".equals(type)) {
if (listener_intent != null) {
listener_intent.success();
} else {
Intent intent = new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", mContext.getPackageName(), null));
mContext.startActivity(intent);
}
} else if ("cancel_authorization".equals(type)) {
dismiss();
} else if ("isLocServiceEnable".equals(type)) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
mContext.startActivity(intent);
} catch (ActivityNotFoundException ex) {
intent.setAction(Settings.ACTION_SETTINGS);
try {
mContext.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
listener_location.success(true);
dismiss();
} else if (listener != null) {
listener.success();
dismiss();
} else if (listener_result != null) {
listener_result.success(true);
dismiss();
}
}
});
}
public interface Listener {
void success();
}
public interface Listener_Result {
void success(boolean b);
}
public interface Listener_Location {
void success(boolean b);
}
public interface Listener_Intent {
void success();
}
}

View File

@ -0,0 +1,58 @@
package com.tfq.library.utils;
import android.content.Context;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
* Created by long on 2016/3/30.
* 视图帮助类
*/
public class RecyclerViewHelper {
private RecyclerViewHelper() {
throw new RuntimeException("RecyclerViewHelper cannot be initialized!");
}
public static void initRecyclerViewV(Context context, RecyclerView view, boolean isDivided, RecyclerView.Adapter adapter) {
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
// view.setHasFixedSize(true);
if (view != null) {
view.setLayoutManager(layoutManager);
view.setItemAnimator(new DefaultItemAnimator());
if (isDivided) {
// view.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL_LIST));
}
view.setAdapter(adapter);
}
}
public static void initRecyclerViewV(Context context, RecyclerView view, RecyclerView.Adapter adapter) {
initRecyclerViewV(context, view, false, adapter);
}
public static void initRecyclerViewH(Context context, RecyclerView view, RecyclerView.Adapter adapter) {
initRecyclerViewH(context, view, false, adapter);
}
public static void initRecyclerViewH(Context context, RecyclerView view, boolean isDivided, RecyclerView.Adapter adapter) {
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
// view.setHasFixedSize(true);
if (view != null) {
view.setLayoutManager(layoutManager);
view.setItemAnimator(new DefaultItemAnimator());
if (isDivided) {
// view.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL_LIST));
}
view.setAdapter(adapter);
}
}
}

View File

@ -0,0 +1,44 @@
package com.tfq.library.utils;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
public class SDUtils {
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public static long getAvailableSize() {
if (isMounted()) {
StatFs stat = new StatFs(getSDCardPath());
// 获得可用的块的数量
long count = stat.getAvailableBlocksLong();
long size = stat.getBlockSizeLong();
return count * size;
}
return 0;
}
/**
* 判断SDCard是否挂载
* Environment.MEDIA_MOUNTED,表示SDCard已经挂载
* Environment.getExternalStorageState()获得当前SDCard的挂载状态
*/
private static boolean isMounted() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
/**
* 获得SDCard 的路径,storage/sdcard
*
* @return 路径
*/
public static String getSDCardPath() {
String path = null;
if (isMounted()) {
path = Environment.getExternalStorageDirectory().getPath();
}
return path;
}
}

View File

@ -0,0 +1,158 @@
package com.tfq.library.utils;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.GradientDrawable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.core.content.ContextCompat;
import com.tfq.library.R;
/**
* Created by TinyHung@outlook.com
* 2019/5/10
* 自行指定背景圆角颜色的BUTTON
*/
public class ShapeTextView extends AppCompatTextView implements View.OnTouchListener {
private boolean mTextMarquee;
private float mStrokeWidth = 0.6f;
//圆角边框
private int mRadius, mStroke;
//背景颜色
private int mBackGroundColor = Color.parseColor("#00000000")
//背景按下颜色
, mBackGroundSelectedColor = Color.parseColor("#00000000")
//边框颜色
, mStrokeColor = Color.parseColor("#00000000");
public ShapeTextView(@NonNull Context context) {
this(context, null);
}
public ShapeTextView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ShapeTextView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.setOnTouchListener(this);
if (null != attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ShapeTextView);
mRadius = typedArray.getDimensionPixelSize(R.styleable.ShapeTextView_shapeRadius, 0);
mStroke = typedArray.getDimensionPixelSize(R.styleable.ShapeTextView_shapeStrokeWidth, 0);
mStrokeColor = typedArray.getColor(R.styleable.ShapeTextView_shapeStrokeColor,
ContextCompat.getColor(getContext(), android.R.color.transparent));
mBackGroundColor = typedArray.getColor(R.styleable.ShapeTextView_shapeBackgroundColor,
ContextCompat.getColor(getContext(), R.color.colorAccent));
mBackGroundSelectedColor = typedArray.getColor(R.styleable.ShapeTextView_shapeBackgroundSelectorColor,
ContextCompat.getColor(getContext(), R.color.colorPrimaryDark));
mStrokeWidth = typedArray.getFloat(R.styleable.ShapeTextView_shapeStorkeWidth, mStrokeWidth);
mTextMarquee = typedArray.getBoolean(R.styleable.ShapeTextView_shapeMarquee, false);
typedArray.recycle();
}
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setCornerRadius(mRadius);
gradientDrawable.setStroke(mStroke, mStrokeColor);
gradientDrawable.setColor(mBackGroundColor);
this.setBackground(gradientDrawable);
setClickable(true);
}
public void setRadius(int radius) {
mRadius = radius;
GradientDrawable gradientDrawable = (GradientDrawable) getBackground();
if (null != gradientDrawable) {
gradientDrawable.setCornerRadius(mRadius);
}
}
public void setBackGroundColor(int color) {
this.mBackGroundColor = color;
GradientDrawable gradientDrawable = (GradientDrawable) getBackground();
if (null != gradientDrawable) {
gradientDrawable.setColor(mBackGroundColor);
}
}
public void setBackGroundSelectedColor(int color) {
this.mBackGroundSelectedColor = color;
}
public void setStroke(int stroke) {
mStroke = stroke;
GradientDrawable gradientDrawable = (GradientDrawable) getBackground();
if (null != gradientDrawable) {
gradientDrawable.setStroke(mStroke, mStrokeColor);
}
}
public void setStrokeColor(int strokeColor) {
mStrokeColor = strokeColor;
GradientDrawable gradientDrawable = (GradientDrawable) getBackground();
if (null != gradientDrawable) {
gradientDrawable.setStroke(mStroke, mStrokeColor);
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
//用户手指按下使用按下Color
case MotionEvent.ACTION_DOWN:
GradientDrawable gradientDrawable = (GradientDrawable) getBackground();
if (null != gradientDrawable) {
gradientDrawable.setColor(mBackGroundSelectedColor);
}
break;
case MotionEvent.ACTION_MOVE:
break;
//用户松手使用默认背景Color
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
GradientDrawable background = (GradientDrawable) getBackground();
if (null != background) {
background.setColor(mBackGroundColor);
}
break;
}
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
//获取当前控件的画笔
TextPaint paint = getPaint();
//设置画笔的描边宽度值
paint.setStrokeWidth(mStrokeWidth);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
super.onDraw(canvas);
}
/**
* 设置描边宽度
*
* @param strokeWidth 从0.0起
*/
public void setStrokeWidth(float strokeWidth) {
this.mStrokeWidth = strokeWidth;
invalidate();
}
@Override
public boolean isFocused() {
return mTextMarquee;
}
}

View File

@ -0,0 +1,34 @@
package com.tfq.library.utils;
import android.content.Context;
import android.content.SharedPreferences;
public class SpManager {
private static SharedPreferences sharedPreferences;
private static SharedPreferences.Editor editor;
/**
* 写入本地
*
* @param context
* @param name
* @return
*/
public static SharedPreferences.Editor startWrite(Context context, String name) {
sharedPreferences = context.getSharedPreferences(name, Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
return editor;
}
/**
* 从本地读取
*
* @param context
* @param name
* @return
*/
public static SharedPreferences startRead(Context context, String name) {
sharedPreferences = context.getSharedPreferences(name, Context.MODE_PRIVATE);
return sharedPreferences;
}
}

View File

@ -0,0 +1,92 @@
package com.tfq.library.utils;
import android.icu.math.BigDecimal;
import android.view.Gravity;
import com.hjq.toast.ToastParams;
import com.hjq.toast.Toaster;
import com.hjq.toast.style.CustomToastStyle;
import com.hjq.toast.style.WhiteToastStyle;
import com.tfq.library.R;
import java.math.BigInteger;
public class ToasterUtil {
public static void show(String text) {
Toaster.show(text);
}
public static void show(Object object) {
Toaster.show(object);
}
public static void show(CharSequence text) {
Toaster.show(text);
}
public static void show(ToastParams params) {
Toaster.show(params);
}
public static void show(int text, int type) {
show(text + "", type);
}
public static void show(Object text, int type) {
show(text + "", type);
}
/**
* @param text 显示内容
* @param type 类型 0:默认黑色;1:通过样式;2:提示样式;3:警告样式;4:错误样式; 10:白色样式;20:自定义弹窗
*/
public static void show(String text, int type) {
ToastParams params;
switch (type) {
case 0:
show(text);
break;
case 1:
params = new ToastParams();
params.text = text;
params.style = new CustomToastStyle(R.layout.toast_success);
Toaster.show(params);
break;
case 2:
params = new ToastParams();
params.text = text;
params.style = new CustomToastStyle(R.layout.toast_info);
Toaster.show(params);
break;
case 3:
params = new ToastParams();
params.text = text;
params.style = new CustomToastStyle(R.layout.toast_warn);
Toaster.show(params);
break;
case 4:
params = new ToastParams();
params.text = text;
params.style = new CustomToastStyle(R.layout.toast_error);
Toaster.show(params);
break;
case 10:
params = new ToastParams();
params.text = text;
params.style = new WhiteToastStyle();
Toaster.show(params);
break;
case 20:
Toaster.setView(R.layout.toast_custom_view);
Toaster.setGravity(Gravity.CENTER);
Toaster.show(text);
break;
default:
show(text);
break;
}
}
}

View File

@ -0,0 +1,96 @@
package com.tfq.library.utils.style;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.hjq.toast.config.IToastStyle;
/**
* author : Android 轮子哥
* github : https://github.com/getActivity/Toaster
* time : 2018/09/01
* desc : 默认黑色样式实现
*/
@SuppressWarnings({"unused", "deprecation"})
public class BlackToastStyle implements IToastStyle<View> {
@Override
public View createView(Context context) {
TextView textView = new TextView(context);
textView.setId(android.R.id.message);
textView.setGravity(getTextGravity(context));
textView.setTextColor(getTextColor(context));
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, getTextSize(context));
int horizontalPadding = getHorizontalPadding(context);
int verticalPadding = getVerticalPadding(context);
// 适配布局反方向特性
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
textView.setPaddingRelative(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
} else {
textView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
}
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
Drawable backgroundDrawable = getBackgroundDrawable(context);
// 设置背景
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
textView.setBackground(backgroundDrawable);
} else {
textView.setBackgroundDrawable(backgroundDrawable);
}
// 设置 Z 轴阴影
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
textView.setZ(getTranslationZ(context));
}
return textView;
}
protected int getTextGravity(Context context) {
return Gravity.CENTER;
}
protected int getTextColor(Context context) {
return 0XEEFFFFFF;
}
protected float getTextSize(Context context) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
14, context.getResources().getDisplayMetrics());
}
protected int getHorizontalPadding(Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
24, context.getResources().getDisplayMetrics());
}
protected int getVerticalPadding(Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
16, context.getResources().getDisplayMetrics());
}
protected Drawable getBackgroundDrawable(Context context) {
GradientDrawable drawable = new GradientDrawable();
// 设置颜色
drawable.setColor(0XB3000000);
// 设置圆角
drawable.setCornerRadius(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
7, context.getResources().getDisplayMetrics()));
return drawable;
}
protected float getTranslationZ(Context context) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, context.getResources().getDisplayMetrics());
}
}

View File

@ -0,0 +1,33 @@
package com.tfq.library.utils.style;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.util.TypedValue;
import com.hjq.toast.style.BlackToastStyle;
/**
* author : Android 轮子哥
* github : https://github.com/getActivity/Toaster
* time : 2018/09/01
* desc : 默认白色样式实现
*/
public class WhiteToastStyle extends BlackToastStyle {
@Override
protected int getTextColor(Context context) {
return 0XBB000000;
}
@Override
protected Drawable getBackgroundDrawable(Context context) {
GradientDrawable drawable = new GradientDrawable();
// 设置颜色
drawable.setColor(0XFFEAEAEA);
// 设置圆角
drawable.setCornerRadius(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
7, context.getResources().getDisplayMetrics()));
return drawable;
}
}

View File

@ -0,0 +1,146 @@
package com.tfq.library.view;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import com.tfq.library.R;
import com.tfq.library.app.BaseConstants;
public class AuthDialog extends Dialog {
private final Context mContext;
private final LayoutInflater inflater;
private Listener listener;
private View contentView;
private String type;
public AuthDialog(Context context, Listener listener) {
super(context, R.style.CustomDialog);
this.listener = listener;
this.mContext = context;
inflater = LayoutInflater.from(context);
}
public AuthDialog(Context context, String type) {
super(context, R.style.CustomDialog);
this.mContext = context;
this.type = type;
inflater = LayoutInflater.from(context);
}
public AuthDialog(Context context, String type, Listener listener) {
super(context, R.style.CustomDialog);
this.listener = listener;
this.mContext = context;
this.type = type;
inflater = LayoutInflater.from(context);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setViews();
}
private void setViews() {
int layout = BaseConstants.dialog_layout == 0 ? R.layout.layout_dialog_auth : BaseConstants.dialog_layout == 1 ? R.layout.layout_dialog_auth2 : R.layout.layout_dialog_auth3;
contentView = inflater.inflate(layout, null);
setContentView(contentView);
TextView tv_left = contentView.findViewById(R.id.tv_left);
TextView tv_right = contentView.findViewById(R.id.tv_right);
TextView tv_content = contentView.findViewById(R.id.tv_content);
TextView tv_title = contentView.findViewById(R.id.tv_title);
if ("privacy".equals(type)) {
tv_title.setText("隐私权限管理");
tv_content.setText("请在本应用的详情页面的权限列表找到'权限'并打开进行设置。");
tv_right.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.callBack();
} else {
Intent intent = new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", mContext.getPackageName(), null));
mContext.startActivity(intent);
}
dismiss();
}
});
tv_left.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
} else if ("authorizatio".equals(type)) {
tv_title.setText("撤回隐私授权");
tv_content.setText("若您撤回本App的隐私授权我们将会停止收集您的个人信息,并且不再为您提供相应服务,谨慎进行此步操作。");
tv_left.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
tv_right.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.callBack();
}
dismiss();
}
});
} else if ("playUrl".equals(type)) {
tv_title.setText("此链接无效");
tv_content.setText("请输入正确地址");
tv_content.setGravity(Gravity.CENTER);
tv_left.setVisibility(View.GONE);
// tv_right.setImageDrawable(mContext.getDrawable(R.mipmap.ic_confirm));
tv_right.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
if (listener != null) {
listener.callBack();
}
}
});
this.setCanceledOnTouchOutside(false);
this.setCancelable(false);
} else {
tv_right.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) listener.callBack();
dismiss();
}
});
tv_left.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
}
}
public interface Listener {
void callBack();
}
}

View File

@ -0,0 +1,34 @@
package com.tfq.library.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import net.center.blurview.ShapeBlurView;
/**
* 安全的模糊视图包装类修复测量问题
*/
public class SafeBlurView extends ShapeBlurView {
public SafeBlurView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} catch (Exception e) {
// 确保在原始测量失败时设置默认尺寸
int width = View.MeasureSpec.getSize(widthMeasureSpec);
int height = View.MeasureSpec.getSize(heightMeasureSpec);
// 确保宽高至少为1px
width = Math.max(width, 1);
height = Math.max(height, 1);
setMeasuredDimension(width, height);
}
}
}

View File

@ -0,0 +1,424 @@
package com.tfq.library.view;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.tfq.library.R;
import com.tfq.library.utils.LogK;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
/**
* Description:
* Created by JiangKe .
*/
public class SlideDownView extends LinearLayout {
// 动画相关属性
private final boolean isExpanded = false;
private float mTextTitleSize = 15f;
private float mTextContentSize = 12f;
private float targetTranslationY; // 目标位置的Y轴偏移量
private float overshootTranslationY; // 超过目标位置的Y轴偏移量
private String mTextTitle = "";
private String mTextContent = "";
private int mMILLISECONDS;
private boolean mViewCenter;
private int mImageView;
private int view_type;//0:通过(默认);1:error
private int view_bg = Color.parseColor("#4CB050");
private DelayedTaskManager taskManager;
public SlideDownView(Context context) {
super(context);
initView(null);
}
public SlideDownView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(attrs);
}
public SlideDownView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(attrs);
}
private void initView(AttributeSet attrs) {
if (null != attrs) {
//获取到自定义xml的数据
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.SlideDownView);
mImageView = typedArray.getResourceId(R.styleable.SlideDownView_custom_image, 0);
mTextTitle = typedArray.getString(R.styleable.SlideDownView_text_title);
mTextTitleSize = typedArray.getFloat(R.styleable.SlideDownView_text_title_size, mTextTitleSize);
mTextContent = typedArray.getString(R.styleable.SlideDownView_text_content);
mTextContentSize = typedArray.getFloat(R.styleable.SlideDownView_text_content_size, mTextContentSize);
// mTextMarquee = typedArray.getBoolean(R.styleable.SlideDownView_boldMarquee, false);
mMILLISECONDS = typedArray.getInteger(R.styleable.SlideDownView_hide_milliseconds, 300);
mViewCenter = typedArray.getBoolean(R.styleable.SlideDownView_view_center, true);
typedArray.recycle();
}
addLinearLayoutView();
initThreadPool();
setLayerType(LAYER_TYPE_SOFTWARE, null);
setWillNotDraw(false);
}
private void initThreadPool() {
taskManager = new DelayedTaskManager();
}
// 在Activity的onCreate或其他适当位置调用此方法
private void addLinearLayoutView() {
// 获取应用上下文
Context context = getContext();
// 创建外层水平LinearLayout
LinearLayout mainLayout = new LinearLayout(context);
// 设置LayoutParams并添加marginTop
LinearLayout.LayoutParams mainParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
// 转换30dp为像素值
mainLayout.setLayoutParams(mainParams);
mainLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
hideFunctionBar();
}
});
// 保留原有其他属性设置
mainLayout.setOrientation(LinearLayout.HORIZONTAL);
// mainLayout.setGravity(Gravity.CENTER_VERTICAL);
if (mViewCenter) {
mainLayout.setGravity(Gravity.CENTER);
} else {
mainLayout.setGravity(Gravity.CENTER_VERTICAL);
}
int paddingHorizontal = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics());
int paddingLeft = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics());
int paddingTop = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 35, getResources().getDisplayMetrics());
mainLayout.setPadding(paddingLeft, paddingTop, paddingHorizontal, 0);
mainLayout.setBackgroundColor(view_bg);
mainLayout.setId(R.id.main_layout);
// 创建ImageView
ImageView imageView = new ImageView(context);
LinearLayout.LayoutParams imageParams = new LinearLayout.LayoutParams((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 70, getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 70, getResources().getDisplayMetrics()));
imageView.setLayoutParams(imageParams);
imageView.setPadding((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics()));
imageView.setImageResource(R.drawable.ic_place);
imageView.setId(R.id.image_view); // 确保在ids.xml中定义了此ID
if (mImageView != 0) {
imageView.setVisibility(VISIBLE);
} else {
imageView.setVisibility(GONE);
}
// 创建内层垂直LinearLayout
LinearLayout innerLayout = new LinearLayout(context);
LinearLayout.LayoutParams innerParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
int marginLeft = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics());
innerParams.setMargins(0, 0, 0, 0);
innerLayout.setLayoutParams(innerParams);
innerLayout.setOrientation(LinearLayout.VERTICAL);
// 创建标题TextView
TextView tvTitle = new TextView(context);
tvTitle.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
// 新增省略号和单行设置
tvTitle.setEllipsize(TextUtils.TruncateAt.END); // 末尾显示省略号
tvTitle.setMaxLines(1); // 限制为单行
tvTitle.setSingleLine(true); // 旧版兼容方案可选
tvTitle.setHorizontallyScrolling(true); // 防止自动换行
tvTitle.setText(mTextTitle);
tvTitle.setTextColor(ContextCompat.getColor(context, R.color.white));
tvTitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mTextTitleSize);
tvTitle.setTypeface(null, Typeface.BOLD);
tvTitle.setId(R.id.tv_title);
if (!TextUtils.isEmpty(mTextTitle)) {
tvTitle.setVisibility(VISIBLE);
} else {
tvTitle.setVisibility(GONE);
}
// 创建分隔线View
View divider = new View(context);
LinearLayout.LayoutParams dividerParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics()));
divider.setLayoutParams(dividerParams);
divider.setBackgroundColor(Color.TRANSPARENT); // 根据实际颜色设置
divider.setId(R.id.view_space);
// 创建内容TextView
TextView tvContent = new TextView(context);
tvContent.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
// 新增省略号和单行设置
tvContent.setEllipsize(TextUtils.TruncateAt.END); // 末尾显示省略号
tvContent.setMaxLines(1); // 限制为单行
tvContent.setSingleLine(true); // 旧版兼容方案可选
tvContent.setHorizontallyScrolling(true); // 防止自动换行
tvContent.setText(mTextContent);
tvContent.setTextColor(ContextCompat.getColor(context, R.color.white));
tvContent.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mTextContentSize);
tvContent.setId(R.id.tv_content);
if (!TextUtils.isEmpty(mTextContent)) {
tvContent.setVisibility(VISIBLE);
} else {
tvContent.setVisibility(GONE);
}
if (!TextUtils.isEmpty(mTextTitle) && !TextUtils.isEmpty(mTextContent)) {
divider.setVisibility(VISIBLE);
} else {
divider.setVisibility(GONE);
}
innerLayout.setGravity(Gravity.CENTER);
// 组装内层布局
innerLayout.addView(tvTitle);
innerLayout.addView(divider);
innerLayout.addView(tvContent);
// 组装外层布局
mainLayout.addView(imageView);
mainLayout.addView(innerLayout);
// 设置为内容视图
addView(mainLayout);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 1. 测量所有子视图
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
// 2. 根据子视图计算父容器尺寸此处以最大子宽度和累加高度为例
int maxChildWidth = 0;
int totalHeight = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
maxChildWidth = Math.max(maxChildWidth, child.getMeasuredWidth());
totalHeight += child.getMeasuredHeight();
}
// 3. 设置父容器最终尺寸
setMeasuredDimension(resolveSize(maxChildWidth, widthMeasureSpec), resolveSize(totalHeight, heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int currentTop = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
// 将子视图纵向排列示例布局
child.layout(0, currentTop, child.getMeasuredWidth(), currentTop + child.getMeasuredHeight());
currentTop += child.getMeasuredHeight();
}
}
public void hideFunctionBar() {
animate().translationY(-getHeight() * 1.5f) // 向上移动 1.5 倍高度
.setDuration(mMILLISECONDS).setInterpolator(new AccelerateInterpolator()).start();
}
/**
* n毫秒后执行隐藏
*
* @param MILLISECONDS 毫秒
*/
public void hideFunctionBar(long MILLISECONDS) {
animate().translationY(-getHeight() * 1.5f) // 向上移动 1.5 倍高度
.setDuration(MILLISECONDS).setInterpolator(new AccelerateInterpolator()).start();
}
public void showFunctionBar() {
hideFunctionBar(0);
// 将15dp转换为像素值
final float overshoot = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics());
AnimatorSet set = new AnimatorSet();
set.playSequentially(ObjectAnimator
.ofFloat(this, "translationY", overshoot)
.setDuration(300), ObjectAnimator.ofFloat(this, "translationY", 0)
.setDuration(200)
);
set.setInterpolator(new AccelerateDecelerateInterpolator());
set.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// 动画开始时触发
LogK.e("Animation 动画开始");
taskManager.scheduleTask(3000, () -> {
// 延迟2秒后执行的实际操作如显示Toast
LogK.e("执行任务=" + System.currentTimeMillis());
hideFunctionBar();
});
}
@Override
public void onAnimationEnd(Animator animation) {
// 动画完成时触发回调整个AnimatorSet执行完毕
LogK.e("Animation 动画完成");
}
@Override
public void onAnimationCancel(Animator animation) {
// 动画被取消时触发
LogK.e("Animation 动画被取消");
}
@Override
public void onAnimationRepeat(Animator animation) {
// 动画重复时触发仅适用于循环动画
LogK.e("Animation 循环动画");
}
});
set.start();
}
public void setTextTitle(String mTextTitle) {
this.mTextTitle = mTextTitle;
invalidate();
}
public void setTextTitleSize(int mTextTitleSize) {
this.mTextTitleSize = mTextTitleSize;
invalidate();
}
public void setTextContent(String mTextContent) {
this.mTextContent = mTextContent;
invalidate();
}
public void setTextContentSize(int mTextContentSize) {
this.mTextContentSize = mTextContentSize;
invalidate();
}
public void setCustomImage(int mImageView) {
this.mImageView = mImageView;
invalidate();
}
public void setHide_milliseconds(int hide_milliseconds) {
this.mMILLISECONDS = hide_milliseconds;
}
public void setBackgroundColor(int view_bg) {
this.view_bg = view_bg;
invalidate();
}
public void setBackgroundColor(String view_bg) {
this.view_bg = Color.parseColor(view_bg);
invalidate();
}
public void setType(int view_type) {
this.view_type = view_type;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
TextView tv_title = findViewById(R.id.tv_title);
tv_title.setText(mTextTitle);
tv_title.setTextSize(mTextTitleSize);
TextView tv_content = findViewById(R.id.tv_content);
tv_content.setText(mTextContent);
tv_content.setTextSize(mTextContentSize);
ImageView image_view = findViewById(R.id.image_view);
View view_space = findViewById(R.id.view_space);
if (!TextUtils.isEmpty(mTextTitle) && !TextUtils.isEmpty(mTextContent)) {
view_space.setVisibility(VISIBLE);
tv_title.setVisibility(VISIBLE);
tv_content.setVisibility(VISIBLE);
} else {
view_space.setVisibility(GONE);
if (TextUtils.isEmpty(mTextTitle)) {
tv_title.setVisibility(GONE);
} else {
tv_title.setVisibility(VISIBLE);
}
if (TextUtils.isEmpty(mTextContent)) {
tv_content.setVisibility(GONE);
} else {
tv_content.setVisibility(GONE);
}
}
if (mImageView != 0) {
image_view.setVisibility(VISIBLE);
image_view.setImageResource(mImageView);
} else {
image_view.setVisibility(GONE);
}
view_bg = view_type==0? Color.parseColor("#4CB050") : Color.parseColor("#FF4443");
LinearLayout main_layout = findViewById(R.id.main_layout);
main_layout.setBackgroundColor(view_bg);
}
}
class DelayedTaskManager {
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
private final Handler mainHandler = new Handler(Looper.getMainLooper());
private ScheduledFuture<?> pendingTask;
// 提交延迟任务UI线程调用
public void scheduleTask(final long time, final Runnable task) {
// 取消之前的任务
if (pendingTask != null) {
pendingTask.cancel(true);
}
// 提交新任务延迟2秒执行
pendingTask = executor.schedule(() -> {
// 切换到主线程执行实际任务如更新UI
mainHandler.post(task);
}, time, TimeUnit.MILLISECONDS);
}
// 关闭线程池避免内存泄漏
public void shutdown() {
executor.shutdownNow();
}
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:fromYDelta="100%"
android:toYDelta="0" />

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:fromYDelta="0"
android:toYDelta="100%" />

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="150"
android:fromXDelta="100%p"
android:toXDelta="0" />
</set>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="150"
android:fromXDelta="0"
android:toXDelta="100%p" />
</set>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="400"
android:fillAfter="true">
<translate
android:fromXDelta="100%p"
android:fromYDelta="0"
android:toXDelta="0"
android:toYDelta="0" />
<alpha
android:fromAlpha="0"
android:toAlpha="1" />
</set>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="400"
android:fillAfter="true">
<translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="100%p"
android:toYDelta="0" />
<alpha
android:fromAlpha="1"
android:toAlpha="0" />
</set>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromYDelta="100%"
android:toYDelta="0" />

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromYDelta="0"
android:toYDelta="100%" />

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="600"
android:fromYDelta="100%p" />
</set>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="600"
android:toYDelta="100%p" />
</set>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="0dp"
android:color="@color/white" />
<corners android:radius="7dp" />
<solid android:color="@color/white" />
</shape>

View File

@ -0,0 +1,6 @@
<!-- res/drawable/red_round_button.xml -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#4387F5" />
<corners android:radius="4dp" />
</shape>

View File

@ -0,0 +1,6 @@
<!-- res/drawable/red_round_button.xml -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/themeColor" />
<corners android:radius="4dp" />
</shape>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="180"
android:endColor="#387cfd"
android:startColor="#26c4fd"
android:type="linear" />
<corners android:radius="7dp" />
</shape>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/toast_error_color" />
<corners android:radius="999dp" />
</shape>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
</vector>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/toast_hint_color" />
<corners android:radius="999dp" />
</shape>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z" />
</vector>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/toast_success_color" />
<corners android:radius="999dp" />
</shape>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FAFBFB"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z" />
</vector>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/toast_warn_color2" />
<corners android:radius="999dp" />
</shape>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M11,15h2v2h-2zM11,7h2v6h-2zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z" />
</vector>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.tfq.library.view.SafeBlurView
android:id="@+id/blur_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:blur_down_sample="4"
app:blur_overlay_color="#00000000"
app:blur_radius="30dp"
/>
</FrameLayout>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
>
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入内容"
android:imeOptions="actionDone"
android:lines="1"
android:textSize="14sp"
/>
</LinearLayout>

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#51D54D"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="30dp"
android:gravity="center"
android:orientation="horizontal"
android:paddingLeft="20dp"
android:paddingRight="20dp"
>
<ImageView
android:id="@+id/image_view"
android:layout_width="50dp"
android:layout_height="50dp"
android:padding="5dp"
android:src="@drawable/ic_place"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:gravity="center_vertical"
android:orientation="vertical"
>
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:text="title"
android:textColor="@color/white"
android:textSize="17dp"
android:textStyle="bold"
/>
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="5dp"
/>
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:text="content"
android:textColor="@color/white"
android:textSize="13dp"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<com.tfq.library.view.SlideDownView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/slide_down_view"
android:layout_width="match_parent"
android:layout_height="130dp"
android:layout_marginTop="-20dp"
android:translationY="-110dp"
app:text_title="提示"
>
</com.tfq.library.view.SlideDownView>

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="@drawable/ll_radio_white">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:layout_marginRight="15dp"
android:gravity="center"
android:text="Title"
android:textColor="#FF333333"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:layout_marginRight="15dp"
android:gravity="center"
android:paddingLeft="22dp"
android:paddingRight="22dp"
android:text="content"
android:textColor="#FF333333"
android:textSize="14sp" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_below="@+id/tv_content"
android:layout_marginTop="15dp"
android:background="#D6D6D6" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_below="@+id/tv_content"
android:layout_marginTop="12dp"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_left"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="取消"
android:textStyle="bold" />
<View
android:layout_width="0.5dp"
android:layout_height="match_parent"
android:background="#D6D6D6" />
<TextView
android:id="@+id/tv_right"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="确定"
android:textColor="#37A96A"
android:textStyle="bold" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<RelativeLayout
android:paddingBottom="18dp"
android:paddingTop="18dp"
android:paddingRight="15dp"
android:paddingLeft="15dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ll_radio_white"
>
<TextView
android:layout_marginTop="5dp"
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title"
android:textColor="@color/black"
android:textSize="17dp"
android:textStyle="bold"
/>
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title"
android:layout_marginTop="10dp"
android:text="content"
android:textColor="#212121"
android:textSize="15dp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_content"
android:layout_marginTop="12dp"
android:gravity="end"
android:orientation="horizontal"
>
<TextView
android:id="@+id/tv_left"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:background="@drawable/round_button_blue"
android:ellipsize="end"
android:gravity="center"
android:lines="1"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:text="取消"
android:textColor="#ffffff"
android:textSize="13dp"
/>
<TextView
android:id="@+id/tv_right"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_marginLeft="8dp"
android:background="@drawable/round_button_blue"
android:ellipsize="end"
android:gravity="center"
android:lines="1"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:text="确定"
android:textColor="#ffffff"
android:textSize="13dp"
/>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ll_radio_white"
android:paddingLeft="15dp"
android:paddingTop="18dp"
android:paddingRight="15dp"
android:paddingBottom="18dp"
>
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="center"
android:text="Title"
android:textColor="#FF333333"
android:textSize="17dp"
android:textStyle="bold"
/>
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp"
android:layout_marginRight="5dp"
android:gravity="center"
android:text="content"
android:textColor="#FF333333"
android:textSize="13dp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_content"
android:layout_marginTop="15dp"
android:gravity="center"
android:orientation="horizontal"
>
<TextView
android:id="@+id/tv_left"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:background="@drawable/round_button_green"
android:ellipsize="end"
android:gravity="center"
android:lines="1"
android:paddingLeft="33dp"
android:paddingRight="33dp"
android:text="取消"
android:textColor="@color/black"
android:textSize="13dp"
/>
<TextView
android:id="@+id/tv_right"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_marginLeft="35dp"
android:background="@drawable/round_button_green"
android:ellipsize="end"
android:gravity="center"
android:lines="1"
android:paddingLeft="33dp"
android:paddingRight="33dp"
android:text="确定"
android:textColor="@color/black"
android:textSize="13dp"
/>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="@color/black"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/dp_10">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginRight="15dp"
android:background="@drawable/ll_radio_white">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="21dp"
android:gravity="center"
android:text="权限申请"
android:textColor="#FC333333"
android:textSize="17sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title"
android:layout_marginTop="15dp"
android:lineSpacingMultiplier="1.2"
android:paddingLeft="22dp"
android:paddingRight="22dp"
android:gravity="center"
android:text="当前手机版本需要‘授予所有文件的管理权限’ 否则将导致应用无法正常使用,请授予所需权限后使用。"
android:textColor="#FF333333"
android:textSize="14sp" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_below="@+id/tv_content"
android:layout_marginTop="15dp"
android:background="#D6D6D6" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_below="@+id/tv_content"
android:layout_marginTop="15dp"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_left"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="取消"
android:textStyle="bold" />
<View
android:layout_width="0.5dp"
android:layout_height="match_parent"
android:background="#D6D6D6" />
<TextView
android:id="@+id/tv_right"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="确定"
android:textColor="#37A96A"
android:textStyle="bold" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40">
<LinearLayout
android:id="@+id/load_more_loading_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal">
<ProgressBar
android:id="@+id/loading_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleSmall"
android:layout_marginRight="@dimen/dp_4"/>
<TextView
android:id="@+id/loading_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_4"
android:text="@string/loading"
android:textColor="@android:color/black"
android:textSize="@dimen/sp_14"/>
</LinearLayout>
<FrameLayout
android:id="@+id/load_more_load_fail_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<TextView
android:id="@+id/tv_prompt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/load_failed"/>
</FrameLayout>
<FrameLayout
android:id="@+id/load_more_load_end_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/load_end"
android:textColor="@android:color/darker_gray"/>
</FrameLayout>
</FrameLayout>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_gradient"
android:gravity="center"
android:orientation="horizontal"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
>
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@mipmap/ic_toast" />
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textColor="#FFFFFFFF"
android:textSize="14sp" />
</LinearLayout>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/toast_error_bg"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="20dp"
android:paddingTop="12dp"
android:paddingEnd="20dp"
android:paddingBottom="12dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:src="@drawable/toast_error_ic" />
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lineSpacingExtra="5dp"
android:textColor="@android:color/white"
android:textSize="15sp"
tools:text="我是 Toast 文本" />
</LinearLayout>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/toast_hint_bg"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="20dp"
android:paddingTop="12dp"
android:paddingEnd="20dp"
android:paddingBottom="12dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:src="@drawable/toast_info_ic" />
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lineSpacingExtra="5dp"
android:textColor="@android:color/white"
android:textSize="15sp"
tools:text="我是 Toast 文本" />
</LinearLayout>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/round_button_green"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="20dp"
android:paddingTop="12dp"
android:paddingEnd="20dp"
android:paddingBottom="12dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:src="@drawable/toast_success_ic" />
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lineSpacingExtra="5dp"
android:textColor="@android:color/black"
android:textSize="15sp"
tools:text="我是 Toast 文本" />
</LinearLayout>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/toast_warn_bg"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="20dp"
android:paddingTop="12dp"
android:paddingEnd="20dp"
android:paddingBottom="12dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:src="@drawable/toast_warn_ic" />
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lineSpacingExtra="5dp"
android:textColor="@android:color/white"
android:textSize="15sp"
tools:text="我是 Toast 文本" />
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -0,0 +1,39 @@
<resources>
<!--ShapeButton-->
<declare-styleable name="ShapeTextView">
<!--Button圆角-->
<attr name="shapeRadius" format="dimension"></attr>
<!--边框宽度-->
<attr name="shapeStrokeWidth" format="dimension"></attr>
<!--边框颜色-->
<attr name="shapeStrokeColor" format="color"></attr>
<!--背景颜色-->
<attr name="shapeBackgroundColor" format="color"></attr>
<!--背景按下的颜色-->
<attr name="shapeBackgroundSelectorColor" format="color"></attr>
<!--字体粗细-->
<attr name="shapeStorkeWidth" format="float"></attr>
<!--是否自动轮播-->
<attr name="shapeMarquee" format="boolean"></attr>
</declare-styleable>
<!--自定义从顶部下滑View-->
<declare-styleable name="SlideDownView">
<!--左侧图片-->
<attr name="custom_image" format="reference"/>
<!--标题名称-->
<attr name="text_title" format="string"></attr>
<!--标题名称大小-->
<attr name="text_title_size" format="float"></attr>
<!--内容名称-->
<attr name="text_content" format="string"></attr>
<!--内容名称大小-->
<attr name="text_content_size" format="float"></attr>
<!--关闭view所需时间 毫秒-->
<attr name="hide_milliseconds" format="integer"></attr>
<!--view是否居中-->
<attr name="view_center" format="boolean"></attr>
</declare-styleable>
</resources>

View File

@ -0,0 +1,269 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#000000</color>
<color name="white">#FFFFFF</color>
<color name="themr_color_white">#FAFAFA</color><!--淡灰白色 App基本背景颜色-->
<color name="theme_color">#9C78FF</color>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#4285F6</color>
<color name="themeColor">#ffcf06</color>
<color name="blue">#0000FF</color>
<color name="beizhuColor">#55999999</color>
<color name="bg_shense">#A1000000</color>
<color name="transparent">#00000000</color>
<color name="translucent">#22050505</color>
<color name="backGroundColor">#B0EEEEEE</color>
<color name="main_bottom_un_select">#999999</color>
<color name="button_shense">#AD1A1818</color>
<color name="lineColor">#e9e9e9</color>
<color name="indexOptionTextColor">#363636</color>
<color name="login_layout_line">#e5e5e5</color>
<color name="red">#FF0000</color>
<color name="text_color">#333333</color>
<color name="text_color_99">#99333333</color>
<color name="deepskyblue">#00bfff</color><!--深天蓝色 -->
<color name="bg_blue">#1541AE</color><!--蓝色 -->
<color name="wathet">#1B97F7</color><!--蓝色 -->
<!--背景框线条颜色-->
<color name="background_line_color">#cccccc</color>
<!---->
<color name="background_content_color">#ECE1E1</color>
<color name="light_green">#7ecf89</color><!--浅绿-->
<!--按钮字体颜色-->
<color name="register_button_text_color">#eb9224</color>
<!--按钮颜色-->
<color name="confirm_background_color">#777777</color>
<!--暗橘黄色-->
<color name="dark_orange_yellow">#f5f7fc</color>
<!--接单-->
<color name="color_order_receipt">#035496</color>
<!--删除-->
<color name="color_order_delete">#C91204</color>
<!--背景灰色-->
<color name="color_my_transport_order_bg">#D9D9D9</color>
<color name="color_my_transport_order_car_number">#686667</color>
<!--按钮-->
<color name="color_send_out">#AE9301</color>
<!--颜色-->
<color name="color_xyz">#E65425</color>
<color name="DarkOrange">#FF8C00</color>
<color name="blue_zfb">#0C7CD8</color><!-- 支付宝蓝色 -->
<color name="whitesmoke">#f5f5f5</color><!--烟白色 -->
<color name="black333">#333333</color><!-- 微浅黑色 -->
<color name="skyblue">#87ceeb</color><!--天蓝色 -->
<color name="colorYang">#FFE2C59B</color><!--羊皮纸色-->
<color name="ivory">#FFFFFFF0</color><!--象牙色-->
<color name="lightYellow">#FFFFFFE0</color><!--亮黄色-->
<color name="yellow">#FFFFFF00</color><!--黄色-->
<color name="snow">#FFFFFAFA</color><!--雪白色-->
<color name="floralWhite">#FFFFFAF0</color><!--花白色-->
<color name="lemonChiffon">#FFFFFACD</color><!--柠檬绸色-->
<color name="cornSilk">#FFFFF8DC</color><!--米绸色-->
<color name="seashell">#FFFFF5EE</color><!--海贝色-->
<color name="lavenderBlush">#FFFFF0F5</color><!--淡紫红色-->
<color name="papayaWhip">#FFFFEFD5</color><!--番木色-->
<color name="blanchedAlmond">#FFFFEBCD</color><!--白杏色-->
<color name="mistyRose">#FFFFE4E1</color><!--浅玫瑰色-->
<color name="bisque">#FFFFE4C4</color><!--桔黄色-->
<color name="moccasin">#FFFFE4B5</color><!--鹿皮色-->
<color name="navajoWhite">#FFFFDEAD</color><!--纳瓦白-->
<color name="peachPuff">#FFFFDAB9</color><!--桃色-->
<color name="gold">#FFFFD700</color><!--金色-->
<color name="pink">#FFFFC0CB</color><!--粉红色-->
<color name="lightPink">#FFFFB6C1</color><!--亮粉红色-->
<color name="orange">#FFFFA500</color><!--橙色-->
<color name="lightSalmon">#FFFFA07A</color><!--亮肉色-->
<color name="darkOrange">#FFFF8C00</color><!--暗桔黄色-->
<color name="coral">#FFFF7F50</color><!--珊瑚色-->
<color name="hotPink">#FFFF69B4</color><!--热粉红色-->
<color name="tomato">#FFFF6347</color><!--西红柿色-->
<color name="orangeRed">#FFFF4500</color><!--红橙色-->
<color name="deepPink">#FFFF1493</color><!--深粉红色-->
<color name="fuchsia">#FFFF00FF</color><!--紫红色-->
<color name="oldLace">#FFFDF5E6</color><!--老花色-->
<color name="lightGoldenrodYellow">#FFFAFAD2</color><!--亮金黄色-->
<color name="linen">#FFFAF0E6</color><!--亚麻色-->
<color name="antiqueWhite">#FFFAEBD7</color><!--古董白色-->
<color name="salmon">#FFFA8072</color><!--鲜肉色-->
<color name="ghostWhite">#FFF8F8FF</color><!--幽灵白-->
<color name="mintCream">#FFF5FFFA</color><!--薄荷色-->
<color name="whiteSmoke">#FFF5F5F5</color><!--烟白色-->
<color name="beige">#FFF5F5DC</color><!--米色-->
<color name="wheat">#FFF5DEB3</color><!--浅黄色-->
<color name="sandyBrown">#FFF4A460</color><!--沙褐色-->
<color name="azure">#FFF0FFFF</color><!--天蓝色-->
<color name="aliceBlue">#FFF0F8FF</color><!--艾利斯兰色-->
<color name="khaki">#FFF0E68C</color><!--黄褐色-->
<color name="lightCoral">#FFF08080</color><!--亮珊瑚色-->
<color name="paleGoldenrod">#FFEEE8AA</color><!--苍麒麟色-->
<color name="violet">#FFEE82EE</color><!--紫罗兰色-->
<color name="darkSalmon">#FFE9967A</color><!--暗肉色-->
<color name="lavender">#FFE6E6FA</color><!--淡紫色-->
<color name="lightCyan">#FFE0FFFF</color><!--亮青色-->
<color name="burlyWood">#FFDEB887</color><!--实木色-->
<color name="plum">#FFDDA0DD</color><!--洋李色-->
<color name="lightGrey">#FFDCDCDC</color><!--淡灰色-->
<color name="crimson">#FFDC143C</color><!--暗深红色-->
<color name="paleVioletRed">#FFDB7093</color><!--苍紫罗兰色-->
<color name="goldenrod">#FFDAA520</color><!--金麒麟色-->
<color name="orchid">#FFDA70D6</color><!--淡紫色-->
<color name="thistle">#FFD8BFD8</color><!--蓟色-->
<color name="lightGray">#FFD3D3D3</color><!--亮灰色-->
<color name="tan">#FFD2B48C</color><!--茶色-->
<color name="chocolate">#FFD2691E</color><!--巧可力色-->
<color name="peru">#FFCD853F</color><!--秘鲁色-->
<color name="indianRed">#FFCD5C5C</color><!--印第安红色-->
<color name="mediumVioletRed">#FFC71585</color><!--中紫罗兰色-->
<color name="silver">#FFC0C0C0</color><!--银色-->
<color name="darkKhaki">#FFBDB76B</color><!--暗黄褐色-->
<color name="rosyBrown">#FFBC8F8F</color><!--褐玫瑰红色-->
<color name="mediumOrchid">#FFBA55D3</color><!--中粉紫色-->
<color name="darkGoldenrod">#FFB8860B</color><!--暗金黄色-->
<color name="firebrick">#FFB22222</color><!--火砖色-->
<color name="powderBlue">#FFB0E0E6</color><!--粉蓝色-->
<color name="lightSteelBlue">#FFB0C4DE</color><!--亮钢兰色-->
<color name="paleTurquoise">#FFAFEEEE</color><!--苍宝石绿色-->
<color name="greenYellow">#FFADFF2F</color><!--黄绿色-->
<color name="lightBlue">#FFADD8E6</color><!--亮蓝色-->
<color name="darkGray">#FFA9A9A9</color><!--暗灰色-->
<color name="brown">#FFA52A2A</color><!--褐色-->
<color name="sienna">#FFA0522D</color><!--赭色-->
<color name="darkOrchid">#FF9932CC</color><!--暗紫色-->
<color name="paleGreen">#FF98FB98</color><!--苍绿色-->
<color name="darkViolet">#FF9400D3</color><!--暗紫罗兰色-->
<color name="mediumPurple">#FF9370DB</color><!--中紫色-->
<color name="lightGreen">#FF90EE90</color><!--亮绿色-->
<color name="darkSeaGreen">#FF8FBC8F</color><!--暗海兰色-->
<color name="saddleBrown">#FF8B4513</color><!--重褐色-->
<color name="darkMagenta">#FF8B008B</color><!--暗洋红色-->
<color name="darkRed">#FF8B0000</color><!--暗红色-->
<color name="blueViolet">#FF8A2BE2</color><!--紫罗兰蓝色-->
<color name="lightSkyBlue">#FF87CEFA</color><!--亮天蓝色-->
<color name="skyBlue">#FF87CEEB</color><!--天蓝色-->
<color name="gray">#FF808080</color><!--灰色-->
<color name="olive">#FF808000</color><!--橄榄色-->
<color name="purple">#FF800080</color><!--紫色-->
<color name="maroon">#FF800000</color><!--粟色-->
<color name="aquamarine">#FF7FFFD4</color><!--碧绿色-->
<color name="chartreuse">#FF7FFF00</color><!--黄绿色-->
<color name="lawnGreen">#FF7CFC00</color><!--草绿色-->
<color name="mediumSlateBlue">#FF7B68EE</color><!--中暗蓝色-->
<color name="lightSlateGray">#FF778899</color><!--亮蓝灰色-->
<color name="slateGray">#FF708090</color><!--灰石色-->
<color name="oliveDrab">#FF6B8E23</color><!--深绿褐色-->
<color name="slateBlue">#FF6A5ACD</color><!--石蓝色-->
<color name="dimGray">#FF696969</color><!--暗灰色-->
<color name="mediumAquamarine">#FF66CDAA</color><!--中绿色-->
<color name="cornFlowerBlue">#FF6495ED</color><!--菊兰色-->
<color name="cadetBlue">#FF5F9EA0</color><!--军兰色-->
<color name="darkOliveGreen">#FF556B2F</color><!--暗橄榄绿色-->
<color name="indigo">#FF4B0082</color><!--靛青色-->
<color name="mediumTurquoise">#FF48D1CC</color><!--中绿宝石色-->
<color name="darkSlateBlue">#FF483D8B</color><!--暗灰蓝色-->
<color name="steelBlue">#FF4682B4</color><!--钢兰色-->
<color name="royalBlue">#FF4169E1</color><!--皇家蓝色-->
<color name="turquoise">#FF40E0D0</color><!--青绿色-->
<color name="mediumSeaGreen">#FF3CB371</color><!--中海蓝色-->
<color name="limeGreen">#FF32CD32</color><!--橙绿色-->
<color name="darkSlateGray">#FF2F4F4F</color><!--暗瓦灰色-->
<color name="seaGreen">#FF2E8B57</color><!--海绿色-->
<color name="forestGreen">#FF228B22</color><!--森林绿色-->
<color name="lightSeaGreen">#FF20B2AA</color><!--亮海蓝色-->
<color name="dodgerBlue">#FF1E90FF</color><!--闪兰色-->
<color name="midnightBlue">#FF191970</color><!--中灰兰色-->
<color name="aqua">#FF00FFFF</color><!--浅绿色-->
<color name="springGreen">#FF00FF7F</color><!--春绿色-->
<color name="lime">#FF00FF00</color><!--酸橙色-->
<color name="mediumSpringGreen">#FF00FA9A</color><!--中春绿色-->
<color name="darkTurquoise">#FF00CED1</color><!--暗宝石绿色-->
<color name="deepSkyBlue">#FF00BFFF</color><!--深天蓝色-->
<color name="darkCyan">#FF008B8B</color><!--暗青色-->
<color name="teal">#FF008080</color><!--水鸭色-->
<color name="green">#FF008000</color><!--绿色-->
<color name="darkGreen">#FF006400</color><!--暗绿色-->
<color name="mediumBlue">#FF0000CD</color><!--中兰色-->
<color name="darkBlue">#FF00008B</color><!--暗蓝色-->
<color name="navy">#FF000080</color><!--海军色-->
<color name="unBlack">#FF2B2B2B</color><!--不知名黑色-->
<color name="textcolor_white_a">#ffffff</color>
<color name="textcolor_black_b1">#111111</color>
<color name="textcolor_black_b2">#666666</color>
<color name="textcolor_black_b3">#999999</color>
<color name="textcolor_black_b4">#bbbbbb</color>
<color name="textcolor_black_b5">#828282</color>
<color name="textcolor_blue_c">#0099ff</color>
<color name="textcolor_blue_c2">#a9dbfc</color>
<color name="textcolor_blue_text">#006ec1</color>
<color name="textcolor_blue_text_refresh">#4b83a9</color>
<color name="textcolor_red_d">#e5533b</color>
<color name="textcolor_red_text">#c2001e</color>
<color name="textcolor_green_e">#19aa49</color>
<color name="background_bg1">#ebebe9</color>
<color name="background_bg2">#d1d1d1</color>
<color name="background_bg3">#ff0000</color>
<color name="background_bg7">#f6f6f5</color>
<color name="background_bg5">#f5f5f5</color>
<color name="background_bg9">#e0e0e0</color>
<color name="dark">#FF222222</color><!-- 暗色 -->
<color name="light">#FFEEEEEE</color><!-- 亮色 -->
<color name="gestureline_green">#00cd56</color>
<color name="gestureline_red">#99E0260C</color>
<color name="highlight">#45C01A</color>
<color name="refresh_blue">#A80375c2</color>
<drawable name="more_popu_pressed">#d9d9d9</drawable>
<drawable name="more_popu_normal">#ffffff</drawable>
<drawable name="background_bg5">#ebebeb</drawable>
<drawable name="contact_bottom_popu_normal">#ebebe9</drawable>
<color name="color_ll_normal">#fff</color>
<color name="color_ll_press">#e5e5e5</color>
<color name="color_head_press">#666</color>
<color name="color_main">#f2f2f2</color>
<color name="color_gray">#999</color>
<color name="color_black">#000</color>
<color name="color_black_light">#222</color>
<color name="color_red">#f22121</color>
<color name="color_blue">#0099cc</color>
<color name="color_blue_trans">#7A0099cc</color>
<color name="color_gray_unable">#333</color>
<color name="textcolor_black_trans">#66000000</color>
<color name="textcolor_black_bb">#333333</color>
<color name="textcolor_black_forget">#666666</color>
<color name="menu_title_color">#333333</color>
<color name="menu_sub_title_color">#72747B</color>
<color name="menu_color">#666666</color>
<color name="menu_stroke">#888888</color>
<color name="menu_stroke_live">#4DFFFFFF</color>
<color name="menu_selected_live">#33E5E5E5</color>
<color name="menu_selected_color">#FFFFFF</color>
<color name="bg_color">#F2F6FA</color>
<color name="player_style_pre">#CC3DA6EC</color>
<!-- 吐司 -->
<color name="toast_hint_color">#3F51B5</color>
<color name="toast_success_color">#388E3C</color>
<color name="toast_warn_color">#FFA900</color>
<color name="toast_warn_color2">#ffcf06</color>
<color name="toast_error_color">#D50000</color>
</resources>

View File

@ -0,0 +1,9 @@
<resources>
<!--id-->
<item name="main_layout" type="id"/>
<item name="image_view" type="id"/>
<item name="tv_title" type="id"/>
<item name="tv_content" type="id"/>
<item name="view_space" type="id"/>
</resources>

View File

@ -0,0 +1,222 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
<!-- 标签栏菜单主样式-->
<style name="menu">
<item name="android:gravity">center</item>
<item name="android:button">@null</item>
<item name="android:textColor">#3d4038</item>
</style>
<style name="BaseAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- &lt;!&ndash; Customize your theme here. &ndash;&gt;
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">#FFFFFF</item>
<item name="colorAccent">@color/colorAccent</item>
&lt;!&ndash;<item name="android:windowBackground">@android:color/transparent</item>&ndash;&gt;
&lt;!&ndash;<item name="android:windowAnimationStyle">@style/ActivityInOutAnimation</item>&ndash;&gt;
<item name="android:windowIsTranslucent">true</item>-->
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="toolbarStyle">@color/colorAccent</item>
</style>
<style name="SplashTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowLayoutInDisplayCutoutMode" tools:ignore="NewApi">shortEdges</item>
</style>
<style name="AppTheme.Main" parent="BaseAppTheme" />
<!--activity的启动和退出动画-->
<style name="ActivityInOutAnimation" parent="android:style/Animation.Translucent">
<item name="android:activityOpenEnterAnimation">@anim/activity_in_animation</item>
<item name="android:activityOpenExitAnimation">@anim/activity_out_animation</item>
<item name="android:activityCloseEnterAnimation">@anim/activity_in_animation</item>
<item name="android:activityCloseExitAnimation">@anim/activity_out_animation</item>
</style>
<!--项目中的dailog向上滑入的动画-->
<style name="CustomDialog" parent="@android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowBackground">@color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowEnterAnimation">@anim/dialog_show_enter</item>
<item name="android:windowExitAnimation">@anim/dialog_show_exis</item>
</style>
<!--打电话弹窗-->
<style name="CallTelPhoneDialog" parent="@android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowBackground">@color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowEnterAnimation">@anim/dialog_show_enter</item>
<item name="android:windowExitAnimation">@anim/dialog_show_exis</item>
</style>
<style name="choose_register" parent="Theme.AppCompat.Light">
<item name="colorControlNormal">#737070</item>
<item name="colorControlActivated">@color/themeColor</item>
</style>
<style name="FloatWindowAnimation">
<item name="android:windowEnterAnimation">@anim/anim_float_window_enter</item>
<item name="android:windowExitAnimation">@anim/anim_float_window_exit</item>
</style>
<style name="Theme.PictureInPicture" parent="Theme.MaterialComponents.DayNight.NoActionBar" />
<!--继承AppCompatActivity时设置全屏-->
<style name="NoTitleFullscreen" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<!--<style name="notitle">
<item name="android:windowNoTitle">true</item>
</style>-->
<declare-styleable name="DoubleHeadedDragonBar">
<!--进度条按钮宽高-->
<attr name="button_width" format="dimension" />
<attr name="button_height" format="dimension" />
<!--进图条按钮图片-->
<attr name="button_img" format="reference" />
<!--单位字体颜色-->
<attr name="text_color" format="color" />
<!--进图条背景颜色-->
<attr name="bg_color" format="color" />
<!--进度条颜色-->
<attr name="value_color" format="color" />
<!--进度条宽-->
<attr name="seek_height" format="dimension" />
</declare-styleable>
<!-- 自定义仿IOS的ActionSheet底部Dialog的样式 ,有模糊效果 -->
<style name="ActionGeneralDialog" parent="@android:style/Theme.Dialog">
<!-- 背景透明 -->
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<!-- 浮于Activity之上 -->
<item name="android:windowIsFloating">true</item>
<!-- 边框 -->
<item name="android:windowFrame">@null</item>
<!-- Dialog以外的区域模糊效果 -->
<item name="android:backgroundDimEnabled">true</item>
<!-- 无标题 -->
<item name="android:windowNoTitle">true</item>
<!-- 半透明 -->
<item name="android:windowIsTranslucent">true</item>
<!-- Dialog进入及退出动画 -->
<item name="android:windowAnimationStyle">@style/ActionSheetDialogAnimation</item>
</style>
<!-- ActionSheet进出动画 -->
<style name="ActionSheetDialogAnimation" parent="@android:style/Animation.Dialog">
<item name="android:windowEnterAnimation">@anim/actionsheet_dialog_in</item>
<item name="android:windowExitAnimation">@anim/actionsheet_dialog_out</item>
</style>
<!--从下而上Dialog出场动画主题样式-->
<style name="MenuButtomAnimationStyle" parent="android:style/Theme.Dialog">
<!-- 是否有标题-->
<item name="android:windowNoTitle">true</item>
<!--背景颜色及透明程度-->
<item name="android:windowBackground">@android:color/transparent</item>
<!--是否浮现在activity之上-->
<item name="android:windowIsFloating">true</item>
<!--是否模糊-->
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowCloseOnTouchOutside">true</item>
<item name="android:windowAnimationStyle">@style/MusicButtomAnimation</item>
</style>
<!--从下而上动画-->
<style name="MusicButtomAnimation">
<!-- 入场动画 -->
<item name="android:windowEnterAnimation">@anim/bottom_menu_enter</item>
<!-- 出厂动画 -->
<item name="android:windowExitAnimation">@anim/bottom_menu_exit</item>
</style>
<!--中间弹窗式Activity-->
<style name="ActivityCenterDialogAnimation" parent="@style/Theme.AppCompat.Light.NoActionBar">
<!-- 是否有标题-->
<item name="android:windowNoTitle">true</item>
<!--背景颜色及透明程度-->
<item name="android:windowBackground">@android:color/transparent</item>
<!--是否浮现在activity之上-->
<item name="android:windowIsFloating">true</item>
<!--是否模糊-->
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowCloseOnTouchOutside">true</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
</style>
<!--播放器标题-->
<style name="MusicTitleStyle">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_gravity">center_vertical</item>
<item name="android:gravity">center_vertical</item>
<item name="android:ellipsize">marquee</item>
<item name="android:singleLine">true</item>
<item name="android:textSize">16dp</item>
<item name="android:textColor">#FFFFFF</item>
</style>
<!--播放器时间字体样式-->
<style name="MusicTimeStyle">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_gravity">center_vertical</item>
<item name="android:textSize">12dp</item>
<item name="android:textColor">#FFFFFFFF</item>
<item name="android:background">?attr/selectableItemBackground</item>
</style>
<!--从屏幕中间出场的动画样式-->
<style name="CenterDialogAnimationStyle" parent="Animation.AppCompat.Dialog">
<!-- 是否有标题-->
<item name="android:windowNoTitle">true</item>
<!--背景颜色及透明程度-->
<item name="android:windowBackground">@android:color/transparent</item>
<!--是否浮现在activity之上-->
<item name="android:windowIsFloating">true</item>
<!--是否模糊-->
<item name="android:backgroundDimEnabled">true</item>
</style>
<!--锁屏Theme-->
<style name="MusicLockScreenTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">false</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:windowContentOverlay">@null</item>
</style>
</resources>

View File

@ -0,0 +1,17 @@
package com.tfq.library;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

210
LICENSE
View File

@ -1,73 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2025 app-lib
Copyright [yyyy] [name of copyright owner]
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
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
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.
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.

1
LibraryAd/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

115
LibraryAd/build.gradle Normal file
View File

@ -0,0 +1,115 @@
plugins {
id 'com.android.library' // application
id 'maven-publish' //
}
//apply plugin: 'com.kezong.fat-aar'
android {
namespace 'com.tfq.libraryad'
compileSdkVersion 34
defaultConfig {
minSdkVersion 21
targetSdkVersion 34
}
buildTypes {
release {
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
// assets.srcDirs += ['../android_data/csj_config']
}
}
}
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
// implementation fileTree(include: ['*.aar', '*.jar'], dir: 'libs')
compileOnly fileTree(include: ['*.aar', '*.jar'], dir: 'libs')
// implementation name: 'GDTSDK.unionNormal.4.610.1480', ext: 'aar'
// implementation name: 'mediation_gdt_adapter_4.610.1480.0', ext: 'aar'
// implementation name: 'open_ad_sdk_6.6.0.7', ext: 'aar'
//
// implementation 'androidx.appcompat:appcompat:1.4.1'
// implementation 'com.google.android.material:material:1.5.0'
// testImplementation 'junit:junit:4.13.2'
// androidTestImplementation 'androidx.test.ext:junit:1.1.3'
// androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//
// api 'com.gyf.immersionbar:immersionbar:3.0.0-beta05'
//
// api 'com.github.getActivity:XXPermissions:18.63'
// api 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.28'
// api 'androidx.activity:activity:1.3.0'
api project(':BaseLibrary')
// implementation project(':LocalAarModules:AdCSJSdk')
// implementation project(':LocalAarModules:AdGDTSdk')
// implementation project(':LocalAarModules:AdGDTSdk_Adapter')
//noinspection Aligned16KB
// implementation 'com.pangle.cn:mediation-sdk:6.6.0.7' //穿SDK
// implementation 'com.pangle.cn:GDTSDK-unionNormal:4.610.1480' //GDT
// implementation 'com.pangle.cn:mediation-gdt-adapter:4.610.1480.0' //GDT adapter
}
afterEvaluate {
publishing {
publications {
release(MavenPublication) {
groupId = 'com.jiangke.group' //
artifactId = 'JKBaseLib' //
version = '1.0.0'
artifact("$buildDir/outputs/aar/${project.name}-release.aar")// AAR
}
}
repositories {
maven {
// url = "file://${projectDir.parent}/maven-repo" //
url = "file://${projectDir.parent}/maven" //
}
/*maven {
url = "https://gitee.com/jiangke/JKBaseLib/raw/master/maven/"
credentials {
username = project.findProperty("gitee.user") ?: ""
password = project.findProperty("gitee.token") ?: ""
}
}*/
}
}
}
/*publishing {
publications {
maven(MavenPublication) {
groupId = 'com.jiangke.group' //
artifactId = 'lib-name' //
version = '1.0.0' //
// AAR
artifact("$buildDir/outputs/aar/${project.name}-release.aar")
}
}
repositories {
maven {
url "file://D:/Android/Code/tfq/JKBaseLib" //
}
}
}*/

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<!--可选权限,申请后用于防作弊功能以及有助于广告平台投放广告-->
<!-- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />-->
<permission
android:name="${applicationId}.openadsdk.permission.TT_PANGOLIN"
android:protectionLevel="signature"
/>
<uses-permission android:name="${applicationId}.openadsdk.permission.TT_PANGOLIN" />
<!--建议添加“query_all_package”权限穿山甲将通过此权限在Android R系统上判定广告对应的应用是否在用户的app上安装避免投放错误的广告以此提高用户的广告体验。若添加此权限需要在您的用户隐私文档中声明 -->
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission"
/>
<!-- <uses-permission android:name="android.permission.GET_TASKS" />-->
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
<!-- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />-->
<uses-permission
android:name="android.permission.GET_TOP_ACTIVITY_INFO"
tools:ignore="ProtectedPermissions"
/>
<application
android:allowBackup="true"
android:supportsRtl="true"
>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<!-- 穿山甲 start================== -->
<provider
android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
android:authorities="${applicationId}.TTFileProvider"
android:exported="false"
android:grantUriPermissions="true"
>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"
/>
</provider>
<provider
android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
android:authorities="${applicationId}.TTMultiProvider"
android:exported="false"
/>
<!-- 穿山甲 end================== -->
<!-- GDT start================== -->
<!-- targetSDKVersion >= 24时才需要添加这个provider。provider的authorities属性的值为${applicationId}.fileprovider请开发者根据自己的${applicationId}来设置这个值例如本例中applicationId为"com.qq.e.union.demo"。 -->
<provider
android:name="com.qq.e.comm.GDTFileProvider"
android:authorities="${applicationId}.gdt.fileprovider"
android:exported="false"
android:grantUriPermissions="true"
>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/gdt_file_path"
/>
</provider>
<activity
android:name="com.qq.e.ads.PortraitADActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait"
tools:replace="android:screenOrientation"
/>
<activity
android:name="com.qq.e.ads.LandscapeADActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:screenOrientation="sensorLandscape"
tools:replace="android:screenOrientation"
/>
<!-- 声明SDK所需要的组件 -->
<service
android:name="com.qq.e.comm.DownloadService"
android:exported="false"
/>
<!-- 请开发者注意字母的大小写ADActivity而不是AdActivity -->
<activity
android:name="com.qq.e.ads.ADActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:screenOrientation="landscape"
tools:replace="android:screenOrientation"
/>
<!-- GDT end================== -->
<activity
android:name="com.tfq.ad.ad.activity.AdSplashActivity"
android:screenOrientation="portrait"
android:theme="@style/SplashTheme"
tools:replace="android:screenOrientation"
/>
</application>
</manifest>

View File

@ -0,0 +1,107 @@
package com.tfq.ad.ad;
import android.app.Activity;
import android.content.Context;
import com.google.gson.Gson;
import com.tfq.ad.bean.AdvBean;
import com.tfq.ad.bean.UserInfo;
import com.tfq.library.app.BaseConstants;
import com.tfq.library.utils.LogK;
public class ADUtils {
private static Activity mContext;
private static String type;
public ADUtils(String type, Context mContext) {
this.mContext = (Activity) mContext;
this.type = type;
regexSwitch();
}
public boolean regexSwitch() {
BaseConstants._isShow = false;
boolean b = false;
if (BaseConstants.AD_Switch_Requested) {
boolean _type;
switch (type) {
case "GMSplashAd"://开屏
_type = BaseConstants.AD_SPLASH;
break;
case "GMRewardAd"://激励
_type = BaseConstants.AD_REWARD;
break;
case "GMInterstitialFullAd"://插全屏
_type = BaseConstants.AD_CQP;
break;
case "GMNativeAd"://信息流
_type = BaseConstants.AD_NATIVE;
break;
case "GMBannerAd"://banner
_type = BaseConstants.AD_BANNER;
break;
default:
_type = false;
break;
}
LogK.e("广告类型=" + type
+ " 穿山甲是否正常=" + BaseConstants.adv_csj
+ " 强制无广告=" + BaseConstants.NO_AD
+ " 当前广告类型是开=" + _type);
if (BaseConstants.adv_csj && !BaseConstants.NO_AD && _type) {
b = true;
}
return b;
} else {
getPlatform();
}
return b;
}
private void getPlatform() {
new UserInfo().getAdvertising(new UserInfo.Success() {
@Override
public void Success(String data, String msg) {
try {
Gson gson = new Gson();
AdvBean entity = gson.fromJson(data, AdvBean.class);
if (entity.getData() != null) {
AdvBean.DataDTO entityData = entity.getData();
if ("1".equals(entityData.getAdv1Flag())) {
BaseConstants.AD_SPLASH = true;
}
if ("1".equals(entityData.getAdv2Flag())) {
BaseConstants.AD_REWARD = true;
}
if ("1".equals(entityData.getAdv3Flag())) {
BaseConstants.AD_NATIVE = true;
}
if ("1".equals(entityData.getAdv4Flag())) {
BaseConstants.AD_CQP = true;
}
if ("1".equals(entityData.getAdv5Flag())) {
BaseConstants.AD_BANNER = true;
}
if ("1".equals(entityData.getAdv6Flag())) {
BaseConstants.AD_DRAW = true;
}
if (entityData.getAdv4Wait() > 0) {
BaseConstants.ADV_Wait = entityData.getAdv4Wait();
}
} else {
BaseConstants.adv_csj = false;
}
} catch (Exception e) {
e.printStackTrace();
}
BaseConstants.AD_Switch_Requested = true;
}
@Override
public void fail(int num, String msg) {
}
});
}
}

View File

@ -0,0 +1,209 @@
package com.tfq.ad.ad;
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import com.bytedance.sdk.openadsdk.AdSlot;
import com.bytedance.sdk.openadsdk.TTAdDislike;
import com.bytedance.sdk.openadsdk.TTAdNative;
import com.bytedance.sdk.openadsdk.TTFeedAd;
import com.bytedance.sdk.openadsdk.TTNativeExpressAd;
import com.tfq.library.app.BaseConstants;
import com.tfq.library.utils.LogK;
import java.util.List;
public class AdBannerUtils {
private static Context mContext;
private static String mAdUnitId = BaseConstants.CODE_AD_BANNER;
private static int width = 0;
private static Listener listener;
//判断大于多少秒
private static int interval = 10;
private static long lastTime = 0;
private static TTNativeExpressAd mBannerAd; // Banner广告对象
private static TTAdNative.NativeExpressAdListener mBannerListener; // 广告加载监听器
private static TTNativeExpressAd.ExpressAdInteractionListener mBannerInteractionListener; // 广告展示监听器
private static TTAdDislike.DislikeInteractionCallback mDislikeCallback; // 接受广告关闭回调
private static FrameLayout mBannerContainer; // banner广告容器view
public static void show_ad(Context context, FrameLayout layout) {
mContext = context;
mBannerContainer = layout;
if (new ADUtils("GMBannerAd", mContext).regexSwitch()) {
loadAD();
}
}
public static void show_ad(Context mContext, FrameLayout mBannerContainer, int i_width) {
width = i_width;
show_ad(mContext, mBannerContainer);
}
public static void show_ad(Context mContext, String adUnitId, FrameLayout mBannerContainer, int i_width) {
width = i_width;
mAdUnitId = adUnitId;
show_ad(mContext, mBannerContainer);
}
public static void show_ad(Context mContext, FrameLayout mBannerContainer, int width, Listener thislistener) {
listener = thislistener;
show_ad(mContext, mBannerContainer, width);
}
private static boolean interval() {
if (System.currentTimeMillis() - lastTime > (100 * interval)) {
return true;
} else {
return false;
}
}
private static void loadAD() {
/** 1、创建AdSlot对象 */
int width = (int) (UIUtils.getScreenWidthDp(mContext) - AdBannerUtils.width);
int height = (int) ((UIUtils.getScreenWidthDp(mContext) - AdBannerUtils.width) / 4);
// height = 0;
LogK.e("AdBannerUtils mAdUnitId=" + mAdUnitId);
AdSlot adSlot = new AdSlot.Builder()
.setCodeId(mAdUnitId)
.setImageAcceptedSize(UIUtils.dp2px(mContext, width), UIUtils.dp2px(mContext, height)) // 单位px
.build();
/** 2、创建TTAdNative对象 */
TTAdNative adNativeLoader = TTAdManagerHolder.get().createAdNative(mContext);
/** 3、创建加载、展示监听器 */
initListeners();
/** 4、加载广告 */
adNativeLoader.loadBannerExpressAd(adSlot, mBannerListener);
}
/**
* 5广告加载成功后设置监听器展示广告
*/
private static void showBannerAd() {
if (mBannerAd != null) {
mBannerAd.setExpressInteractionListener(mBannerInteractionListener);
mBannerAd.setDislikeCallback((Activity) mContext, mDislikeCallback);
mBannerAd.uploadDislikeEvent("mediation_dislike_event");
/** 注意使用融合功能时load成功后可直接调用getExpressAdView获取广告view展示而无需调用render等onRenderSuccess后 */
View bannerView = mBannerAd.getExpressAdView();
if (bannerView != null && mBannerContainer != null) {
mBannerContainer.removeAllViews();
mBannerContainer.addView(bannerView);
}
mBannerAd.setSlideIntervalTime(5);
} else {
LogK.e("请先加载广告或等待广告加载完毕后再展示广告");
}
}
private static void initListeners() {
// 广告加载监听器
mBannerListener = new TTAdNative.NativeExpressAdListener() {
@Override
public void onError(int i, String s) {
LogK.e("banner load fail: errCode: " + i + ", errMsg: " + s);
}
@Override
public void onNativeExpressAdLoad(List<TTNativeExpressAd> list) {
if (list != null && list.size() > 0) {
LogK.e("banner load success");
mBannerAd = list.get(0);
showBannerAd();
} else {
LogK.e("banner load success, but list is null");
}
}
};
// 广告展示监听器
mBannerInteractionListener = new TTNativeExpressAd.ExpressAdInteractionListener() {
@Override
public void onAdClicked(View view, int i) {
LogK.e("banner clicked");
}
@Override
public void onAdShow(View view, int i) {
LogK.e("banner showed");
}
@Override
public void onRenderFail(View view, String s, int i) {
// 注意使用融合功能时无需调用renderload成功后可调用mBannerAd.getExpressAdView()进行展示
}
@Override
public void onRenderSuccess(View view, float v, float v1) {
// 注意使用融合功能时无需调用renderload成功后可调用mBannerAd.getExpressAdView()获取view进行展示
// 如果调用了render则会直接回调onRenderSuccess***** 参数view为null请勿使用*****
}
};
// dislike监听器广告关闭时会回调onSelected
mDislikeCallback = new TTAdDislike.DislikeInteractionCallback() {
@Override
public void onShow() {
}
@Override
public void onSelected(int i, String s, boolean b) {
if (mBannerContainer != null)
mBannerContainer.removeAllViews();
LogK.e("banner closed");
}
@Override
public void onCancel() {
}
};
}
private static void removeAdView() {
if (mBannerAd != null) {
mBannerAd.destroy();
}
if (mBannerContainer != null) {
mBannerContainer.removeAllViews();
}
}
public static View getBannerAdView(Context mContext) {
FrameLayout drawAdView = new FrameLayout(mContext);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, // 宽度
RelativeLayout.LayoutParams.WRAP_CONTENT // 高度
);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
AdBannerUtils.show_ad(mContext, drawAdView, 10);
return drawAdView;
}
public interface Listener {
void success(boolean b);
}
public interface ListenerAD {
void success(TTFeedAd ad);
}
}

View File

@ -0,0 +1,176 @@
package com.tfq.ad.ad;
import android.app.Activity;
import android.content.Context;
import com.bytedance.sdk.openadsdk.AdSlot;
import com.bytedance.sdk.openadsdk.TTAdConstant;
import com.bytedance.sdk.openadsdk.TTAdNative;
import com.bytedance.sdk.openadsdk.TTAdSdk;
import com.bytedance.sdk.openadsdk.TTFullScreenVideoAd;
import com.tfq.library.app.BaseConstants;
import com.tfq.library.utils.LogK;
public class AdCQPUtils {
private CQP listener;
private CQP_Load_Success cqp_load_success;
private String mAdUnitId = BaseConstants.CODE_AD_CQP;
public interface CQP {
void success(boolean b);
}
public interface CQP_Load_Success {
void success(boolean b);
}
//判断大于多少秒可以下一次开启
int interval = BaseConstants.ADV_Wait;
static long lastTime = 0;
private boolean interval() {
if (System.currentTimeMillis() - lastTime > (1000 * interval)) {
return true;
} else {
return false;
}
}
public AdCQPUtils() {
}
public AdCQPUtils(Context mContext, boolean load, CQP listener) {
this.listener = listener;
init(mContext, load);
}
public AdCQPUtils(Context mContext, boolean load, String mAdUnitId, CQP_Load_Success cqp_load_success) {
this.cqp_load_success = cqp_load_success;
this.mAdUnitId = mAdUnitId;
init(mContext, load);
}
public void init(Context mContext) {
init(mContext, true);
}
public void init(Context mContext, boolean load) {
boolean csj = true;
if (new ADUtils("GMInterstitialFullAd", mContext).regexSwitch() && csj && interval()) {
loadInterstitialFullAd(mContext);
} else {
if (listener != null) {
listener.success(false);
listener = null;
}
if (cqp_load_success != null) {
cqp_load_success.success(false);
cqp_load_success = null;
}
}
}
private void loadInterstitialFullAd(Context mContext) {
TTAdNative adNativeLoader = TTAdSdk.getAdManager().createAdNative(mContext);
AdSlot adslot = new AdSlot.Builder()
.setCodeId(mAdUnitId)
.setOrientation(TTAdConstant.VERTICAL)
.setUserID("user121")
.build();
adNativeLoader.loadFullScreenVideoAd(adslot, new TTAdNative.FullScreenVideoAdListener() {
@Override
public void onError(int code, String message) {
LogK.e("Screen onError code = " + code + " message = " + message);
if (listener != null) {
listener.success(false);
listener = null;
}
if (cqp_load_success != null) {
cqp_load_success.success(false);
cqp_load_success = null;
}
}
@Override
public void onFullScreenVideoAdLoad(TTFullScreenVideoAd ttFullScreenVideoAd) {
showInterstitialFullAd(ttFullScreenVideoAd, mContext);
}
@Override
public void onFullScreenVideoCached() {
LogK.e("onFullScreenVideoCached");
}
@Override
public void onFullScreenVideoCached(TTFullScreenVideoAd ttFullScreenVideoAd) {
LogK.e("onFullScreenVideoCached");
showInterstitialFullAd(ttFullScreenVideoAd, mContext);
}
});
}
private void showInterstitialFullAd(TTFullScreenVideoAd ttFullScreenVideoAd, Context mContext) {
if (ttFullScreenVideoAd == null) {
return;
} else {
ttFullScreenVideoAd.setFullScreenVideoAdInteractionListener(new TTFullScreenVideoAd.FullScreenVideoAdInteractionListener() {
@Override
public void onAdShow() {
LogK.e("InterstitialFullActivity onAdShow");
if (cqp_load_success != null) {
cqp_load_success.success(true);
cqp_load_success = null;
}
lastTime = System.currentTimeMillis();
}
@Override
public void onAdVideoBarClick() {
LogK.e("InterstitialFullActivity onAdVideoBarClick");
}
@Override
public void onAdClose() {
LogK.e("InterstitialFullActivity onAdClose");
if (listener != null) {
listener.success(false);
listener = null;
}
}
@Override
public void onVideoComplete() {
LogK.e("InterstitialFullActivity onVideoComplete");
}
@Override
public void onSkippedVideo() {
LogK.e("InterstitialFullActivity onSkippedVideo");
}
});
ttFullScreenVideoAd.showFullScreenVideoAd((Activity) mContext);
}
}
/**
* 展示广告
*/
public void showInterFullAd(Context mContext, CQP listene) {
this.listener = listene;
boolean csj = true;
if (new ADUtils("GMInterstitialFullAd", mContext).regexSwitch() && csj) {
loadInterstitialFullAd(mContext);
} else {
if (listener != null) {
listener.success(false);
listener = null;
}
if (cqp_load_success != null) {
cqp_load_success.success(false);
cqp_load_success = null;
}
}
}
}

View File

@ -0,0 +1,343 @@
package com.tfq.ad.ad;
import android.app.Activity;
import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.bytedance.sdk.openadsdk.AdSlot;
import com.bytedance.sdk.openadsdk.TTAdDislike;
import com.bytedance.sdk.openadsdk.TTAdNative;
import com.bytedance.sdk.openadsdk.TTAdSdk;
import com.bytedance.sdk.openadsdk.TTFeedAd;
import com.bytedance.sdk.openadsdk.mediation.ad.MediationExpressRenderListener;
import com.tfq.library.app.BaseConstants;
import com.tfq.library.utils.LogK;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AdFeedUtils {
public static Map<String, Boolean> map = new HashMap<>();
public static Map<String, Boolean> locationMap;
private static Context mContext;
private static String mAdUnitId = LoopAd.getCurrentFeedID();
private static String tag;
private static int width = 0;
private static TTAdNative adNativeLoader;
private static Listener listener;
private static ListenerAD listenerAD;
private static boolean mIsLoadedAndShow;
private static TTFeedAd mTTFeedAd;
private static FrameLayout mFeedContainer;
//判断大于多少秒
private static int interval = 10;
private static long lastTime = 0;
private static boolean reload = false;
/**
* @param mContext
* @param mFeedContainer
* @param i_width
* @param tag
* @param page_type 1:代表一级页面;2:代表二级页面;3:代表三级页面
*/
private static int page_type = 1;
public static void setTag(String tag) {
map.put(tag, true);
}
public static void cancelTag(String tag) {
map.put(tag, false);
}
private static void addSkip(String tag) {
if (locationMap == null) {
locationMap = new HashMap<>();
}
if (!TextUtils.isEmpty(tag)) {
locationMap.put(tag, true);
}
}
/**
* 返回true:请求,false:不请求
*
* @param tag
* @return
*/
private static boolean isNoSkip(String tag) {
/*if (locationMap == null || TextUtils.isEmpty(tag) || locationMap.size() == 0) {
return true;
} else {
return !locationMap.containsKey(tag) || !locationMap.get(tag);
}*/
// if (new AdPreAndLevelUtils().getPage_Interval(page_type)) {
if (new AdPreAndLevelUtils().getPage_Interval(tag, page_type)) {
return true;
} else {
return false;
}
}
public static void preAD(Context mContext) {
preAD(mContext, 20);
}
public static void preAD(Context context, int i_width) {
if (new ADUtils("GMNativeAd", context).regexSwitch()) {
width = i_width;
mContext = context;
mIsLoadedAndShow = false;
setTag("tag");
loadAD();
}
}
private static void show_ad(Context context, FrameLayout feedContainer, String s_tag) {
if (new ADUtils("GMNativeAd", context).regexSwitch() && isNoSkip(s_tag)) {
mContext = context;
mFeedContainer = feedContainer;
mIsLoadedAndShow = true;
tag = s_tag;
setTag(s_tag);
loadAD();
}
}
public static void show_ad(Context mContext, String adUnitId, FrameLayout mFeedContainer, int i_width, String tag, int mPage_type) {
page_type = mPage_type;
mAdUnitId = adUnitId;
width = i_width;
show_ad(mContext, mFeedContainer, tag);
}
private static void loadAD() {
setTag(tag);
if (adNativeLoader == null) {
GMNativeADBean bean = CacheADManager.requestHaveAD("feed", mAdUnitId);
if (bean == null) {
LogK.e("bean == null");
load();
} else {
LogK.e("bean != null");
if (mIsLoadedAndShow) {
mTTFeedAd = bean.getmGMNativeAD();
show();
} else if (listenerAD != null) {
listenerAD.success(bean.getmGMNativeAD());
listenerAD = null;
}
}
} else {
}
}
private static boolean interval() {
if (System.currentTimeMillis() - lastTime > (100 * interval)) {
return true;
} else {
return false;
}
}
private static void load() {
LogK.e("mAdUnitId=" + mAdUnitId);
if (adNativeLoader == null && interval()) {
lastTime = System.currentTimeMillis();
adNativeLoader = TTAdSdk.getAdManager().createAdNative(mContext);
AdSlot adSlot = new AdSlot.Builder().setCodeId(mAdUnitId).setExpressViewAcceptedSize((int) (UIUtils.getScreenWidthDp(mContext) - width), 0).setAdCount(1)//请求广告数量为1到3条 优先采用平台配置的数量
.build();
adNativeLoader.loadFeedAd(adSlot, new TTAdNative.FeedAdListener() {
@Override
public void onError(int i, String s) {
LogK.e("onError code = " + i + " msg = " + s);
removeAD();
if (adNativeLoader != null) {
adNativeLoader = null;
}
}
@Override
public void onFeedAdLoad(List<TTFeedAd> ads) {
if (ads == null || ads.isEmpty()) {
removeAD();
if (adNativeLoader != null) {
adNativeLoader = null;
}
return;
}
mTTFeedAd = ads.get(0);
if (listenerAD != null && map.get(tag)) {
listenerAD.success(ads.get(0));
listenerAD = null;
}
CacheADManager.addAdLoaded("feed", mAdUnitId, ads.get(0));
LogK.e("map.get(tag)=" + map.get(tag));
if (mIsLoadedAndShow && map.get(tag)) {
if (mFeedContainer != null) {
// new AdPreAndLevelUtils().setThisTime(page_type);
AdPreAndLevelUtils.setTagTime(tag, System.currentTimeMillis());
show();
}
}
if (adNativeLoader != null) {
adNativeLoader = null;
}
}
});
}
}
private static void show() {
if (mTTFeedAd == null || mTTFeedAd.getMediationManager() == null) {
LogK.e("请先加载广告或等待广告加载完毕后再调用show方法");
// loadAD();
if (adNativeLoader != null) {
adNativeLoader = null;
}
return;
}
if (mTTFeedAd.getMediationManager().isExpress() && mFeedContainer != null && map.get(tag)) { //模板
mFeedContainer.setVisibility(View.VISIBLE);
showExpressView(mFeedContainer, mTTFeedAd);
} else {
if (adNativeLoader != null) {
adNativeLoader = null;
}
}
}
private static void showExpressView(FrameLayout mFeedContainer, TTFeedAd mTTFeedAd) {
mTTFeedAd.setExpressRenderListener(new MediationExpressRenderListener() {
@Override
public void onRenderFail(View view, String s, int i) {
LogK.e("onRenderFail");
}
@Override
public void onAdClick() {
LogK.e("onAdClick");
}
@Override
public void onAdShow() {
LogK.e("onAdShow");
if (listener != null) {
listener.success(true);
listener = null;
}
if (mFeedContainer != null) {
mFeedContainer.setVisibility(View.VISIBLE);
}
if (adNativeLoader != null) {
adNativeLoader = null;
}
if (new AdPreAndLevelUtils().getPre(page_type)) {
LogK.e("pre();");
pre();
}
}
@Override
public void onRenderSuccess(View view, float v, float v1, boolean b) {
LogK.e("onRenderSuccess");
mTTFeedAd.setDislikeCallback((Activity) mContext, new TTAdDislike.DislikeInteractionCallback() {
@Override
public void onShow() {
LogK.e("express dislike 点击show");
}
@Override
public void onSelected(int i, String s, boolean b) {
LogK.e("\"express 点击 " + s);
removeAdView();
if (mFeedContainer != null) {
mFeedContainer.setVisibility(View.GONE);
}
addSkip(tag);
}
@Override
public void onCancel() {
LogK.e("express dislike 点击了取消");
}
});
removeAdView();
View adView = mTTFeedAd.getAdView();
if (adView.getParent() != null) {
ViewGroup viewGroup = (ViewGroup) adView.getParent();
viewGroup.removeView(adView);
}
mFeedContainer.addView(adView);
if (listener != null) {
listener.success(true);
listener = null;
}
if (adNativeLoader != null) {
adNativeLoader = null;
}
}
});
removeAD();
mTTFeedAd.render();
LogK.e("render");
}
private static void pre() {
if (BaseConstants.PRE_AD) {
String currentFeedID = LoopAd.getCurrentFeedID();
if (currentFeedID != null) {
if (!CacheADManager.getContentID(currentFeedID)) {
if (false) {//如果轮播就是true
LoopAd.AdFeedIdAdd();
}
mAdUnitId = LoopAd.getCurrentFeedID();
preAD(mContext, 20);
}
}
}
}
private static void removeAD() {
if (mAdUnitId != null) {
CacheADManager.removeAD("feed", mAdUnitId);
}
if (listenerAD != null) {
listenerAD.success(mTTFeedAd);
listenerAD = null;
}
}
private static void removeAdView() {
LogK.e("removeAdView");
if (mFeedContainer != null) {
mFeedContainer.removeAllViews();
}
}
public interface Listener {
void success(boolean b);
}
public interface ListenerAD {
void success(TTFeedAd ad);
}
}

View File

@ -0,0 +1,132 @@
package com.tfq.ad.ad;
import android.text.TextUtils;
import com.tfq.library.utils.LogK;
import java.util.HashMap;
import java.util.Map;
public class AdPreAndLevelUtils {
/**
* page是几级页面
* pre是预加载
* interval是请求间隔
*/
public static boolean page1_pre = false;
public static boolean page2_pre = false;
public static boolean page3_pre = false;
public static int page1_interval = 5;
public static int page2_interval = 5;
public static int page3_interval = 5;
public static Map<String, Long> map = new HashMap<>();
//判断大于多少秒可以下一次开启
private static long lastTime_page1 = 0;
private static long lastTime_page2 = 0;
private static long lastTime_page3 = 0;
public static void setTagTime(String tag, Long time) {
map.put(tag, time);
}
public boolean getPage_Interval(int page) {
LogK.e("page1_interval=" + page1_interval);
LogK.e("page2_interval=" + page2_interval);
LogK.e("page3_interval=" + page3_interval);
if (page == 1) {
return get_interval_page1();
} else if (page == 2) {
return get_interval_page2();
} else if (page == 3) {
return get_interval_page3();
}
return true;
}
public boolean getPage_Interval(String tag, int page_level) {
/*LogK.e("page1_interval=" + page1_interval);
LogK.e("page2_interval=" + page2_interval);
LogK.e("page3_interval=" + page3_interval);
if (page == 1) {
return get_interval_page1();
} else if (page == 2) {
return get_interval_page2();
} else if (page == 3) {
return get_interval_page3();
}
return true;*/
if (!TextUtils.isEmpty(tag)) {
Long aLong = map.get(tag);
if (aLong != null) {
if (page_level == 1) {
if (System.currentTimeMillis() - aLong > (1000L * page1_interval)) {
return true;
}
return false;
} else if (page_level == 2) {
if (System.currentTimeMillis() - aLong > (1000L * page2_interval)) {
return true;
}
return false;
} else {
return true;
}
} else {
return true;
}
} else {
return true;
}
}
private boolean get_interval_page1() {
if (lastTime_page1 == 0) {
return true;
} else if (System.currentTimeMillis() - lastTime_page1 > (1000L * page1_interval)) {
return true;
} else {
return false;
}
}
private boolean get_interval_page2() {
if (lastTime_page2 == 0) {
return true;
} else if (System.currentTimeMillis() - lastTime_page2 > (1000L * page2_interval)) {
return true;
} else {
return false;
}
}
private boolean get_interval_page3() {
if (lastTime_page3 == 0) {
return true;
} else if (System.currentTimeMillis() - lastTime_page3 > (1000L * page3_interval)) {
return true;
} else {
return false;
}
}
public boolean getPre(int page) {
if (page == 1) {
return page1_pre;
} else if (page == 2) {
return page2_pre;
} else if (page == 3) {
return page3_pre;
}
return false;
}
public void setThisTime(int page_type) {
if (page_type == 1) {
lastTime_page1 = System.currentTimeMillis();
} else if (page_type == 2) {
lastTime_page2 = System.currentTimeMillis();
} else if (page_type == 3) {
lastTime_page3 = System.currentTimeMillis();
}
}
}

View File

@ -0,0 +1,251 @@
package com.tfq.ad.ad;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import com.bytedance.sdk.openadsdk.AdSlot;
import com.bytedance.sdk.openadsdk.TTAdConstant;
import com.bytedance.sdk.openadsdk.TTAdNative;
import com.bytedance.sdk.openadsdk.TTRewardVideoAd;
import com.bytedance.sdk.openadsdk.mediation.MediationConstant;
import com.bytedance.sdk.openadsdk.mediation.ad.MediationAdSlot;
import com.bytedance.sdk.openadsdk.mediation.manager.MediationAdEcpmInfo;
import com.bytedance.sdk.openadsdk.mediation.manager.MediationBaseManager;
import com.tfq.library.app.BaseConstants;
import com.tfq.library.utils.LogK;
import com.tfq.library.utils.ToasterUtil;
public class AdRewardUtils {
static long lastTime = 0;
private static Boolean requestAD = false;
//判断大于多少秒可以下一次开启
int interval = BaseConstants.ADV_Wait;
private Listener listener;
private String mAdUnitId = BaseConstants.CODE_AD_CQP;
private TTRewardVideoAd mTTRewardVideoAd; // 插全屏广告对象
private TTAdNative.RewardVideoAdListener mRewardVideoListener; // 广告加载监听器
private TTRewardVideoAd.RewardAdInteractionListener mRewardVideoAdInteractionListener; // 广告展示监听器
private LoadingDialog loadingDialog;
private boolean isRewardValid;//是否获取奖励
public AdRewardUtils() {
}
public AdRewardUtils(Context mContext, Listener listener) {
this.listener = listener;
init(mContext);
}
public AdRewardUtils(Context mContext, boolean load, Listener listener) {
this.listener = listener;
init(mContext, load);
}
public static void printShowInfo(MediationBaseManager adInfo) {
MediationBaseManager mediationManager = adInfo;
if (mediationManager != null) {
MediationAdEcpmInfo showEcpm = mediationManager.getShowEcpm();
if (showEcpm != null) {
logEcpmInfo(showEcpm);
}
}
}
public static void logEcpmInfo(MediationAdEcpmInfo item) {
LogK.e("EcpmInfo: \n" +
"SdkName: " + item.getSdkName() + ",\n" +
"CustomSdkName: " + item.getCustomSdkName() + ",\n" +
"SlotId: " + item.getSlotId() + ",\n" +
// 单位
"Ecpm: " + item.getEcpm() + ",\n" +
"ReqBiddingType: " + item.getReqBiddingType() + ",\n" +
"ErrorMsg: " + item.getErrorMsg() + ",\n" +
"RequestId: " + item.getRequestId() + ",\n" +
"RitType: " + item.getRitType() + ",\n" +
"AbTestId: " + item.getAbTestId() + ",\n" +
"ScenarioId: " + item.getScenarioId() + ",\n" +
"SegmentId: " + item.getSegmentId() + ",\n" +
"Channel: " + item.getChannel() + ",\n" +
"SubChannel: " + item.getSubChannel() + ",\n" +
"customData: " + item.getCustomData()
);
}
public void init(Context mContext) {
if (!requestAD) {
requestAD = true;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
requestAD = false;
loadingDialog.cancel();
}
}, 5000);
loadingDialog = new LoadingDialog(mContext);
loadingDialog.show();
init(mContext, true);
}
}
public void init(Context mContext, boolean load) {
boolean csj = true;
if (new ADUtils("GMRewardAd", mContext).regexSwitch() && csj) {
loadRewardVideoAd(mContext);
} else {
if (listener != null) {
listener.success(false);
listener = null;
}
}
}
private void loadRewardVideoAd(Context mContext) {
/** 1、创建AdSlot对象 */
AdSlot adslot = new AdSlot.Builder()
.setCodeId(BaseConstants.CODE_AD_REWARD)
.setOrientation(TTAdConstant.ORIENTATION_VERTICAL)
.setMediationAdSlot(new MediationAdSlot
.Builder()
.setExtraObject(MediationConstant.ADN_PANGLE, "pangleRewardCustomData")//服务端奖励验证透传参数
.setExtraObject(MediationConstant.ADN_GDT, "gdtRewardCustomData")
.setExtraObject(MediationConstant.ADN_BAIDU, "baiduRewardCustomData")
.build())
.build();
/** 2、创建TTAdNative对象 */
TTAdNative adNativeLoader = TTAdManagerHolder.get().createAdNative(mContext);
/** 3、创建加载、展示监听器 */
initListeners(mContext);
/** 4、加载广告 */
adNativeLoader.loadRewardVideoAd(adslot, mRewardVideoListener);
}
private void initListeners(Context mContext) {
// 广告加载监听器
this.mRewardVideoListener = new TTAdNative.RewardVideoAdListener() {
@Override
public void onError(int i, String s) {
LogK.e("reward load fail: errCode: " + i + ", errMsg: " + s);
}
@Override
public void onRewardVideoAdLoad(TTRewardVideoAd ttRewardVideoAd) {
LogK.e("reward load success");
loadingDialog.cancel();
mTTRewardVideoAd = ttRewardVideoAd;
showRewardVideoAd(mContext);
}
@Override
public void onRewardVideoCached() {
LogK.e("reward cached success");
}
@Override
public void onRewardVideoCached(TTRewardVideoAd ttRewardVideoAd) {
LogK.e("reward cached success 2");
mTTRewardVideoAd = ttRewardVideoAd;
showRewardVideoAd(mContext);
}
};
// 广告展示监听器
this.mRewardVideoAdInteractionListener = new TTRewardVideoAd.RewardAdInteractionListener() {
@Override
public void onAdShow() {
LogK.e("reward show");
}
@Override
public void onAdVideoBarClick() {
LogK.e("reward click");
}
@Override
public void onAdClose() {
LogK.e("reward close");
}
@Override
public void onVideoComplete() {
LogK.e("reward onVideoComplete");
success();
}
@Override
public void onVideoError() {
LogK.e("reward onVideoError");
}
@Override
public void onRewardVerify(boolean b, int i, String s, int i1, String s1) {
LogK.e("reward onRewardVerify");
}
@Override
public void onRewardArrived(boolean isReward_Valid, int rewardType, Bundle extraInfo) {//奖励是否发放请依据isRewardValid
// 当用户的观看行为满足了奖励条件
if (isReward_Valid) {
isRewardValid = true;
success();
}
}
@Override
public void onSkippedVideo() {
LogK.e("reward onSkippedVideo");
if (!isRewardValid) {
ToasterUtil.show("看完视频才可以获得奖励",3);
}
}
};
}
// 广告加载成功后开始展示广告
private void showRewardVideoAd(Context mContext) {
if (mTTRewardVideoAd == null) {
LogK.e("请先加载广告或等待广告加载完毕后再调用show方法");
return;
}
/** 5、设置展示监听器展示广告 */
mTTRewardVideoAd.setRewardAdInteractionListener(mRewardVideoAdInteractionListener);
mTTRewardVideoAd.showRewardVideoAd((Activity) mContext);
}
public interface Listener {
void success(boolean b);
}
private void success() {
if (listener != null) {
if (isRewardValid) {
listener.success(true);
} else {
listener.success(false);
}
listener = null;
}
}
}

View File

@ -0,0 +1,150 @@
package com.tfq.ad.ad;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.FrameLayout;
import com.bytedance.sdk.openadsdk.AdSlot;
import com.bytedance.sdk.openadsdk.CSJAdError;
import com.bytedance.sdk.openadsdk.CSJSplashAd;
import com.bytedance.sdk.openadsdk.CSJSplashCloseType;
import com.bytedance.sdk.openadsdk.TTAdNative;
import com.tfq.library.app.BaseConstants;
import com.tfq.library.utils.LogK;
public class AdSplashUtils {
private Context mContext;
private FrameLayout mSplashContainer;
private CSJSplashAd mCsjSplashAd;
private Listener listener;
public interface Listener {
void success(long time);
}
public AdSplashUtils(Context context, FrameLayout mSplashContainer, Listener listener) {
this.mContext = context;
this.mSplashContainer = mSplashContainer;
this.listener = listener;
loadAndShowSplashAd();
}
private TTAdNative.CSJSplashAdListener mCSJSplashAdListener;
private CSJSplashAd.SplashAdListener mCSJSplashInteractionListener;
public void loadAndShowSplashAd() {
if (new ADUtils("GMSplashAd", mContext).regexSwitch()) {
LogK.e("init kaiping");
init();
} else if (listener != null) {
listener.success(0);
}
}
private void init() {
new Handler(Looper.myLooper()).postDelayed(new Runnable() {
@Override
public void run() {
finishAndBack(0);
}
}, 9000);
AdSlot adSlot = new AdSlot.Builder()
.setCodeId(BaseConstants.CODE_AD_SPLASH)
.setImageAcceptedSize(UIUtils.getScreenWidthInPx(mContext), UIUtils.getAllScreenHeight(mContext))
.build();
TTAdNative adNativeLoader = TTAdManagerHolder.get().createAdNative(mContext);
initListeners();
adNativeLoader.loadSplashAd(adSlot, mCSJSplashAdListener, 3500);
}
private void initListeners() {
// 广告加载监听器
mCSJSplashAdListener = new TTAdNative.CSJSplashAdListener() {
@Override
public void onSplashRenderSuccess(CSJSplashAd csjSplashAd) {
/** 5、渲染成功后展示广告 */
LogK.e("splash render success");
mCsjSplashAd = csjSplashAd;
csjSplashAd.setSplashAdListener(mCSJSplashInteractionListener);
View splashView = csjSplashAd.getSplashView();
UIUtils.removeFromParent(splashView);
mSplashContainer.removeAllViews();
mSplashContainer.addView(splashView);
}
public void onSplashLoadSuccess() {
LogK.e("splash load success");
}
@Override
public void onSplashLoadSuccess(CSJSplashAd csjSplashAd) {
}
@Override
public void onSplashLoadFail(CSJAdError csjAdError) {
LogK.e("splash load fail, errCode: " + csjAdError.getCode() + ", errMsg: " + csjAdError.getMsg());
finishAndBack(0);
}
@Override
public void onSplashRenderFail(CSJSplashAd csjSplashAd, CSJAdError csjAdError) {
LogK.e("splash render fail, errCode: " + csjAdError.getCode() + ", errMsg: " + csjAdError.getMsg());
finishAndBack(0);
}
};
// 广告展示监听器
this.mCSJSplashInteractionListener = new CSJSplashAd.SplashAdListener() {
@Override
public void onSplashAdShow(CSJSplashAd csjSplashAd) {
LogK.d("splash show");
}
@Override
public void onSplashAdClick(CSJSplashAd csjSplashAd) {
LogK.d("splash click");
}
@Override
public void onSplashAdClose(CSJSplashAd csjSplashAd, int closeType) {
if (closeType == CSJSplashCloseType.CLICK_SKIP) {
LogK.d("开屏广告点击跳过");
finishAndBack(0);
} else if (closeType == CSJSplashCloseType.COUNT_DOWN_OVER) {
LogK.d("开屏广告点击倒计时结束");
finishAndBack(0);
} else if (closeType == CSJSplashCloseType.CLICK_JUMP) {
LogK.d("点击跳转");
}
}
};
}
private void finishAndBack(int time) {
if (listener != null) {
listener.success(time);
listener = null;
}
}
public void onDestroy() {
if (mCsjSplashAd != null && mCsjSplashAd.getMediationManager() != null) {
mCsjSplashAd.getMediationManager().destroy();
}
}
}

View File

@ -0,0 +1,106 @@
package com.tfq.ad.ad;
import com.bytedance.sdk.openadsdk.TTFeedAd;
import com.tfq.library.utils.LogK;
import java.util.ArrayList;
import java.util.List;
public class CacheADManager {
private static List<GMNativeADBean> mGMNativeADBean;
public static void init() {
mGMNativeADBean = new ArrayList<>();
}
private static int contentID = -1;
public static List<GMNativeADBean> getAdBean() {
return mGMNativeADBean;
}
public static GMNativeADBean requestHaveAD(String adType, String mAdUnitId) {
GMNativeADBean bean = null;
switch (adType) {
case "feed":
if (getAdBean() != null && getAdBean().size() > 0) {
boolean b = getContentID(mAdUnitId);
if (b) {
try {
bean = getAdBean().get(contentID);
} catch (Exception e) {
e.printStackTrace();
}
} else {
if (mGMNativeADBean != null && mGMNativeADBean.size() > 0) {
GMNativeADBean gmNativeADBean = mGMNativeADBean.get(0);
if (gmNativeADBean != null && gmNativeADBean.getmGMNativeAD() != null && gmNativeADBean.getmGMNativeAD().getMediationManager().isExpress()) {
bean = gmNativeADBean;
} else if (gmNativeADBean != null) {
mGMNativeADBean.remove(gmNativeADBean);
}
}
}
}
break;
}
return bean;
}
private static void addAd(String mAdUnitId, long l_time, TTFeedAd o) {
GMNativeADBean bean = new GMNativeADBean();
bean.setGMNativeADID(mAdUnitId);
bean.setmGMNativeAD(o);
bean.setSaveTime(l_time);
mGMNativeADBean.add(bean);
}
public static void removeAD(String adType, String mAdUnitId) {
switch (adType) {
case "feed":
while (getContentID(mAdUnitId)) {
mGMNativeADBean.remove(contentID);
LogK.e("移除该广告");
}
LogK.e("移除广告完成! ");
break;
}
}
/**
* 有了回调
*/
public static void addAdLoaded(String adType, String mAdUnitId, TTFeedAd mGMNativeAd) {
switch (adType) {
case "feed":
contentID = -1;
boolean b = getContentID(mAdUnitId);
if (b) {
GMNativeADBean bean = new GMNativeADBean();
bean.setmGMNativeAD(mGMNativeAd);
bean.setSaveTime(System.currentTimeMillis());
bean.setGMNativeADID(mAdUnitId);
mGMNativeADBean.set(contentID, bean);
} else {
addAd(mAdUnitId, System.currentTimeMillis(), mGMNativeAd);
}
break;
}
}
public static boolean getContentID(String mAdUnitId) {
boolean b = false;
if (mGMNativeADBean != null && mGMNativeADBean.size() > 0) {
for (int i = 0; i < mGMNativeADBean.size(); i++) {
if (mAdUnitId.equals(mGMNativeADBean.get(i).getGMNativeADID())) {
contentID = i;
b = true;
}
}
return b;
} else {
return false;
}
}
}

View File

@ -0,0 +1,60 @@
package com.tfq.ad.ad;
import com.bytedance.sdk.openadsdk.TTFeedAd;
public class GMNativeADBean {
private String GMNativeADID;
private TTFeedAd mGMNativeAD;
private boolean mGMNativeADShow;
private boolean adUsed;
private long saveTime;
private boolean isList;
public String getGMNativeADID() {
return GMNativeADID;
}
public void setGMNativeADID(String GMNativeADID) {
this.GMNativeADID = GMNativeADID;
}
public TTFeedAd getmGMNativeAD() {
return mGMNativeAD;
}
public void setmGMNativeAD(TTFeedAd mGMNativeAD) {
this.mGMNativeAD = mGMNativeAD;
}
public boolean ismGMNativeADShow() {
return mGMNativeADShow;
}
public void setmGMNativeADShow(boolean mGMNativeADShow) {
this.mGMNativeADShow = mGMNativeADShow;
}
public boolean isAdUsed() {
return adUsed;
}
public void setAdUsed(boolean adUsed) {
this.adUsed = adUsed;
}
public long getSaveTime() {
return saveTime;
}
public void setSaveTime(long saveTime) {
this.saveTime = saveTime;
}
public boolean isList() {
return isList;
}
public void setList(boolean list) {
isList = list;
}
}

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