You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android项目全局通用ProgressBar实现方案求助(附自定义代码)

通用全局ProgressBar实现方案(Android Java)

我来给你分享两种非常实用的通用ProgressBar实现方案,解决你之前重复布局、显示隐藏控制麻烦的问题,附上完整的Java代码示例:


方案一:全局单例工具类(灵活无侵入)

这种方案不需要修改现有页面的继承关系,通过单例工具类动态添加加载框到窗口,所有Activity/Fragment都能直接调用。

第一步:完善自定义ProgressBar布局

先把你未完成的布局补全,命名为layout_progress_loading.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#80000000"
    android:gravity="center">

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminate="true"
        android:indeterminateTint="@color/white" />

    <!-- 可选:添加加载提示文字 -->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="加载中..."
        android:textColor="@color/white"
        android:textSize="14sp" />
</FrameLayout>

第二步:实现单例工具类

创建ProgressLoadingUtil.java,负责加载框的显示和隐藏:

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;

public class ProgressLoadingUtil {
    private static ProgressLoadingUtil instance;
    private View loadingView;
    private WindowManager windowManager;
    private WindowManager.LayoutParams layoutParams;

    private ProgressLoadingUtil() {
        // 私有构造,保证单例
    }

    public static ProgressLoadingUtil getInstance() {
        if (instance == null) {
            synchronized (ProgressLoadingUtil.class) {
                if (instance == null) {
                    instance = new ProgressLoadingUtil();
                }
            }
        }
        return instance;
    }

    // 显示加载框
    public void showLoading(Context context) {
        // 校验Context有效性,避免内存泄漏
        if (context == null || (context instanceof Activity && ((Activity) context).isFinishing())) {
            return;
        }

        // 避免重复添加
        if (loadingView != null && loadingView.getParent() != null) {
            return;
        }

        windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        loadingView = LayoutInflater.from(context).inflate(R.layout.layout_progress_loading, null);

        // 适配Android版本的窗口参数
        layoutParams = new WindowManager.LayoutParams();
        layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
        layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
        layoutParams.format = android.graphics.PixelFormat.TRANSLUCENT;

        windowManager.addView(loadingView, layoutParams);
    }

    // 隐藏加载框
    public void hideLoading() {
        if (windowManager != null && loadingView != null && loadingView.getParent() != null) {
            try {
                windowManager.removeView(loadingView);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } finally {
                loadingView = null;
                windowManager = null;
            }
        }
    }
}

第三步:在页面中使用

不管是Activity还是Fragment,直接调用即可:

// 显示加载框(Activity中)
ProgressLoadingUtil.getInstance().showLoading(this);

// 显示加载框(Fragment中)
ProgressLoadingUtil.getInstance().showLoading(requireContext());

// 隐藏加载框(比如网络请求完成后)
ProgressLoadingUtil.getInstance().hideLoading();

注意事项

  • 记得在页面销毁时调用hideLoading(),避免内存泄漏;
  • Android 8.0+如果使用TYPE_APPLICATION_OVERLAY,需要在Manifest中添加权限:<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />,如果只是在自己应用内显示,也可以改用TYPE_APPLICATION(无需额外权限)。

方案二:BaseActivity/BaseFragment封装(统一管理生命周期)

如果你的项目已经有Base类,这种方案更省心,自动管理加载框的生命周期,不用手动清理。

第一步:实现BaseActivity

创建BaseActivity.java,封装加载框的显示和隐藏逻辑:

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public abstract class BaseActivity extends AppCompatActivity {
    private View loadingView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutId());
        initView();
    }

    // 子类实现:返回页面布局ID
    protected abstract int getLayoutId();
    // 子类实现:初始化页面控件
    protected abstract void initView();

    // 显示加载框
    protected void showLoading() {
        if (loadingView == null) {
            loadingView = LayoutInflater.from(this).inflate(R.layout.layout_progress_loading, null);
            // 获取页面根布局,添加加载框
            ViewGroup rootView = findViewById(android.R.id.content);
            rootView.addView(loadingView);
        }
        loadingView.setVisibility(View.VISIBLE);
    }

    // 隐藏加载框
    protected void hideLoading() {
        if (loadingView != null) {
            loadingView.setVisibility(View.GONE);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 页面销毁时移除加载框,避免内存泄漏
        if (loadingView != null && loadingView.getParent() != null) {
            ((ViewGroup) loadingView.getParent()).removeView(loadingView);
            loadingView = null;
        }
    }
}

第二步:实现BaseFragment

同理,创建BaseFragment.java:

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

public abstract class BaseFragment extends Fragment {
    private View loadingView;
    private View rootView;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        rootView = inflater.inflate(getLayoutId(), container, false);
        initView(rootView);
        return rootView;
    }

    protected abstract int getLayoutId();
    protected abstract void initView(View rootView);

    protected void showLoading() {
        if (loadingView == null && getContext() != null) {
            loadingView = LayoutInflater.from(getContext()).inflate(R.layout.layout_progress_loading, null);
            if (rootView instanceof ViewGroup) {
                ((ViewGroup) rootView).addView(loadingView);
            }
        }
        if (loadingView != null) {
            loadingView.setVisibility(View.VISIBLE);
        }
    }

    protected void hideLoading() {
        if (loadingView != null) {
            loadingView.setVisibility(View.GONE);
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (loadingView != null && loadingView.getParent() != null) {
            ((ViewGroup) loadingView.getParent()).removeView(loadingView);
            loadingView = null;
        }
        rootView = null;
    }
}

第三步:子类页面使用

Activity继承BaseActivity后直接调用:

public class MainActivity extends BaseActivity {
    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initView() {
        // 显示加载框
        showLoading();

        // 模拟网络请求,3秒后隐藏
        new android.os.Handler().postDelayed(() -> hideLoading(), 3000);
    }
}

Fragment继承BaseFragment同理:

public class HomeFragment extends BaseFragment {
    @Override
    protected int getLayoutId() {
        return R.layout.fragment_home;
    }

    @Override
    protected void initView(View rootView) {
        showLoading();
        // 业务逻辑...
    }
}

方案对比与选择

  • 单例工具类:适合没有统一Base类的项目,灵活无侵入,但需要手动管理加载框的生命周期,避免内存泄漏;
  • Base类封装:适合有统一Base类的项目,自动管理生命周期,代码更简洁,减少重复调用。

你可以根据自己项目的架构选择合适的方案,两种都能完美实现所有页面通用ProgressBar的需求。

内容的提问来源于stack exchange,提问作者Pixxu Waku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:21:21