425 lines
17 KiB
Java
425 lines
17 KiB
Java
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();
|
||
}
|
||
}
|