Может ли Android-тост быть длиннее, чем Toast.LENGTH_LONG? - PullRequest
241 голосов
/ 08 февраля 2010

При использовании setDuration () для тоста, возможно ли установить пользовательскую длину или хотя бы что-то длиннее, чем Toast.LENGTH_LONG?

Ответы [ 28 ]

318 голосов
/ 22 февраля 2011

Если вы покопаетесь глубже в коде 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
131 голосов
/ 08 февраля 2010

Значения LENGTH_SHORT и LENGTH_LONG равны 0 и 1. Это означает, что они рассматриваются как флаги, а не как фактические длительности, поэтому я не думаю, что это будет можно установить длительность, отличную от этих значений.

Если вы хотите дольше отображать сообщение пользователю, рассмотрите Уведомление в строке состояния . Уведомления в строке состояния могут быть программно отменены, если они больше не актуальны.

117 голосов
/ 16 июня 2011

Вы можете попробовать:

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

чтобы удвоить время. Если вы укажете 3 вместо 2, это утроит время .. и т. Д.

93 голосов
/ 24 августа 2011

Лучшее решение, чтобы избежать эффектов затухания между тостами, которые запускаются последовательно:

final Toast tag = Toast.makeText(getBaseContext(), "YOUR MESSAGE",Toast.LENGTH_SHORT);

tag.show();

new CountDownTimer(9000, 1000)
{

    public void onTick(long millisUntilFinished) {tag.show();}
    public void onFinish() {tag.show();}

}.start();

Здесь тост отображается примерно через 10 с.

Надеюсь, это поможет.

31 голосов
/ 12 августа 2010

Если вы хотите, чтобы значение Toast сохранялось, я обнаружил, что вы можете взломать его, набрав Timer вызов toast.show() несколько раз (каждую секунду или около того следует делать). Вызов show() ничего не нарушает, если Toast уже отображается, но он обновляет количество времени, которое он остается на экране.

16 голосов
/ 18 января 2014

Я разработал класс Custom Toast, с помощью которого вы можете показывать Toast за желаемое количество времени (в миллисекундах)

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);
        }
    }
}
13 голосов
/ 03 января 2012

Я написал вспомогательный класс для этого. Вы можете увидеть код на 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);
10 голосов
/ 02 февраля 2015

Я знаю, что немного опоздал, но я взял ответ 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);
8 голосов
/ 01 ноября 2012

Я знаю, что ответ довольно поздно .. У меня возникла та же проблема, и я решил реализовать свою собственную версию Toast, после изучения исходного кода 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);

}

Это была быстрая и грязная реализация. Не принимал во внимание какую-либо производительность.

7 голосов
/ 28 августа 2015

LONG_DELAY тост-дисплей для 3,5 с и SHORT_DELAY тост-дисплей для 2 с .

Toast внутренне использует INotificationManager и вызывает его метод enqueueToast при каждом вызове Toast.show ().

Вызовите show () дважды с SHORT_DELAY, чтобы снова поставить в очередь один и тот же тост. будет отображаться 4 с (2 с + 2 с).

аналогично, вызовите show () с LONG_DELAY дважды, чтобы снова поставить в очередь один и тот же тост. будет отображаться в течение 7 с (3,5 с + 3,5 с)

...