有 2 层时,FrameLayout 无法正确处理触摸请求

FrameLayout doesn't handle touch request correct when having 2 layers

我正在尝试扩展 FrameLayout 以便能够决定为哪个视图传递触摸事件:

我的App是这样的:

点在水平滚动视图中,矩形只是一个视图。 当您触摸点区域时,它会滚动。我希望矩形可以拖动。 我一次可以做一个(我的意思是 - 如果框架只有一个 child)。但不是两者。 我想我需要重写:onInterceptTouchEvent 但没有设法将事件传递给矩形视图。这是我的代码: activity_main.xml:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/LinearLayout1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <com.example.trashproject.FrameWithTouchControl
            android:id="@+id/frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <View
                android:id="@+id/selector"
                android:layout_width="45dp"
                android:layout_height="match_parent"
                android:background="#33FF0000" >
            </View>

             <HorizontalScrollView
            android:id="@+id/horizontalScroll"
            android:layout_width="wrap_content"
            android:layout_height="match_parent" >

            <TableLayout
                android:id="@+id/table"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:orientation="horizontal" >
            </TableLayout>
        </HorizontalScrollView>

        </com.example.trashproject.FrameWithTouchControl>
    </LinearLayout>

FrameWithTouchControl.java:

package com.example.trashproject;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.FrameLayout;

public class FrameWithTouchControl extends FrameLayout {

    private static final String TAG ="FrameWithTouchControl" ;
    private float curSelectorPositionX1;
    private float curSelectorPositionX2;
    private boolean isDragging = false;
    private View mSelector;
    private int mTouchSlop;

    public FrameWithTouchControl(Context context) {
        super(context);
        init();

    }


    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        initViewMembers();
    }


    public FrameWithTouchControl(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }


    public FrameWithTouchControl(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        init();
    }


    private void initViewMembers() {
        mSelector = this.findViewById(R.id.selector);

    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        // Always handle the case of the touch gesture being complete.
        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
            // Release the scroll.
            isDragging = false;
            return false; // Do not intercept touch event, let the child handle it
        }
        curSelectorPositionX1 = mSelector.getLeft();
        curSelectorPositionX2 = mSelector.getRight();
        float evX = ev.getX();
        //if the touch is out of the selector's area
        if (evX >= curSelectorPositionX2 || evX <= curSelectorPositionX1) {
            return false;
        }

        switch (action) {
        case MotionEvent.ACTION_MOVE:
            if (isDragging) {
                // We're currently dragging, so yes, intercept the 
                // touch event!
                mSelector.onTouchEvent(ev);
                return true;
            }

            mSelector.onTouchEvent(ev);
            return true;



        }//switch
        return false;
    }//onIntercept
}

MainActivity.java:

package com.example.trashproject;

import java.util.Calendar;
import java.util.Random;

import android.content.ClipData;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnDragListener;
import android.view.View.OnTouchListener;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TableRow.LayoutParams;
import android.widget.TextView;
public class MainActivity extends FragmentActivity{


    private static final int ROWS =8;
    private static final int COLS = 100;
    private static final String TAG = "MainActivity";
    private TableLayout mTable;
    private TextView[][] mCircles;
    private boolean[][] mData;
    private LayoutInflater mInflater;
    private FrameLayout mFrame;
    private View mSelector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mData = generateFakeGuestsTimes();
        mInflater =(LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        makeTable();
        mFrame = (FrameLayout) findViewById(R.id.frame);

        mSelector = findViewById(R.id.selector);
        mSelector.setOnTouchListener(new OnTouchListener() {

            boolean isDragging;
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.d(TAG, "selector touch triggered" );
                Log.d(TAG, event.toString());
                int action = event.getAction();
                float deltaX = 0;
                if (action==MotionEvent.ACTION_DOWN && !isDragging) {
                    isDragging = true;
                    deltaX = event.getX();
                    return true;
                } else if (isDragging) {
                    if (action== MotionEvent.ACTION_MOVE) {
                        v.setX(v.getX() + event.getX() - deltaX);
                    } else if (action == MotionEvent.ACTION_CANCEL) {
                        isDragging = false;
                        return true;
                    } else if (action == MotionEvent.ACTION_UP) {
                        isDragging = false;
                        return false;
                    }
                }
                return false;
            }
        });


    }
/**** NOT RELEVANT FROM HERE *******/
    private boolean[][] generateFakeGuestsTimes() {
        boolean[][] values = new boolean[ROWS][COLS];
        Random rand = new Random();
        for (int i = 0; i < ROWS; i++) {
            for (int j = 0; j < COLS    ; j++) {
                values[i][j] = rand.nextBoolean();
            }
        }
        return values;

    }
    public void onClick(View view) {
        Log.d(TAG, "numOfChildren" + mTable.getChildCount());
    }


    private void makeTable() {
        mTable = (TableLayout) findViewById(R.id.table);

        TableRow.LayoutParams rowParams = new TableRow.LayoutParams();
        rowParams.width = LayoutParams.WRAP_CONTENT;
        rowParams.height = 67;
        mCircles = new TextView[ROWS][COLS];
        final TableRow[] row = new TableRow[ROWS];
        final TextView[] headerText = new TextView[ROWS];
        long start = cal.getTimeInMillis();
        for (int i = 0; i < ROWS; i++) {
            row[i] = new TableRow(this);
            row[i].setLayoutParams(rowParams);
            for (int j = 0; j < COLS; j++) {
                mCircles[i][j] = (TextView) mInflater.inflate(R.layout.calendar_month_grid, null);
                if (mData[i][j]) {
                    mCircles[i][j].setBackgroundResource(R.drawable.small_circle);
                } else {                    
                    mCircles[i][j].setBackgroundResource(R.drawable.small_circle_red);
                }
                row[i].addView(mCircles[i][j]);
            }
            mTable.addView(row[i]);
        }//outer loop

        long end = cal.getTimeInMillis();
        Log.d(TAG, "time of operation=" + end + ", " + start + ", " + String.valueOf(end - start));
    }

我通过在 FrameLayout 中切换顺序解决了这个问题。 显然,框架布局以相反的顺序设置图层。即:

<FrameLAyout>
   <View1/>
   <View2/>
</FrameLAyout>

View2会在上层。 View2 将首先获取触摸回调,如果未处理触摸,View1 将进行调用。 IE。这与绘图相同。底层是View1,上层是View2。有道理