简体   繁体   中英

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

I'm trying to extend FrameLayout to be capable to decide for which view to pass the touch event:

myApp is like this: 在此处输入图片说明

The dots are in horizontal scrollview, and the rectangle is just a view. When you touch the dots area it's scrolls. I would like the rectangle to be draggable. I can do that one at a time(I mean - if the frame has only one child). but not both. I've figured I need to override: onInterceptTouchEvent but didn't manage to pass the event to the rectange View. here is my code: 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));
    }

I resolved the issue by switching the order inside the FrameLayout. apparently the framelayout set the layers in opposite order. ie:

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

View2 will be on the upper layer. View2 will first gets the touch callbacks, if it is not handling the touch, View1 will get a call. Ie It is the same as drawing. the bottom layer is View1, the upper is View2. make sense

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM