¿Cómo deshabilitar la interacción del usuario mientras ProgressBar está visible en Android?

80

Estoy usando una barra de progreso personalizada. Ahora, mientras se realiza una tarea, estoy mostrando la barra de progreso, pero el usuario aún puede interactuar con las vistas y los controles. ¿Cómo desactivo la interacción del usuario en la vista completa tal como lo hace un ProgressDialog, cuando está visible?

¿Necesito usar una vista transparente en la parte superior de la vista principal y mostrar la barra de progreso en esa vista y ocultar esa vista una vez que se complete una tarea?

¿O simplemente obtener la identificación de mi parentView y desactivarla? Pero entonces no podré atenuar el fondo, como sucede cuando aparece un cuadro de diálogo en la vista / Actividad / Fragmento. ¿Correcto?

Solo quiero saber la forma de no permitir que el usuario interactúe mientras la barra de progreso está visible.

Gracias

intellignt_idiot
fuente
4
@txteclipse No quiero personalizar la barra de progreso, ya lo hice. Entonces, mi pregunta no está duplicada. Solo quiero deshabilitar la interacción del usuario mientras la barra de progreso está visible, de la misma manera cuando un ProgressDialog está visible, el usuario no puede interactuar con otros controles de IU sin descartar el cuadro de diálogo de progreso. Ahora, ¿cómo es que mi pregunta es un duplicado de esa pregunta? Mi pregunta no está ni remotamente relacionada con la personalización.
intellignt_idiot
1
Si desea toda la funcionalidad de un diálogo, debe utilizar un diálogo. La modalidad no es trivial de implementar: la respuesta aceptada no bloquea la interacción del teclado, por ejemplo. La segunda respuesta en la pregunta vinculada demuestra cómo usar recursos ProgressBar personalizados con un ProgressDialog. Si eso no satisface sus necesidades, puede usar un diseño personalizado con su ProgressBar.
Graph Theory

Respuestas:

147

Su pregunta: ¿Cómo deshabilitar la interacción del usuario mientras ProgressBar está visible en Android?

Para deshabilitar la interacción del usuario solo necesita agregar el siguiente código

getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                    WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

Para recuperar la interacción del usuario, solo necesita agregar el siguiente código

getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

A continuación se muestra un ejemplo: Nota: le doy solo un ejemplo para mostrar cómo deshabilitar o retener la interacción del usuario

Agrega una barra de progreso en tu xml, algo como esto

<ProgressBar
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/progressBar"
    android:visibility="gone"/>

En MainActivity, cuando se presiona un botón, muestra la barra de progreso y deshabilita la interacción del usuario.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mImageView = (ImageView) findViewById(R.id.imageView);
    mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
    mImageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mProgressBar.setVisibility(View.VISIBLE);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                    WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
        }
    });
}

Y cuando el usuario retrocede, eliminas la barra de progreso y retienes la interacción del usuario.

  @Override
public void onBackPressed() {
    super.onBackPressed();
    mProgressBar.setVisibility(View.GONE);
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}

Si desea agregar una función de visualización desactivada y atenuada, debe agregar en su archivo de diseño xml un diseño lineal que llene el primario. Establezca su fondo en # B0000000 y su visibiltya GONE. Luego, establezca programáticamente su visibilityen VISIBLE.

¡Espero que esto ayude!

Niyamat Ullah
fuente
1
Hay algo interesante en esta implementación. Estoy desarrollando una aplicación portátil para un reloj polar y esta solución me ha estado dando algunos problemas. Me di cuenta de que cada vez que el usuario toca la pantalla rápidamente si la acción después de dicho toque está bloqueando la interfaz de usuario con su solución (para evitar múltiples eventos), por alguna razón, Android abre cualquier aplicación u opción que esté detrás de mi aplicación. Para tratar de explicarlo un poco mejor, es como si mi aplicación se minimizara por una fracción de segundo muy rápido y me permitiera tocar cualquier cosa que esté en la pantalla en ese momento. ¿Alguien ha experimentado algo similar?
Roger
13

He solucionado este problema agregando un diseño raíz al archivo ProgressBar.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:clickable="true"
    android:gravity="center"
    android:visibility="gone"
    android:id="@+id/progress">
    <ProgressBar
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:indeterminate="true"
        android:indeterminateTintMode="src_atop"
        android:indeterminateTint="@color/primary"/>
</LinearLayout>

Hizo clic en el diseño raíz

android:clickable="true"

NOTA: En mi vista principal, teníaRelativeLayout como raíz y agregué el código mencionado anteriormente dentro del diseño raíz en la última posición (último hijo).

¡¡Espero que esto ayude!!

Nirav Dangi
fuente
Sugeriría un FrameLayoutlugar de uno LinearLayout, aparte de eso, esta respuesta es perfecta y simplemente funciona. Gracias Nivar
Lucas P.
¿Funciona esto cuando hay botones en la vista de fondo? La elevación de esos parece más alta (api 21+ al menos) y se podrá hacer clic en ellos, a menos que establezca una elevación más alta en este diseño de raíz.
Ixx
10

acaba de configurar:

android:clickable="true" 

en tu xml

<ProgressBar...

¡Solo esto hace magia!

Paulo Linhares - Packapps
fuente
3

Utilice el método predeterminado del documento progressbar.setCancelable (false)

Ramesh sambu
fuente
1
Pero, ¿qué efecto tendrá en la interacción del usuario? Todavía puedo tocar o escribir EditText mientras ProgressBar está visible y se puede cancelar en falso.
intellignt_idiot
6
y ¿desde cuándo una barra de progreso comenzó a tener la propiedad setCancelable (false)?
intellignt_idiot
Tiene la opción cuando su tarea en ejecución se configura como falsa como la vista principal y después de la tarea se configura como verdadera
Ramesh sambu
3

Haz un diálogo con fondo transparente. El problema getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);es que cuando la aplicación pasa a segundo plano y regresa, el usuario podrá interactuar con los componentes de la interfaz de usuario, mucho más manejo. Entonces, para bloquear la interfaz de usuario, haga un cuadro de diálogo transparente y si desea establecer un tiempo para ocultar / mostrar. Haga esto en un hilo ejecutable. Entonces la solución será

public class TransparentDialogHelper {

    private Dialog overlayDialog;

    @Inject
    public TransparentDialogHelper() {

    }

    public void showDialog(Context context) {
        if (AcmaUtility.isContextFinishing(context)) {
            return;
        }
        if (overlayDialog == null) {
            overlayDialog = new Dialog(context, android.R.style.Theme_Panel);
            overlayDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED);
        }
        overlayDialog.show();
    }

    public void hideDialog() {
        if (overlayDialog == null || AcmaUtility.isContextFinishing(overlayDialog.getContext())) {
            return;
        }
        overlayDialog.cancel();
    }
}

-------- Timer

Handler handler = new Handler();
handler.postDelayed( () -> {
    view.hideProgress();
}, 2000);
Qumber Abbas
fuente
Excelente solución, mantiene un control explícito sobre el proceso. Oh, sí, y también funciona. UPVOTED :)
tony gil
1

Haga su diseño principal como Diseño relativo y agregue esto:

    <RelativeLayout ... >

    <other layout elements over which prog bar will appear>

<RelativeLayout android:id="@+id/rl_progress_bar"
                android:layout_width="match_parent" android:clickable="true"
                android:layout_height="match_parent" >
<ProgressBar android:id="@+id/pb"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_centerInParent="true"
             android:indeterminateOnly="true"
             style="@android:style/Widget.DeviceDefault.ProgressBar"
             android:theme="@style/AppTheme.MyProgressBar"
    />
</RelativeLayout>

Si tiene botones flotantes en su interfaz de usuario, aún capturan todo el enfoque y se pueden hacer clic cuando la barra de progreso está visible. para este uso: (cuando su barra de progreso esté visible y vuelva a habilitarlos cuando haga que su barra de progreso sea invisible / desaparezca)

fb.setEnabled(false);
AndroidGuy
fuente
1

Para extender (juego de palabras intencionado) en la Respuesta aceptada :

Cuando usa kotlin, puede usar funciones de extensión. De esa manera, tiene un método rápido y atractivo para bloquear y desbloquear la interfaz de usuario.

fun AppCompatActivity.blockInput() {
    window.setFlags(
        WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
        WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
}

fun AppCompatActivity.unblockInput() {
    window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
}

fun AppCompatActivity.blockInputForTask(task: () -> Unit) {
    blockInput()
    task.invoke()
    unblockInput()
}

Puede utilizar las funciones de bloqueo y desbloqueo en su actividad. Además, puede agregar más funciones, como mostrar un brindis o algo.

Cuando lo usa en una vista personalizada o en cualquier otra vista, simplemente puede convertir el contexto a la actividad y usar las funciones.

Úselo blockInputForTaskpara rodear tareas lineales simples blockInputy unblockInputcuando se necesiten en diferentes ámbitos.

Puedes usar blockInputForTaskasí:

blockInputForTask { 
    // Your lines of code
    // Can be multiple lines
}
Benjamín Basmaci
fuente