在Java的MultiTouchListener中避免点击重复添加View以消除闪烁
修复点击View重复添加导致的卡顿/闪烁问题
问题根源
每次点击View时,都会重复执行以下冗余操作:
- 重新inflate并添加
view2到frameLayout,导致布局中堆积大量重复弹窗视图 - 重复设置
frmBorder的背景资源,触发不必要的视图重绘
这些重复操作会引发频繁的布局计算和绘制流程,最终导致界面卡顿或闪烁。
修复方案
1. 提前初始化弹窗视图(避免重复创建)
将view2及其中的控件作为Activity成员变量,在初始化阶段(如onCreate)仅创建一次,不再每次点击都重新inflate。
// Activity成员变量声明 private View view2; private TextView imgPhotoEditorEdit; private TextView imgPhotoEditorClose; private FrameLayout frameLayout;
// 在Activity的onCreate方法中初始化(仅执行一次) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_activity_layout); frameLayout = findViewById(R.id.frameLayout); // 初始化弹窗视图,添加到布局后默认隐藏 view2 = LayoutInflater.from(this).inflate(R.layout.pop_up_text, frameLayout, false); imgPhotoEditorEdit = view2.findViewById(R.id.imgPhotoEditorEdit); imgPhotoEditorClose = view2.findViewById(R.id.imgPhotoEditorClose); view2.setElevation(20); frameLayout.addView(view2); view2.setVisibility(View.GONE); // 给关闭按钮添加隐藏逻辑 imgPhotoEditorClose.setOnClickListener(v -> view2.setVisibility(View.GONE)); }
2. 修改点击事件逻辑(避免重复操作)
在点击回调中,仅做显示/隐藏弹窗、更新弹窗位置和按需设置边框的操作,移除重复创建和添加视图的代码。
multiTouchListener = getMultiTouchListener(); multiTouchListener.setOnGestureControl(new MultiTouchListener.OnGestureControl() { @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override public void onClick() { // 隐藏其他布局 if (filter_layout.getVisibility() == View.VISIBLE) filter_layout.setVisibility(View.GONE); if (sticker_layout.getVisibility() == View.VISIBLE) sticker_layout.setVisibility(View.GONE); text_layout.setVisibility(View.VISIBLE); new Handler().postDelayed(new Runnable() { @Override public void run() { // 仅当边框未设置时才更新,避免重复触发重绘 Drawable targetBorder = getResources().getDrawable(R.drawable.rounded_border_tv); if (frmBorder.getBackground() == null || !frmBorder.getBackground().getConstantState().equals(targetBorder.getConstantState())) { frmBorder.setBackgroundResource(R.drawable.rounded_border_tv); } // 显示弹窗并更新位置 view2.setVisibility(View.VISIBLE); Rect rectf = new Rect(); selected_View.getGlobalVisibleRect(rectf); View rootLayout = selected_View.getRootView().findViewById(R.id.frameLayout); int[] viewLocation = new int[2]; selected_View.getLocationInWindow(viewLocation); int[] rootLocation = new int[2]; rootLayout.getLocationInWindow(rootLocation); // 计算弹窗相对于父布局的位置 int relativeLeft = viewLocation[0] - rootLocation[0]; int relativeTop = viewLocation[1] - rootLocation[1]; // 调整弹窗位置(可根据需求自定义) view2.setX(relativeLeft + rectf.width()); view2.setY(relativeTop); } }, 100); } });
额外优化建议
- 如果支持切换选中多个View,可记录当前选中的View,仅对新选中的View设置边框,同时隐藏弹窗后重新显示到新位置
- 移除不必要的日志输出,减少性能消耗
内容的提问来源于stack exchange,提问作者Roushan Mehmood
相关产品推荐
相关产品推荐

