资讯详情

Toast的高级自定义方式-循序渐进带你了解toast

写在前面 对于Toast相信只要用过,android童鞋并不陌生,它是一个不需要与用户互动的提示框。接下来,让我们一步一步地定制它Toast,全方位玩Toast,实现其不同的显示需求。从那时起,我们不再害怕提示的各种异常需求。~ 先看效果图,华为手机,4.4版本,没root,只能连上电脑,再通过录制电脑屏幕上的手机画面录屏,求推荐好方法录屏。~

1.最基本的Toast Toast.makeText(getApplicationContext(),"最基本的Toast",Toast.LENGTH_SHORT).show(); 1 不用多说。

2.定制位置Toast 通过Toast设置类自带定义位置的方法toast位置。

Toast toast=Toast.makeText(getApplicationContext(),"定制位置Toast",Toast.LENGTH_SHORT); /** *Toast.setGravity(gravity,xOffset,yOffset); *@gravity:toast的位置 *@xOffset:相对于gravity x方向偏移。yOffset:相对于gravity y方向偏移。 */ toast.setGravity(Gravity.LEFT,50,0); toast.show(); 3.带图片的toast 我讲了前两个最基本的。Toast,现在先来看看toast.markText看看源码toast它是如何显示的。 源码位置:frameworks/base/core/java/Android/widght/Toast.java (Toast#makeText()) 要增加的view布局如下:frameworks/base/core/res/res/layout/transient_notification.xml。里面只有一个TextView没什么好说的。

public static Toast makeText(Context context, CharSequence text, int duration) { Toast result = new Toast(context); LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null); TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message); tv.setText(text); result.mNextView = v; result.mDuration = duration; return result; } 从上面的源码中可以得到什么:1.new一个Toast类,获得当前的context;2.LayoutInflater,动态载入layout的类,将view布局载入。3.获得view中的textview中文信息。4.设置toast的view和duration属性。5.返回toast.从而实现了toast的markText方法。 ok!,搞懂了toast.markText我们可以在这部分设置自定义源代码view的toast. 1.创建一个custom_toast.xml,一个LinearLayout,水平方向,ImageView TextView。设置它们的各种属性。(代码很简单,所以不。 2.自定义Toast.直接上代码

Toast customToast = new Toast(MainActivity.this.getApplicationContext()); //获得view的布局 View customView = LayoutInflater.from(MainActivity.this).inflate(R.layout.custom_toast,null); ImageView img = (ImageView) customView.findViewById(R.id.iv); TextView tv = (TextView) customView.findViewById(R.id.tv); //设置ImageView的图片 img.setBackgroundResource(R.drawable.ab); //设置textView中的文字 tv.setText("我是带图片的自定义位置toast"); //设置toast的View,Duration,Gravity最后显示 customToast.setView(customView); customToast.setDuration(Toast.LENGTH_SHORT); customToast.setGravity(Gravity.CENTER,0,0); customToast.show(); 4.自定义View超高级带动画Toast. 其实这是3。toast加强版。用我们定制的图片代替里面的图片。view,通过自定义view,实现多种多样Toast. 1.创建自定义view.CustomToastView继承View. 整体的Custom结构(具体实现代码如下):

public class CustomToastView extends View { //a.一些初始化的变量。 ... //a.实现CustomToastView三个结构函数 ... //b.初始化画笔的参数和矩形参数 ...

} a.部分变量初始化,实现三个结构函数。

public class CustomToastView extends View { //矩形,设置toast布局时用 RectF rectF =new RectF(); ///属性动画 ValueAnimator valueAnimator; float mAnimatedValue = 0f; //自定义view的画笔 private Paint mPaint;

private float mWidth = 0f; //view的宽 private float mEyeWidth = 0f; ///笑脸的眼睛半径 private float mPadding = 0f; //view的偏移量。 private float endAngle = 0f; ///圆弧结束数

//左眼或右眼 private boolean isSmileLeft = false; private boolean isSmileRight = false;

public CustomToastViw(Context context) {         super(context);     }     public CustomToastView(Context context, AttributeSet attrs) {         super(context, attrs);     }     public CustomToastView(Context context, AttributeSet attrs, int defStyleAttr) {         super(context, attrs, defStyleAttr);     }     ....... } b.设置画笔的参数以及矩形的参数。

 private void initPaint() {         mPaint = new Paint();         mPaint.setAntiAlias(true);         mPaint.setStyle(Paint.Style.STROKE);         mPaint.setColor(Color.parseColor("#5cb85c"));         mPaint.setStrokeWidth(dip2px(2));     }     private void initRect() {         rectF = new RectF(mPadding, mPadding, mWidth - mPadding, mWidth - mPadding);     }     //dip转px。为了支持多分辨率手机  public int dip2px(float dpValue) {         final float scale = getContext().getResources().getDisplayMetrics().density;         return (int) (dpValue * scale + 0.5f);     } c.重写onMeasure

  @Override     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {         super.onMeasure(widthMeasureSpec, heightMeasureSpec);         initPaint();         initRect();         mWidth = getMeasuredWidth(); //当前view在父布局里的宽度。即view所占宽度。         mPadding = dip2px(10);         mEyeWidth = dip2px(3);     } d.重写OnDraw

  @Override     protected void onDraw(Canvas canvas) {         super.onDraw(canvas);         mPaint.setStyle(Paint.Style.STROKE);         //画微笑弧(从左向右画弧)         canvas.drawArc(rectF, 180, endAngle, false, mPaint);         //设置画笔为实心         mPaint.setStyle(Paint.Style.FILL);         //左眼         if (isSmileLeft) {             canvas.drawCircle(mPadding + mEyeWidth + mEyeWidth / 2, mWidth / 3, mEyeWidth, mPaint);         }         //右眼         if (isSmileRight) {             canvas.drawCircle(mWidth - mPadding - mEyeWidth - mEyeWidth / 2, mWidth / 3, mEyeWidth, mPaint);         }     } e.自定义View中的动画效果实现

  /**      * startAnim()不带参数的方法      */     public void startAnim() {         stopAnim();         startViewAnim(0f, 1f, 2000);     }

    /**      * 停止动画的方法      *      */     public void stopAnim() {         if (valueAnimator != null) {             clearAnimation();             isSmileLeft = false;             isSmileRight = false;             mAnimatedValue = 0f;             valueAnimator.end();         }     }     /**      * 开始动画的方法      * @param startF 起始值      * @param endF   结束值      * @param time  动画的时间      * @return      */     private ValueAnimator startViewAnim(float startF, final float endF, long time) {         //设置valueAnimator 的起始值和结束值。         valueAnimator = ValueAnimator.ofFloat(startF, endF);         //设置动画时间         valueAnimator.setDuration(time);         //设置补间器。控制动画的变化速率         valueAnimator.setInterpolator(new LinearInterpolator());         //设置监听器。监听动画值的变化,做出相应方式。         valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {             @Override             public void onAnimationUpdate(ValueAnimator valueAnimator) {

                mAnimatedValue = (float) valueAnimator.getAnimatedValue();                 //如果value的值小于0.5                 if (mAnimatedValue < 0.5) {                     isSmileLeft = false;                     isSmileRight = false;                     endAngle = -360 * (mAnimatedValue);                     //如果value的值在0.55和0.7之间                 } else if (mAnimatedValue > 0.55 && mAnimatedValue < 0.7) {                     endAngle = -180;                     isSmileLeft = true;                     isSmileRight = false;                     //其他                 } else {                     endAngle = -180;                     isSmileLeft = true;                     isSmileRight = true;                 }                 //重绘                 postInvalidate();             }         });         if (!valueAnimator.isRunning()) {             valueAnimator.start();         }         return valueAnimator;     } 好了,就这么多,自定义view大功告成。

2.toast要用的view的xml。没啥多说的直接上代码。有三个xml. 一个是backgroud_toast.xml(设置view的样式。)

<shape xmlns:android="http://schemas.android.com/apk/res/android"     android:shape="rectangle">     <solid android:color="#FFFFFF"></solid>     <stroke android:color="#C4CDE0"></stroke>     <corners android:radius="10dp"></corners>

</shape> 一个text_toast.xml(设置textView的样式)

<shape xmlns:android="http://schemas.android.com/apk/res/android"     android:shape="rectangle">     <solid android:color="#5cb85c"></solid>     <stroke android:color="#C4CDE0"></stroke>     <corners         android:bottomRightRadius="10dp"         android:topRightRadius="10dp"></corners>

</shape> 一个是smile_toast.xml(显示的toast的view布局方式)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:id="@+id/root_layout"     android:layout_width="match_parent"     android:layout_height="wrap_content"     android:background="#00000000"     android:orientation="vertical">     <LinearLayout         android:id="@+id/base_layout"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_marginBottom="25dp"         android:layout_marginLeft="30dp"         android:layout_marginRight="30dp"         android:layout_marginTop="25dp"         android:background="@drawable/backgroud_toast"         android:orientation="horizontal">         <LinearLayout             android:id="@+id/linearLayout"             android:layout_width="match_parent"             android:layout_height="match_parent"             android:gravity="center">             <com.example.yyh.toasttest.CustomToastView                 android:id="@+id/successView"                 android:layout_width="50dp"                 android:layout_height="50dp"                 android:layout_gravity="center_vertical|left"                 android:layout_margin="10px"                 android:gravity="center_vertical|left" />         </LinearLayout>         <TextView             android:id="@+id/toastMessage"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:gravity="center_vertical"             android:padding="10dp"             android:text="New Text" />     </LinearLayout> </LinearLayout> 3.接下来就是在代码中将自定义的toast,加入进去。大功告成。

//在MainActivity中声明CustomToastView static CustomToastView customToastView;

  Toast smileToast=new Toast(MainActivity.this.getApplicationContext());                //view布局                 View smileView =LayoutInflater.from(MainActivity.this.getApplicationContext()).inflate(R.layout.smile_toast,null,false);                 TextView text = (TextView) smileView.findViewById(R.id.toastMessage);                 text.setText("我是带动画的toast");                 //给customToastView增加动画效果                 customToastView=(CustomToastView)smileView.findViewById(R.id.smileView);                 customToastView.startAnim();                 //设置text的背景样式                 text.setBackgroundResource(R.drawable.text_toast);                 text.setTextColor(Color.parseColor("#FFFFFF"));                 smileToast.setView(smileView);                 smileToast.setDuration(Toast.LENGTH_SHORT);                 smileToast.show(); 是不是脑光一亮~,笑脸的toast只是个启发,有了这个思路我们就可以设置不同的效果显示方式。

5.带出入效果的Toast 大家如果用的小米手机,就会发现,小米手机弹出的toast,有一个从底部上移弹出的效果。这个效果也是比较特别的。我们就来试试也实现下这个效果。 我们将4.自定义View带动画超高级的Toast.进行进一步的扩展,利用悬浮窗的原理,完成从底部弹出toast的效果。(其实查看源码 Toast实质上就是用到了悬浮窗的知识WindowManager.addView;和 mWM.removeView(mView);)来实现Toast的显示和消失的。当然,这里我们不再剖析源码,大家知道就行了 对悬浮窗的知识不是很了解的童鞋,可以去看我的上一篇文章: 仿360加速球。(实现内存释放) 首先,新建一个MiUiToast类。 1.一些需要的变量。这里用到了上面的自定义的view.

    //窗口管理类,用来管理Toast的显示和隐藏。     private WindowManager mWdm;     //自定义的view.     private CustomToastView mToastView;     //toast的参数     private WindowManager.LayoutParams mParams;     //是否显示toast.     private int showTime;     private boolean mIsShow;//记录当前Toast的内容是否已经在显示     //要显示的view.     private final View smileView;  2.相关函数的设置。

    //显示时间的设置相关     public int getShowTime() {         return showTime;     }     public void setShowTime(int showTime) {         this.showTime = showTime;     }     public static MiUiToast MakeText(Context context, String text, int showTime) {         MiUiToast result = new MiUiToast(context, text, showTime);         return result;     }     private MiUiToast(Context context, String text, int time){         setShowTime(time);         mIsShow = false;//记录当前Toast的内容是否已经在显示         mWdm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);         smileView = LayoutInflater.from(context.getApplicationContext()).inflate(R.layout.smile_toast, null, false);         TextView text1 = (TextView) smileView.findViewById(R.id.toastMessage);         text1.setText("我是带动画的toast");         mToastView=(CustomToastView) smileView.findViewById(R.id.smileView);         mToastView.startAnim();         text1.setBackgroundResource(R.drawable.text_toast);         text1.setTextColor(Color.parseColor("#FFFFFF"));         //设置布局参数         setParams();     }     //toast.布局参数的设置。     private void setParams() {         mParams = new WindowManager.LayoutParams();         mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;         mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;         mParams.format = PixelFormat.TRANSLUCENT;         mParams.windowAnimations = R.style.anim_view;//设置进入退出动画效果         mParams.type = WindowManager.LayoutParams.TYPE_TOAST;         mParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON                 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE                 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;         mParams.gravity = Gravity.CENTER_HORIZONTAL;         mParams.y = 250;     }

    //显示Toast.     public void show(){         if(!mIsShow){//如果Toast没有显示,则开始加载显示             mIsShow = true;             mWdm.addView(smileView, mParams);//将其加载到windowManager上         }     }

    //取消toast.     public void cancel(){         mWdm.removeView(smileView);         mIsShow = false;     } 3.在ManiActivity中设置MiUiToast,显示。大功告成。

 private Handler handler=new Handler(){         @Override         public void handleMessage(Message msg) {             super.handleMessage(msg);             if (msg.what==007){                 miUitoast.cancel();             }         }     };  private MiUiToast miUitoast;   if(miUitoast == null){                     miUitoast = MiUiToast.MakeText(this, "仿小米Toast", 2000);                 }               miUitoast.show();               handler.sendEmptyMessageDelayed(007,miUitoast.getShowTime()); 6.关于Toast几个不为人知的秘密(敲黑板,认真脸,加分项啊加分项。) 1.toast的显示时间只有两种可能。我们查看源码可以得知它只有2秒和3.5秒。(long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;)

private void scheduleTimeoutLocked(ToastRecord r)  {     mHandler.removeCallbacksAndMessages(r);     Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);     long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;     mHandler.sendMessageDelayed(m, delay);   } private static final int LONG_DELAY = 3500; // 3.5 seconds   private static final int SHORT_DELAY = 2000; // 2 seconds   那如果我们要控制toast的显示时间随意该怎么办呢,认真看过的上面的文章的童鞋,相信已经有了思路。没错,自定义view的toast,利用WindowManager+Handler,确定一定时间来remove这个自定义的Toast.就行了。参考5.带出入效果的Toast 当然还有另一种思路,利用反射拿到show方法,我试了好久,都是有错误,最后寻找原因但是好像在andorid4.0往上,这种方法就用了不了。这里就不讲了。。。 还有一种思路。利用Timer+Handler也可以来控制Toast的显示时间问题。那么开始吧~ 新建一个TimeToast类,定义两个Timer,一个是显示Toast,一个是取消Toast.代码不难直接上~

 /**  * Created by yyh on 2016/10/27.  */ public class TimeToast {     //定义的显示时间     private double time;     private static Handler handler;     //显示的计时器     private Timer showTimer;     //取消的计时器     private Timer cancelTimer;

    private Toast toast;

    private TimeToast(){         showTimer = new Timer();         cancelTimer = new Timer();     }     public void setTime(double time) {         this.time = time;     }     public void setToast(Toast toast){         this.toast = toast;     }

    public static TimeToast makeText(Context context, String text, double time){         TimeToast toast1= new TimeToast();         toast1.setTime(time);         toast1.setToast(Toast.makeText(context, text, Toast.LENGTH_SHORT));         handler = new Handler(context.getMainLooper());         return toast1;     }     public void show(){         toast.show();         if(time > 2){             showTimer.schedule(new TimerTask() {                 @Override                 public void run() {                     handler.post(new ShowRunnable());                 }             }, 0, 1900);         }         cancelTimer.schedule(new TimerTask() {             @Override             public void run() {                 handler.post(new CancelRunnable());             }         }, (long)(time * 1000));     }     private class CancelRunnable implements Runnable{         @Override         public void run() {             showTimer.cancel();             toast.cancel();         }     }     private class ShowRunnable implements Runnable{         @Override         public void run() {             toast.show();         }     } } 之后在ManiActivity中调用这个类就行了

  TimeToast timeToast=TimeToast.makeText(getApplicationContext(),"显示时间自定的Toast",6);                 timeToast.show(); 1 2 2.Toast显示的问题,当我们连续点击Toast的时候,居然一直在显示,点击30多下,结果这条Toast显示了将近2分钟。这样用户的体验很不好。(原因是因为Toast的管理是在队列中,点击一次,就会产生一个新的Toast,所以要等这个队列中的Toast处理完,这个显示Toast的任务才算结束。) so~ 思路来了,我们可以把Toast改成单例模式,没有Toast再新建它,这样也就解决了连续点击Toast,一直在显示的问题。~ 先上新建的单例模式的SingleToast类:

public class SingleToast {     private static Toast mToast;     /**双重定,使用同一个Toast实例*/     public static Toast getInstance(Context context){         if (mToast == null){             synchronized (SingleToast.class){                 if (mToast == null){                     mToast = new Toast(context);                 }             }         }         return mToast;     } } 1 接着在ManiActivity中进行应用,就是这么随意~ 大功告成~

 Toast singleToast=SingleToast.getInstance(getApplicationContext());                 View singleCustomView = LayoutInflater.from(MainActivity.this).inflate(R.layout.custom_toast,null);                 ImageView img1 = (ImageView) singleCustomView.findViewById(R.id.iv);                 TextView tv1 = (TextView) singleCustomView.findViewById(R.id.tv);                 img1.setBackgroundResource(R.drawable.ic_launcher);                 tv1.setText("这是第"+num+++"遍 点击我了~~");                 singleToast.setView(singleCustomView);                 singleToast.setDuration(Toast.LENGTH_SHORT);                 singleToast.show();

标签: sub微型d连接器mwdm2l

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台