package com.xscm.moduleutil.activity; import static androidx.core.content.ContextCompat.getSystemService; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.databinding.DataBindingUtil; import androidx.databinding.ViewDataBinding; import com.alibaba.android.arouter.launcher.ARouter; import com.blankj.utilcode.util.ActivityUtils; import com.blankj.utilcode.util.BarUtils; import com.hjq.toast.ToastUtils; import com.tencent.qcloud.tuikit.tuichat.bean.ChatInfo; import com.xscm.moduleutil.R; import com.xscm.moduleutil.base.CommonAppContext; import com.xscm.moduleutil.bean.XLHBean; import com.xscm.moduleutil.event.MqttBean; import com.xscm.moduleutil.utils.ARouteConstants; import com.xscm.moduleutil.utils.BackgroundManager; import com.xscm.moduleutil.utils.ColorManager; import com.xscm.moduleutil.utils.DisplayUtil; import com.xscm.moduleutil.utils.ImageUtils; import com.xscm.moduleutil.utils.LanguageUtil; import com.xscm.moduleutil.utils.SpUtil; import com.xscm.moduleutil.widget.PiaoPingManager; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; public abstract class BaseAppCompatActivity extends AppCompatActivity implements BackgroundManager.BackgroundUpdateListener, ColorManager.ColorChangeListener { // @Override // protected void attachBaseContext(Context newBase) { // super.attachBaseContext(LanguageUtil.attachBaseContext(newBase)); // } @Override protected void attachBaseContext(Context newBase) { // 设置字体缩放比例为1.0f,即不跟随系统字体大小变化 super.attachBaseContext(DisplayUtil.attachBaseContext(newBase, 1.0f)); } protected VDB mBinding; private static final List activityList = new ArrayList<>(); // private LoadingDialog mLoadingDialog; // 添加广播接收器成员变量 private BroadcastReceiver mLogoutReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if ("com.xscm.moduleutil.ACTION_USER_LOGOUT".equals(intent.getAction())) { // 在这里处理用户登出后的UI更新 // 例如:隐藏需要登录才能显示的控件 // 或者跳转到登录状态的页面 handleUserLogout(); } } }; // 处理用户登出的方法 protected void handleUserLogout() { // 子类可以重写此方法处理具体的登出逻辑 // 例如:更新UI状态、清除本地数据等 ActivityUtils.finishAllActivities(); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().getDecorView().setBackgroundResource(R.mipmap.log_bj); setContentView(getLayoutId()); // 隐藏标题栏 if (getSupportActionBar() != null) { getSupportActionBar().hide(); } mBinding = DataBindingUtil.setContentView(this, getLayoutId()); mBinding.setLifecycleOwner(this); ARouter.getInstance().inject(this); BarUtils.setStatusBarLightMode(this, isLightMode()); BarUtils.transparentStatusBar(this); initView(); initData(); initCompleted(); // 注册背景更新监听器 BackgroundManager.getInstance().addListener(this); // 尝试加载网络背景 loadNetworkBackground(); // 注册颜色变化监听器 ColorManager.getInstance().addColorChangeListener(this); // 注册登出广播接收器 IntentFilter filter = new IntentFilter("com.xscm.moduleutil.ACTION_USER_LOGOUT"); registerReceiver(mLogoutReceiver, filter); // 动态判断是否包含 @Subscribe 注解的方法 boolean hasSubscribeMethods = false; for (Method method : getClass().getDeclaredMethods()) { if (method.isAnnotationPresent(Subscribe.class)) { hasSubscribeMethods = true; break; } } if (hasSubscribeMethods) { EventBus.getDefault().register(this); } } // 在Activity中 private static final int REQUEST_OVERLAY_PERMISSION = 1001; private void checkAndRequestOverlayPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { new AlertDialog.Builder(this) .setTitle("需要悬浮窗权限") .setMessage("应用需要悬浮窗权限才能显示飘屏效果") .setPositiveButton("去设置", (dialog, which) -> { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, REQUEST_OVERLAY_PERMISSION); }) .setNegativeButton("取消", null) .show(); } } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_OVERLAY_PERMISSION) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOverlays(this)) { ToastUtils.show("已获得悬浮窗权限"); } else { ToastUtils.show("未获得悬浮窗权限"); } } } } public static void finishAll() { for (BaseMvpActivity activity : activityList) { if (!activity.isFinishing()) { activity.finish(); } } } @Override public void onColorChanged() { // 在主线程中更新UI runOnUiThread(this::updateUIColors); } // 子类可以重写此方法来更新UI颜色 protected void updateUIColors() { // 默认实现,子类可以覆盖 } protected void loadNetworkBackground() { // 只有当已经有背景URL时才加载 String backgroundUrl = BackgroundManager.getInstance().getBackgroundUrl(); if (backgroundUrl != null && !backgroundUrl.isEmpty()) { // 检查是否有已加载的drawable Drawable cachedDrawable = BackgroundManager.getInstance().getBackgroundDrawable(); if (cachedDrawable != null) { getWindow().getDecorView().setBackground(cachedDrawable); } else { // 加载网络背景 BackgroundManager.getInstance().loadBackgroundDrawable(this, new BackgroundManager.BackgroundLoadCallback() { @Override public void onLoadSuccess(Drawable drawable) { getWindow().getDecorView().setBackground(drawable); } @Override public void onLoadFailed() { // 加载失败时使用默认背景 getWindow().getDecorView().setBackgroundResource(R.mipmap.activity_bj); } }); } } } @Override public void onBackgroundUpdated(Drawable drawable) { // 当背景更新时,更新当前Activity的背景 if (drawable != null) { getWindow().getDecorView().setBackground(drawable); } } // 提供一个方法供子类调用,用于设置背景URL protected void setNetworkBackgroundUrl(String url) { BackgroundManager.getInstance().setBackgroundUrl(url); } @Override public Resources getResources() {//禁止app字体大小跟随系统字体大小调节 Resources resources = super.getResources(); if (resources != null && resources.getConfiguration().fontScale != 1.0f) { android.content.res.Configuration configuration = resources.getConfiguration(); configuration.fontScale = 1.0f; resources.updateConfiguration(configuration, resources.getDisplayMetrics()); } return resources; } static float fontScale = 1f; // @Override // public Resources getResources() { // Resources resources = super.getResources(); // return DisplayUtil.getResources(this,resources,fontScale); // } public void setFontScale(float fontScale) { this.fontScale = fontScale; DisplayUtil.recreate(this); } public boolean isLightMode() { return true; } protected abstract void initData(); protected abstract void initView(); protected void initCompleted() { } protected abstract int getLayoutId(); @Override protected void onDestroy() { // 移除背景更新监听器 BackgroundManager.getInstance().removeListener(this); // 移除颜色变化监听器 ColorManager.getInstance().removeColorChangeListener(this); if (mBinding != null) { mBinding.unbind(); } if (EventBus.getDefault().isRegistered(this)) { EventBus.getDefault().unregister(this); } try { unregisterReceiver(mLogoutReceiver); } catch (Exception e) { // 忽略异常 } super.onDestroy(); } public void showLoading(String content) { // if (mLoadingDialog == null) { // mLoadingDialog = new LoadingDialog(this); // } // if (!mLoadingDialog.isShowing()) { // mLoadingDialog.show(); // } } public void showLoading() { // if (mLoadingDialog == null) { // mLoadingDialog = new LoadingDialog(this); // } // if (!mLoadingDialog.isShowing()) { // mLoadingDialog.show(); // } } public void disLoading() { // if (mLoadingDialog != null && mLoadingDialog.isShowing()) { // mLoadingDialog.dismiss(); // } } @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { View view = getCurrentFocus(); if (isShouldHideInput(view, ev)) { InputMethodManager Object = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); if (Object != null) { Object.hideSoftInputFromWindow(view.getWindowToken(), 0); } } } try { return super.dispatchTouchEvent(ev); } catch (Exception e) { return false; } } //判断是否隐藏键盘 public boolean isShouldHideInput(View v, MotionEvent event) { if (v != null && (v instanceof EditText)) { int[] leftTop = {0, 0}; //获取输入框当前的location位置 v.getLocationInWindow(leftTop); int left = leftTop[0]; int top = leftTop[1]; int bottom = top + v.getHeight(); int right = left + v.getWidth(); if (event.getX() > left && event.getX() < right && event.getY() > top && event.getY() < bottom) { // 点击的是输入框区域,保留点击EditText的事件 return false; } else { return true; } } return false; } // 在类中添加以下成员变量 private final List messageQueue = new ArrayList<>(); // 消息队列 private boolean isPlaying = false; // 播放状态标志 private final Object queueLock = new Object(); // 队列同步锁 ///礼物特效 @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageReceived(MqttBean mqttBean) { if (mqttBean == null) { return; } // 将消息添加到队列 synchronized (queueLock) { messageQueue.add(mqttBean); } // 尝试播放下一个消息 processNextMessage(); } private void processNextMessage() { synchronized (queueLock) { // 如果正在播放或队列为空,则不处理 if (isPlaying || messageQueue.isEmpty()) { return; } // 标记为正在播放 isPlaying = true; } MqttBean mqttBean; synchronized (queueLock) { mqttBean = messageQueue.remove(0); // 取出队列中的第一个消息 } // 显示飘屏消息 showFloatingMessage(mqttBean); } private View floatingView; // 成员变量保存浮动视图 private boolean isFloatingViewAdded = false; // 标记浮动视图是否已添加到 decorView private void showFloatingMessage(MqttBean mqttBean) { ViewGroup decorView = (ViewGroup) this.getWindow().getDecorView(); // 如果浮动视图未创建,则创建一次 if (floatingView == null) { floatingView = LayoutInflater.from(this).inflate(R.layout.item_piaoping, null); // 设置布局参数 FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT ); layoutParams.topMargin = com.sunfusheng.marqueeview.DisplayUtil.dip2px(this, 70); layoutParams.gravity = android.view.Gravity.TOP | android.view.Gravity.CENTER_HORIZONTAL; floatingView.setLayoutParams(layoutParams); // 初始化动画监听器 setupAnimationListener(floatingView, decorView); } // 更新视图数据 updateFloatingViewData(mqttBean); // 如果浮动视图未添加到 decorView,则添加 if (!isFloatingViewAdded) { decorView.addView(floatingView); isFloatingViewAdded = true; } // 重置视图位置并开始动画 resetAndStartAnimation(floatingView); } private void setupAnimationListener(View floatingView, ViewGroup decorView) { // 为视图添加一个全局布局监听器,确保在视图完全加载后再设置动画 floatingView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // 移除监听器,避免重复调用 floatingView.getViewTreeObserver().removeOnGlobalLayoutListener(this); // 确保初始位置在屏幕右侧外部 floatingView.setTranslationX(floatingView.getWidth()); // 第一阶段:从右到屏幕右侧边缘(缓慢进入) ObjectAnimator animator1 = ObjectAnimator.ofFloat(floatingView, "translationX", floatingView.getWidth(), 0f); animator1.setDuration(1500); // 延长动画时间到1.5秒 animator1.setInterpolator(new DecelerateInterpolator(2.0f)); // 更平缓的减速效果 animator1.start(); // 第二阶段:延迟1秒后从当前位置向左滑出 floatingView.postDelayed(() -> { ObjectAnimator animator2 = ObjectAnimator.ofFloat(floatingView, "translationX", 0f, -floatingView.getWidth()); animator2.setDuration(1500); // 延长动画时间到1.5秒 animator2.setInterpolator(new DecelerateInterpolator(2.0f)); // 更平缓的减速效果 animator2.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // 动画结束后移除悬浮窗 if (isFloatingViewAdded) { decorView.removeView(floatingView); isFloatingViewAdded = false; } // 标记播放结束并处理下一个消息 synchronized (queueLock) { isPlaying = false; } processNextMessage(); } }); animator2.start(); }, 3000); // 停留1秒 } }); } private void resetAndStartAnimation(View floatingView) { // 重置视图位置并开始动画 floatingView.setTranslationX(floatingView.getWidth()); // 第一阶段:从右到屏幕右侧边缘(缓慢进入) ObjectAnimator animator1 = ObjectAnimator.ofFloat(floatingView, "translationX", floatingView.getWidth(), 0f); animator1.setDuration(1500); animator1.setInterpolator(new DecelerateInterpolator(2.0f)); animator1.start(); // 第二阶段:延迟1秒后从当前位置向左滑出 floatingView.postDelayed(() -> { ObjectAnimator animator2 = ObjectAnimator.ofFloat(floatingView, "translationX", 0f, -floatingView.getWidth()); animator2.setDuration(1500); animator2.setInterpolator(new DecelerateInterpolator(2.0f)); animator2.start(); }, 3000); } private void updateFloatingViewData(MqttBean mqttBean) { TextView textView = floatingView.findViewById(R.id.tv_name); TextView textView2 = floatingView.findViewById(R.id.tv_to_name); TextView tv_time = floatingView.findViewById(R.id.tv_num); if (mqttBean.getList() != null) { if (mqttBean.getList().getToUserName() != null) { textView2.setText("送给" + mqttBean.getList().getToUserName()); } else { textView2.setText("送给"); } if (mqttBean.getList().getFromUserName() != null) { textView.setText(mqttBean.getList().getFromUserName()); } else { textView.setText(""); } if (mqttBean.getList().getGift_picture() != null) { ImageUtils.loadHeadCC(mqttBean.getList().getGift_picture(), floatingView.findViewById(R.id.iv_piaoping)); } if (mqttBean.getList().getNumber() != null) { tv_time.setText("x" + mqttBean.getList().getNumber()); } else { tv_time.setText("x1"); } } else { textView2.setText("送给"); textView.setText(""); tv_time.setText("x1"); } } // private void showFloatingMessage(MqttBean mqttBean) { // ViewGroup decorView = (ViewGroup) this.getWindow().getDecorView(); // View floatingView = LayoutInflater.from(this).inflate(R.layout.item_piaoping, null); // // // 设置布局参数,使整个布局显示在屏幕顶部并距离顶部100dp // FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( // FrameLayout.LayoutParams.MATCH_PARENT, // FrameLayout.LayoutParams.WRAP_CONTENT // ); // layoutParams.topMargin = com.sunfusheng.marqueeview.DisplayUtil.dip2px(this, 100); // 距离顶部100dp // layoutParams.gravity = android.view.Gravity.TOP | android.view.Gravity.CENTER_HORIZONTAL; // 顶部居中 // floatingView.setLayoutParams(layoutParams); // // TextView textView = floatingView.findViewById(R.id.tv_name); // TextView textView2 = floatingView.findViewById(R.id.tv_to_name); // TextView tv_time = floatingView.findViewById(R.id.tv_num); // // // 添加对 getList() 返回值的空值检查 // if (mqttBean.getList() != null) { // // 检查各个字段是否为 null // if (mqttBean.getList().getToUserName() != null) { // textView2.setText("送给" + mqttBean.getList().getToUserName()); // } else { // textView2.setText("送给"); // } // // if (mqttBean.getList().getFromUserName() != null) { // textView.setText(mqttBean.getList().getFromUserName()); // } else { // textView.setText(""); // } // // // 检查礼物图片 // if (mqttBean.getList().getGift_picture() != null) { // ImageUtils.loadHeadCC(mqttBean.getList().getGift_picture(), floatingView.findViewById(R.id.iv_piaoping)); // } // // // 检查数量 // if (mqttBean.getList().getNumber() != null) { // tv_time.setText("x" + mqttBean.getList().getNumber()); // } else { // tv_time.setText("x1"); // } // } else { // // 如果 getList() 返回 null,设置默认值 // textView2.setText("送给"); // textView.setText(""); // tv_time.setText("x1"); // } // // floatingView.setTranslationX(10000); // 先放到屏幕外 // // floatingView.post(() -> { // // 确保初始位置在屏幕右侧外部 // floatingView.setTranslationX(floatingView.getWidth()); // // // 第一阶段:从右到屏幕右侧边缘(缓慢进入) // ObjectAnimator animator1 = ObjectAnimator.ofFloat(floatingView, "translationX", // floatingView.getWidth(), 0f); // animator1.setDuration(1500); // 延长动画时间到1.5秒 // animator1.setInterpolator(new DecelerateInterpolator(2.0f)); // 更平缓的减速效果 // animator1.start(); // // // 第二阶段:延迟1秒后从当前位置向左滑出 // floatingView.postDelayed(() -> { // ObjectAnimator animator2 = ObjectAnimator.ofFloat(floatingView, "translationX", // 0f, -floatingView.getWidth()); // animator2.setDuration(1500); // 延长动画时间到1.5秒 // animator2.setInterpolator(new DecelerateInterpolator(2.0f)); // 更平缓的减速效果 // animator2.addListener(new AnimatorListenerAdapter() { // @Override // public void onAnimationEnd(Animator animation) { // // 动画结束后移除悬浮窗 // decorView.removeView(floatingView); // // // 标记播放结束并处理下一个消息 // synchronized (queueLock) { // isPlaying = false; // } // processNextMessage(); // } // }); // animator2.start(); // }, 3000); // 停留1秒 // }); // decorView.addView(floatingView); // } // 在类中添加新的成员变量 private View xlhFloatingView; // XLH类型的浮动视图 private boolean isXlhFloatingViewAdded = false; // 标记XLH浮动视图是否已添加到 decorView @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(XLHBean event) { showPiaoPingMessageXlh(event); } private void showPiaoPingMessageXlh(XLHBean event) { // 创建 FloatingX 配置 ViewGroup decorView = (ViewGroup) this.getWindow().getDecorView(); // 如果XLH浮动视图未创建,则创建一次 if (xlhFloatingView == null) { xlhFloatingView = LayoutInflater.from(this).inflate(R.layout.item_piaoping_xlh, null); // 设置布局参数 FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT ); layoutParams.topMargin = com.sunfusheng.marqueeview.DisplayUtil.dip2px(this, 100); layoutParams.gravity = android.view.Gravity.TOP | android.view.Gravity.CENTER_HORIZONTAL; xlhFloatingView.setLayoutParams(layoutParams); // 初始化动画监听器 setupXlhAnimationListener(xlhFloatingView, decorView); } // 更新视图数据 updateXlhFloatingViewData(event); // 如果浮动视图未添加到 decorView,则添加 if (!isXlhFloatingViewAdded) { decorView.addView(xlhFloatingView); isXlhFloatingViewAdded = true; } // 重置视图位置并开始动画 resetAndStartXlhAnimation(xlhFloatingView); } private void setupXlhAnimationListener(View floatingView, ViewGroup decorView) { // 为视图添加一个全局布局监听器,确保在视图完全加载后再设置动画 floatingView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // 移除监听器,避免重复调用 floatingView.getViewTreeObserver().removeOnGlobalLayoutListener(this); // 确保初始位置在屏幕右侧外部 floatingView.setTranslationX(floatingView.getWidth()); // 第一阶段:从右到屏幕右侧边缘(缓慢进入) ObjectAnimator animator1 = ObjectAnimator.ofFloat(floatingView, "translationX", floatingView.getWidth(), 0f); animator1.setDuration(1500); // 延长动画时间到1.5秒 animator1.setInterpolator(new DecelerateInterpolator(2.0f)); // 更平缓的减速效果 animator1.start(); // 第二阶段:延迟1秒后从当前位置向左滑出 floatingView.postDelayed(() -> { ObjectAnimator animator2 = ObjectAnimator.ofFloat(floatingView, "translationX", 0f, -floatingView.getWidth()); animator2.setDuration(1500); // 延长动画时间到1.5秒 animator2.setInterpolator(new DecelerateInterpolator(2.0f)); // 更平缓的减速效果 animator2.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // 动画结束后移除悬浮窗 if (isXlhFloatingViewAdded) { decorView.removeView(floatingView); isXlhFloatingViewAdded = false; } // 标记播放结束并处理下一个消息 synchronized (queueLock) { isPlaying = false; } processNextMessage(); } }); animator2.start(); }, 3000); // 停留1秒 } }); } private void resetAndStartXlhAnimation(View floatingView) { // 重置视图位置并开始动画 floatingView.setTranslationX(floatingView.getWidth()); // 第一阶段:从右到屏幕右侧边缘(缓慢进入) ObjectAnimator animator1 = ObjectAnimator.ofFloat(floatingView, "translationX", floatingView.getWidth(), 0f); animator1.setDuration(1500); animator1.setInterpolator(new DecelerateInterpolator(2.0f)); animator1.start(); // 第二阶段:延迟1秒后从当前位置向左滑出 floatingView.postDelayed(() -> { ObjectAnimator animator2 = ObjectAnimator.ofFloat(floatingView, "translationX", 0f, -floatingView.getWidth()); animator2.setDuration(1500); animator2.setInterpolator(new DecelerateInterpolator(2.0f)); animator2.start(); }, 3000); } private void updateXlhFloatingViewData(XLHBean xlhBean) { TextView textView = xlhFloatingView.findViewById(R.id.tv_name); ImageView xlh_image = xlhFloatingView.findViewById(R.id.im_xlh); if (xlhBean!=null){ xlh_image.setImageDrawable(xlhBean.getFrom_type() == 1 ? getResources().getDrawable(R.mipmap.xlh_jjks) : getResources().getDrawable(R.mipmap.xlh_zsks)); textView.setText(xlhBean.getText()); } else { textView.setText(""); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(ChatInfo event) { String id = event.getId().replace("g", ""); ARouter.getInstance().build(ARouteConstants.H5).withString("url", CommonAppContext.getInstance().getCurrentEnvironment().getH5Url() + "/web/index.html#/pages/union/setGroup?id=" + SpUtil.getToken() + "&guildId=" + id).navigation(); } }