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: 从上往下的弹出提示view * 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.library_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(); } }