Android 原生自定义toast的简单实现
一,需求分析
1,装toast组件容器需要为一个从上往下进行布局的内容
2,toast组件添加后需要播放消失动画
消失动画的表现方式
1,布局往上推,然后缓慢变透明直至消失
2,消失过程中,后加入的toast位置随着逐渐消失的toast的位置改变而跟着改变
二,代码实现
1,布局,就一个按钮
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <? xml version="1.0" encoding="utf-8"?> < androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> < TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> < Button android:id="@+id/test_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="测试" tools:ignore="MissingConstraints" /> </ androidx.constraintlayout.widget.ConstraintLayout > |
2,MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package com.ahao.toastdemo; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn = findViewById(R.id.test_btn); btn.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { new Handler(Looper.getMainLooper()).post( new Runnable() { @Override public void run() { ToastUtils.showToast(MainActivity. this , "你好啊你好啊" , 1200 ); } }); } }); } } |
3,ToastUtils.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | package com.ahao.toastdemo; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Color; import android.graphics.PixelFormat; import android.view.Gravity; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.LinearLayout; import android.widget.TextView; import java.lang.ref.WeakReference; public class ToastUtils { private static WeakReference<LinearLayout> toastLayoutRef; @SuppressLint ({ "RtlHardcoded" , "UseCompatLoadingForDrawables" }) public static void showToast(Context context, String content, int duration) { if (toastLayoutRef == null ) { WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); LinearLayout linearLayout = new LinearLayout(context); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); linearLayout.setLayoutParams(lp); linearLayout.setOrientation(LinearLayout.VERTICAL); WindowManager.LayoutParams winLp = new WindowManager.LayoutParams(); winLp.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL; winLp.type = WindowManager.LayoutParams.TYPE_APPLICATION; winLp.width = WindowManager.LayoutParams.MATCH_PARENT; winLp.height = WindowManager.LayoutParams.MATCH_PARENT; winLp.flags = WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; winLp.format = PixelFormat.RGBA_8888; windowManager.addView(linearLayout, winLp); toastLayoutRef = new WeakReference<>(linearLayout); showToast(context, content, duration); return ; } LinearLayout toastItem = new LinearLayout(context); toastItem.setHorizontalGravity(Gravity.CENTER_HORIZONTAL); LinearLayout.LayoutParams toastLp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 56 ); toastLp.setMargins( 0 , 0 , 0 , 16 ); toastItem.setLayoutParams(toastLp); TextView toastContent = new TextView(context); toastContent.setText(content); toastContent.setPadding( 10 , 10 , 10 , 10 ); toastContent.setMinWidth( 200 ); toastContent.setHeight( 56 ); toastContent.setGravity(Gravity.CENTER); toastContent.setBackground(context.getResources().getDrawable(R.drawable.toast_bg)); toastContent.setTextColor(Color.parseColor( "#FFFFFF" )); toastItem.addView(toastContent); toastItem.animate() .setStartDelay(duration) .setDuration( 1200 ) .alpha( 0 ) .translationY( 0 ) .setUpdateListener( new ValueAnimator.AnimatorUpdateListener() { private float oldHeight = 0 ; @Override public void onAnimationUpdate(ValueAnimator animation) { float currentProgress = Float.parseFloat(animation.getAnimatedValue().toString()); if (oldHeight == 0 ){ oldHeight = toastItem.getMeasuredHeight(); } LinearLayout.LayoutParams toastLP = (LinearLayout.LayoutParams) toastItem.getLayoutParams(); int newMarginBottom = ( int ) (- 1 * currentProgress * oldHeight); toastLP.setMargins( 0 , 0 , 0 ,newMarginBottom); toastItem.post( new Runnable() { @Override public void run() { toastItem.setLayoutParams(toastLP); } }); } }) .setListener( new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super .onAnimationEnd(animation); toastLayoutRef.get().removeView(toastItem); } }) .start(); toastLayoutRef.get() .addView(toastItem); } } |
4,toast_bg.xml
1 2 3 4 5 6 | <? xml version="1.0" encoding="utf-8"?> < shape xmlns:android="http://schemas.android.com/apk/res/android"> < solid android:color="#000000"/> < corners android:radius="1000dp"/> < stroke android:color="#1d39c4" /> </ shape > |
三,演示
四,项目代码
https://gitee.com/UPUP0326/android-toast-demo
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库