Android Toast可以比Toast. length_long长吗?

当为Toast使用setDuration()时,是否可以设置自定义长度或至少比Toast.LENGTH_LONG长?

218883 次浏览

LENGTH_SHORTLENGTH_LONG的值分别为0和1。这意味着它们被视为标志,而不是实际的持续时间,所以我认为不可能将持续时间设置为这些值以外的任何东西。

如果你想更长时间地向用户显示一条消息,可以考虑状态栏通知。当状态栏通知不再相关时,可以通过编程方式取消它们。

如果你想要Toast持久,我发现你可以通过反复调用Timer来解决它(每秒钟左右应该这样做)。如果Toast已经显示,调用show()不会破坏任何东西,但它会刷新它在屏幕上停留的时间。

如果你深入挖掘android代码,你会发现这些行清楚地表明,我们不能改变Toast消息的持续时间。

 NotificationManagerService.scheduleTimeoutLocked() {
...
long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY);
}

持续时间的默认值为

private static final int LONG_DELAY = 3500; // 3.5 seconds
private static final int SHORT_DELAY = 2000; // 2 seconds

你可能想试试:

for (int i=0; i < 2; i++)
{
Toast.makeText(this, "blah", Toast.LENGTH_LONG).show();
}

使时间加倍。如果你指定3而不是2,它会使时间增加三倍等等。

下面是我用上面的代码创建的一个自定义Toast类:

import android.content.Context;
import android.os.CountDownTimer;
import android.widget.Toast;


public class CustomToast extends Toast {
int mDuration;
boolean mShowing = false;
public CustomToast(Context context) {
super(context);
mDuration = 2;
}




/**
* Set the time to show the toast for (in seconds)
* @param seconds Seconds to display the toast
*/
@Override
public void setDuration(int seconds) {
super.setDuration(LENGTH_SHORT);
if(seconds < 2) seconds = 2; //Minimum
mDuration = seconds;
}


/**
* Show the toast for the given time
*/
@Override
public void show() {
super.show();


if(mShowing) return;


mShowing = true;
final Toast thisToast = this;
new CountDownTimer((mDuration-2)*1000, 1000)
{
public void onTick(long millisUntilFinished) {thisToast.show();}
public void onFinish() {thisToast.show(); mShowing = false;}


}.start();
}
}

创建略长的消息的一个非常简单的方法如下:

private Toast myToast;


public MyView(Context context) {
myToast = Toast.makeText(getContext(), "", Toast.LENGTH_LONG);
}


private Runnable extendStatusMessageLengthRunnable = new Runnable() {
@Override
public void run() {
//Show the toast for another interval.
myToast.show();
}
};


public void displayMyToast(final String statusMessage, boolean extraLongDuration) {
removeCallbacks(extendStatusMessageLengthRunnable);


myToast.setText(statusMessage);
myToast.show();


if(extraLongDuration) {
postDelayed(extendStatusMessageLengthRunnable, 3000L);
}
}

注意,上面的示例消除了LENGTH_SHORT选项以保持示例简单。

通常不希望使用Toast消息在很长时间间隔内显示消息,因为这不是Toast类的预期目的。但是有时候,你需要显示的文本量可能需要用户超过3.5秒的时间来阅读,在这种情况下,稍微延长时间(例如,如上所示,到6.5秒)可能是有用的,并且与预期的用法一致。

为此,我编写了一个辅助类。你可以在github: https://github.com/quiqueqs/Toast-Expander/blob/master/src/com/thirtymatches/toasted/ToastedActivity.java上看到代码

这是你如何在5秒(或5000毫秒)内显示祝酒词:

Toast aToast = Toast.makeText(this, "Hello World", Toast.LENGTH_SHORT);
ToastExpander.showFor(aToast, 5000);

我知道答案已经很晚了。我也有同样的问题,在研究了android的Toast源代码后,决定实现我自己的裸骨吐司版本。

基本上,您需要创建一个新的窗口管理器,并使用处理程序在所需的持续时间内显示和隐藏窗口

 //Create your handler
Handler mHandler = new Handler();


//Custom Toast Layout
mLayout = layoutInflater.inflate(R.layout.customtoast, null);


//Initialisation


mWindowManager = (WindowManager) context.getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams();


params.gravity = Gravity.BOTTOM
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.format = PixelFormat.TRANSLUCENT;
params.windowAnimations = android.R.style.Animation_Toast;
params.type = WindowManager.LayoutParams.TYPE_TOAST;

初始化布局后,您可以使用自己的隐藏和显示方法

    public void handleShow() {
mWindowManager.addView(mLayout, mParams);
}


public void handleHide() {
if (mLayout != null) {
if (mLayout.getParent() != null) {
mWindowManager.removeView(mLayout);
}
mLayout = null;
}

现在你所需要的就是添加两个可运行的线程,分别调用handleShow()和handleHide(),你可以将它们发布到Handler中。

    Runnable toastShowRunnable = new Runnable() {
public void run() {
handleShow();
}
};


Runnable toastHideRunnable = new Runnable() {
public void run() {
handleHide();
}
};

最后一部分

public void show() {


mHandler.post(toastShowRunnable);
//The duration that you want
mHandler.postDelayed(toastHideRunnable, mDuration);


}

这是一个快速而肮脏的实现。没有考虑到任何业绩。

正如其他人提到的,Android toast可以是LENGTH_LONG或LENGTH_SHORT。这是没有办法的,你也不应该遵循发布的任何“技巧”。

toast的目的是显示“非必要的”信息,由于它们的持久影响,如果消息的持续时间超过一定的阈值,消息可能会脱离上下文。如果股票吐司被修改,使它们可以显示比LENGTH_LONG更长的时间,消息将在屏幕上停留,直到应用程序的进程终止,因为吐司视图被添加到WindowManager,而不是应用程序中的ViewGroup。我认为这就是硬编码的原因。

如果您确实需要显示toast样式的消息超过3.5秒,我建议构建一个附加到Activity内容的视图,这样当用户退出应用程序时,它就会消失。我的SuperToasts库处理这个问题和许多其他问题,请随意使用它!你很可能会对使用SuperActivityToasts感兴趣

Toast.makeText(this, "Text", Toast.LENGTH_LONG).show();
Toast.makeText(this, "Text", Toast.LENGTH_LONG).show();

这个问题的解决方法很简单。两到三倍就能让吐司保鲜得更久。这是唯一的办法。

如果你需要一个很长的Toast,有一个实用的替代方案,但它需要你的用户点击一个OK按钮来让它消失。你可以像这样使用AlertDialog:

String message = "This is your message";
new AlertDialog.Builder(YourActivityName.this)
.setTitle("Optional Title (you can omit this)")
.setMessage(message)
.setPositiveButton("ok", null)
.show();

如果您有一个很长的消息,很可能您不知道用户需要多长时间来阅读消息,因此有时要求用户单击OK按钮来继续是一个好主意。在我的例子中,当用户单击帮助图标时,我使用了这种技术。

用户不能自定义吐司的持续时间。因为NotificationManagerService的scheduleTimeoutLocked()函数没有使用字段duration。源代码如下。

private void scheduleTimeoutLocked(ToastRecord r, boolean immediate)
{
Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY);
mHandler.removeCallbacksAndMessages(r);
mHandler.sendMessageDelayed(m, delay);
}

我已经开发了一个自定义吐司类,您可以显示吐司所需的持续时间(以毫秒计)

import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;


public final class ToastHelper {


private static final String TAG = ToastHelper.class.getName();


public static interface OnShowListener {
public void onShow(ToastHelper toast);
}


public static interface OnDismissListener {
public void onDismiss(ToastHelper toast);
}


private static final int WIDTH_PADDING_IN_DIP = 25;
private static final int HEIGHT_PADDING_IN_DIP = 15;
private static final long DEFAULT_DURATION_MILLIS = 2000L;


private final Context context;
private final WindowManager windowManager;
private View toastView;


private int gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
private int mX;
private int mY;
private long duration = DEFAULT_DURATION_MILLIS;
private CharSequence text = "";
private int horizontalMargin;
private int verticalMargin;
private WindowManager.LayoutParams params;
private Handler handler;
private boolean isShowing;
private boolean leadingInfinite;


private OnShowListener onShowListener;
private OnDismissListener onDismissListener;


private final Runnable timer = new Runnable() {


@Override
public void run() {
cancel();
}
};


public ToastHelper(Context context) {
Context mContext = context.getApplicationContext();
if (mContext == null) {
mContext = context;
}
this.context = mContext;
windowManager = (WindowManager) mContext
.getSystemService(Context.WINDOW_SERVICE);
init();
}


private void init() {
mY = context.getResources().getDisplayMetrics().widthPixels / 5;
params = new WindowManager.LayoutParams();
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.format = android.graphics.PixelFormat.TRANSLUCENT;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
params.setTitle("ToastHelper");
params.alpha = 1.0f;
// params.buttonBrightness = 1.0f;
params.packageName = context.getPackageName();
params.windowAnimations = android.R.style.Animation_Toast;
}


@SuppressWarnings("deprecation")
@android.annotation.TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private View getDefaultToastView() {
TextView textView = new TextView(context);
textView.setText(text);
textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
textView.setClickable(false);
textView.setFocusable(false);
textView.setFocusableInTouchMode(false);
textView.setTextColor(android.graphics.Color.WHITE);
// textView.setBackgroundColor(Color.BLACK);
android.graphics.drawable.Drawable drawable = context.getResources()
.getDrawable(android.R.drawable.toast_frame);
if (Build.VERSION.SDK_INT < 16) {
textView.setBackgroundDrawable(drawable);
} else {
textView.setBackground(drawable);
}
int wP = getPixFromDip(context, WIDTH_PADDING_IN_DIP);
int hP = getPixFromDip(context, HEIGHT_PADDING_IN_DIP);
textView.setPadding(wP, hP, wP, hP);
return textView;
}


private static int getPixFromDip(Context context, int dip) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dip, context.getResources().getDisplayMetrics());
}


public void cancel() {
removeView(true);
}


private void removeView(boolean invokeListener) {
if (toastView != null && toastView.getParent() != null) {
try {
Log.i(TAG, "Cancelling Toast...");
windowManager.removeView(toastView);
handler.removeCallbacks(timer);
} finally {
isShowing = false;
if (onDismissListener != null && invokeListener) {
onDismissListener.onDismiss(this);
}
}
}
}


public void show() {
if (leadingInfinite) {
throw new InfiniteLoopException(
"Calling show() in OnShowListener leads to infinite loop.");
}
cancel();
if (onShowListener != null) {
leadingInfinite = true;
onShowListener.onShow(this);
leadingInfinite = false;
}
if (toastView == null) {
toastView = getDefaultToastView();
}
params.gravity = android.support.v4.view.GravityCompat
.getAbsoluteGravity(gravity, android.support.v4.view.ViewCompat
.getLayoutDirection(toastView));
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
params.horizontalWeight = 1.0f;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
params.verticalWeight = 1.0f;
}
params.x = mX;
params.y = mY;
params.verticalMargin = verticalMargin;
params.horizontalMargin = horizontalMargin;


removeView(false);
windowManager.addView(toastView, params);
isShowing = true;
if (handler == null) {
handler = new Handler();
}
handler.postDelayed(timer, duration);
}


public boolean isShowing() {
return isShowing;
}


public void setDuration(long durationMillis) {
this.duration = durationMillis;
}


public void setView(View view) {
removeView(false);
toastView = view;
}


public void setText(CharSequence text) {
this.text = text;
}


public void setText(int resId) {
text = context.getString(resId);
}


public void setGravity(int gravity, int xOffset, int yOffset) {
this.gravity = gravity;
mX = xOffset;
mY = yOffset;
}


public void setMargin(int horizontalMargin, int verticalMargin) {
this.horizontalMargin = horizontalMargin;
this.verticalMargin = verticalMargin;
}


public long getDuration() {
return duration;
}


public int getGravity() {
return gravity;
}


public int getHorizontalMargin() {
return horizontalMargin;
}


public int getVerticalMargin() {
return verticalMargin;
}


public int getXOffset() {
return mX;
}


public int getYOffset() {
return mY;
}


public View getView() {
return toastView;
}


public void setOnShowListener(OnShowListener onShowListener) {
this.onShowListener = onShowListener;
}


public void setOnDismissListener(OnDismissListener onDismissListener) {
this.onDismissListener = onDismissListener;
}


public static ToastHelper makeText(Context context, CharSequence text,
long durationMillis) {
ToastHelper helper = new ToastHelper(context);
helper.setText(text);
helper.setDuration(durationMillis);
return helper;
}


public static ToastHelper makeText(Context context, int resId,
long durationMillis) {
String string = context.getString(resId);
return makeText(context, string, durationMillis);
}


public static ToastHelper makeText(Context context, CharSequence text) {
return makeText(context, text, DEFAULT_DURATION_MILLIS);
}


public static ToastHelper makeText(Context context, int resId) {
return makeText(context, resId, DEFAULT_DURATION_MILLIS);
}


public static void showToast(Context context, CharSequence text) {
makeText(context, text, DEFAULT_DURATION_MILLIS).show();
}


public static void showToast(Context context, int resId) {
makeText(context, resId, DEFAULT_DURATION_MILLIS).show();
}


private static class InfiniteLoopException extends RuntimeException {
private static final long serialVersionUID = 6176352792639864360L;


private InfiniteLoopException(String msg) {
super(msg);
}
}
}

一个自定义背景和视图的祝酒词对我来说很管用。我在nexus 7平板电脑上测试了它,我注意到在循环过程中没有淡入淡出动画。实现如下:

public static void customToast(Context context, String message, int duration) {


for (int i = 0; i < duration; i++) {
Toast toast = new Toast(context);
toast.setDuration(Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.toast_layout, null);
TextView textViewToast = (TextView) view
.findViewById(R.id.textViewToast);
textViewToast.setText(message);
toast.setView(view);
toast.show();
}


}

下面是上面代码中使用的自定义textview:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/textViewToast"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/fragment_background"
android:padding="8dp"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="@color/blue" />

@drawable/fragment_background正在使我的吐司有圆角,就像kitkat版本一样。您还可以在该文件中添加其他视图。任何改进和评论的修改都是鼓励的,因为我计划在我的live应用程序中实现这一点。

使用Crouton,这是一个非常灵活的吐司库。

油炸面包丁 .

你可以像烤面包一样使用它:

Crouton.makeText(context, "YOUR_MESSAGE", Style.INFO);

或者你甚至可以更深入一点,自定义更多,比如将时间设置为无限!例如,在这里我想显示一个toast消息,直到用户通过点击它来确认它。

private static void showMessage(final Activity context, MessageType type, String header, String message) {
View v = context.getLayoutInflater().inflate(R.layout.toast_layout, null);
TextView headerTv = (TextView) v.findViewById(R.id.toastHeader);
headerTv.setText(header);
TextView messageTv = (TextView) v.findViewById(R.id.toastMessage);
messageTv.setText(message);
ImageView toastIcon = (ImageView) v.findViewById(R.id.toastIcon);


final Crouton crouton = getCrouton(context, v);
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Crouton.hide(crouton);
}
});


crouton.show();
}


private static Crouton getCrouton(final Activity context, View v) {
Crouton crouton = Crouton.make(context, v);
crouton.setConfiguration(new Configuration.Builder().setDuration(Configuration.DURATION_INFINITE).build());
return crouton;
}

自定义布局,将膨胀为吐司。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:background="@drawable/shadow_container"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="@dimen/default_margin"
tools:ignore="Overdraw">


<ImageView
android:id="@+id/toastIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />


<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_spacing_full"
android:layout_weight="1"
android:orientation="vertical">


<TextView
android:id="@+id/toastHeader"
style="@style/ItemText"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />


<TextView
android:id="@+id/toastMessage"
style="@style/ItemSubText"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />


</LinearLayout>


</LinearLayout>

我知道我有点晚了,但我取了Regis_AG的答案,并将其包装在一个助手类中,它工作得很好。

public class Toaster {
private static final int SHORT_TOAST_DURATION = 2000;


private Toaster() {}


public static void makeLongToast(String text, long durationInMillis) {
final Toast t = Toast.makeText(App.context(), text, Toast.LENGTH_SHORT);
t.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0);


new CountDownTimer(Math.max(durationInMillis - SHORT_TOAST_DURATION, 1000), 1000) {
@Override
public void onFinish() {
t.show();
}


@Override
public void onTick(long millisUntilFinished) {
t.show();
}
}.start();
}
}

在你的应用代码中,就像这样做:

    Toaster.makeLongToast("Toasty!", 8000);

将吐司设置为以毫秒为单位的特定时间段:

public void toast(int millisec, String msg) {
Handler handler = null;
final Toast[] toasts = new Toast[1];
for(int i = 0; i < millisec; i+=2000) {
toasts[0] = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
toasts[0].show();
if(handler == null) {
handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
toasts[0].cancel();
}
}, millisec);
}
}
}

LONG_DELAY吐司显示为3.5秒SHORT_DELAY吐司显示为2秒

Toast内部使用INotificationManager并在每次调用Toast.show()时调用它的enqueueToast方法。

使用SHORT_DELAY调用show()两次将再次将同一toast排队。它将显示为4秒(2秒+ 2秒)。

类似地,两次使用LONG_DELAY调用show()将再次将同一toast排队。它将显示为7秒(3.5秒+ 3.5秒)

简单地使用SuperToast在任何情况下做一个优雅的祝酒词。做你的吐司。编辑你的字体颜色,它也是大小。希望这对你来说都是一体的。

为什么要吃吐司,当你可以拥有整个间小吃店: https://developer.android.com/reference/android/support/design/widget/Snackbar.html

小吃店>吐司,定制吐司,油炸面包丁

计划一个倒计时,直到将来的某个时间,并在此过程中定期通知。在文本框中显示30秒倒计时的例子:



new CountDownTimer(30000, 1000) {


public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}


public void onFinish() {
mTextField.setText("done!");
}
}.start();




这段文字将在5秒内消失。

    final Toast toast = Toast.makeText(getApplicationContext(), "My Text", Toast.LENGTH_SHORT);
toast.show();


Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
toast.cancel();
}
}, 5000); // Change to what you want
< p >编辑: 正如Itai Spector在评论中所说,它将显示约3.5秒,所以使用以下代码:

    int toastDuration = 5000; // in MilliSeconds
Toast mToast = Toast.makeText(this, "My text", Toast.LENGTH_LONG);
CountDownTimer countDownTimer;
countDownTimer = new CountDownTimer(toastDuration, 1000) {
public void onTick(long millisUntilFinished) {
mToast.show();
}


public void onFinish() {
mToast.cancel();
}
};


mToast.show();
countDownTimer.start();
  private Toast mToastToShow;
public void showToast(View view) {
// Set the toast and duration
int toastDurationInMilliSeconds = 10000;
mToastToShow = Toast.makeText(this, "Hello world, I am a toast.",  Toast.LENGTH_LONG);


// Set the countdown to display the toast
CountDownTimer toastCountDown;
toastCountDown = new CountDownTimer(toastDurationInMilliSeconds, 1000 /*Tick duration*/) {
public void onTick(long millisUntilFinished) {
mToastToShow.show();
}
public void onFinish() {
mToastToShow.cancel();
}
};


// Show the toast and starts the countdown
mToastToShow.show();
toastCountDown.start();
}

吐司持续时间可以使用专门运行吐司的线程来破解。这是有效的(运行吐司10秒,根据你的喜好修改睡眠ctr):

final Toast toast = Toast.makeText(this, "Your Message", Toast.LENGTH_LONG);


Thread t = new Thread(){
public void run(){
int ctr = 0;
try{
while( ctr<10 ){
toast.show();
sleep(1000);
ctr++;
}
} catch (Exception e) {
Log.e("Error", "", e);
}
}
};
t.start();

在所有可用的解决方案都失败后,我最终使用递归解决了问题。

代码:

//Recursive function, pass duration in seconds
public void showToast(int duration) {
if (duration <= 0)
return;


Toast.makeText(this, "Hello, it's a toast", Toast.LENGTH_LONG).show();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
showToast(duration-1);
}
}, 1000);
}

不,这里列出的大多数/所有黑客都不再适用于android 9。但有一个更好的解决方案:如果你的消息需要挂着,使用对话框。

(new AlertDialog.Builder(this)).setTitle("Sorry!")
.setMessage("Please let me know by posting a beta comment on the play store .")
.setPositiveButton("OK", null).create().show();
val toast = Toast.makeText(this, "", Toast.LENGTH_LONG)


val countDownTimer = object : CountDownTimer(5000, 1000) {
override fun onTick(millisUntilFinished: Long) { }
override fun onFinish() { toast.cancel() }
}


toast.show()
countDownTimer.start()