半透明视图覆盖下如何保持ListView可滚动?
解决Fragment中半透明遮罩下ListView滚动卡顿的问题
嘿,我猜你这问题大概率是遮罩层抢了ListView的触摸事件,导致滚动时事件传递卡壳,所以滚动效果才这么差~下面给你几个实用的解决方案,一步步来搞定:
方案一:让遮罩层“放行”触摸事件(最简单直接)
你可以自定义一个半透明View当遮罩,重写它的触摸事件方法,让它把事件乖乖传给下面的ListView:
public class TransparentMaskView extends View { public TransparentMaskView(Context context) { super(context); init(); } public TransparentMaskView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { // 设置半透明背景,比如50%透明度的黑色,你可以改成自己要的颜色 setBackgroundColor(Color.parseColor("#80000000")); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // 不拦截触摸事件,让事件继续往下传给ListView return false; } @Override public boolean onTouchEvent(MotionEvent event) { // 不消费事件,直接交给下层处理 return false; } }
然后修改你的布局,把这个遮罩View放在ListView的后面(RelativeLayout里后写的View会在上层显示):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/green"> <ListView android:id="@+id/list" android:layout_width="match_parent" android:layout_height="match_parent"/> <!-- 半透明遮罩层,放在ListView之后 --> <com.yourpackage.TransparentMaskView android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout>
这样遮罩会正常显示在ListView上面,但触摸事件会直接落到ListView上,滚动自然就顺畅了。
方案二:用FrameLayout嵌套,靠属性搞定(不用写Java代码)
如果不想自定义View,直接用FrameLayout嵌套,给遮罩层加两个属性,让它不抢事件:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/green"/> <!-- 半透明遮罩,设置这两个属性就不会拦截事件了 --> <View android:layout_width="match_parent" android:layout_height="match_parent" android:background="#80000000" android:clickable="false" android:focusable="false"/> </FrameLayout>
原理很简单:默认情况下,View如果是可点击或可获取焦点的,会拦截触摸事件;把这两个属性设为false,事件就会自动往下传给ListView了。
方案三:如果遮罩层需要部分区域响应点击(可选)
要是你的遮罩层某些地方需要点,其他地方要让ListView滚动,那可以在自定义遮罩View里判断触摸位置,只在特定区域消费事件:
@Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); // 比如遮罩顶部200dp的区域要响应点击,其他地方放行 int clickAreaHeight = dp2px(getContext(), 200); if (y < clickAreaHeight) { // 这里写你的点击逻辑 return true; // 消费这个事件,不让它传给ListView } else { // 其他区域不消费,让事件继续传给ListView return false; } } // 工具方法:dp转px private int dp2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); }
这样就能同时满足遮罩的交互需求和ListView的滚动需求啦~
内容的提问来源于stack exchange,提问作者E I
相关产品推荐
相关产品推荐

