Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/201.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 使用自定义流布局时,不会在所有设备上传播单击事件_Android_Android Layout - Fatal编程技术网

Android 使用自定义流布局时,不会在所有设备上传播单击事件

Android 使用自定义流布局时,不会在所有设备上传播单击事件,android,android-layout,Android,Android Layout,我使用自定义布局来显示不同数量的按钮并拦截它们的点击。以下是自定义布局的源代码: import android.content.Context; import android.content.res.TypedArray; import android.database.DataSetObserver; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; impo

我使用自定义布局来显示不同数量的按钮并拦截它们的点击。以下是自定义布局的源代码:

import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.AdapterView;

public class FlowLayout extends AdapterView<Adapter> {
    public static final int HORIZONTAL = 0;
    public static final int VERTICAL = 1;
    private static final int INVALID_INDEX = -1;
    private static final int TOUCH_STATE_RESTING = 0;
    private static final int TOUCH_STATE_CLICK = 1;
    private int mTouchState = TOUCH_STATE_RESTING;
    private Rect mRect;
    private Runnable mLongPressRunnable;
    private int mTouchStartX;
    private int mTouchStartY;
    private int horizontalSpacing = 0;
    private int verticalSpacing = 0;
    private int orientation = 0;
    private boolean debugDraw = false;
    private Adapter mAdapter;
    private final AdapterObserver mObserver = new AdapterObserver();

    public FlowLayout(Context context) {
        super(context);

        this.readStyleParameters(context, null);
    }

    public FlowLayout(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);

        this.readStyleParameters(context, attributeSet);
    }

    public FlowLayout(Context context, AttributeSet attributeSet, int defStyle) {
        super(context, attributeSet, defStyle);

        this.readStyleParameters(context, attributeSet);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft();
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft();

        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

        int size;
        int mode;

        if (orientation == HORIZONTAL) {
            size = sizeWidth;
            mode = modeWidth;
        } else {
            size = sizeHeight;
            mode = modeHeight;
        }

        int lineThicknessWithSpacing = 0;
        int lineThickness = 0;
        int lineLengthWithSpacing = 0;
        int lineLength;

        int prevLinePosition = 0;

        int controlMaxLength = 0;
        int controlMaxThickness = 0;

        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() == GONE) {
                continue;
            }

            child.measure(
                    MeasureSpec.makeMeasureSpec(sizeWidth, modeWidth == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : modeWidth),
                    MeasureSpec.makeMeasureSpec(sizeHeight, modeHeight == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : modeHeight)
            );

            LayoutParams lp = (LayoutParams) child.getLayoutParams();

            int hSpacing = this.getHorizontalSpacing(lp);
            int vSpacing = this.getVerticalSpacing(lp);

            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();

            int childLength;
            int childThickness;
            int spacingLength;
            int spacingThickness;

            if (orientation == HORIZONTAL) {
                childLength = childWidth;
                childThickness = childHeight;
                spacingLength = hSpacing;
                spacingThickness = vSpacing;
            } else {
                childLength = childHeight;
                childThickness = childWidth;
                spacingLength = vSpacing;
                spacingThickness = hSpacing;
            }

            lineLength = lineLengthWithSpacing + childLength;
            lineLengthWithSpacing = lineLength + spacingLength;

            boolean newLine = lp.newLine || (mode != MeasureSpec.UNSPECIFIED && lineLength > size);
            if (newLine) {
                prevLinePosition = prevLinePosition + lineThicknessWithSpacing;

                lineThickness = childThickness;
                lineLength = childLength;
                lineThicknessWithSpacing = childThickness + spacingThickness;
                lineLengthWithSpacing = lineLength + spacingLength;
            }

            lineThicknessWithSpacing = Math.max(lineThicknessWithSpacing, childThickness + spacingThickness);
            lineThickness = Math.max(lineThickness, childThickness);

            int posX;
            int posY;
            if (orientation == HORIZONTAL) {
                posX = getPaddingLeft() + lineLength - childLength;
                posY = getPaddingTop() + prevLinePosition;
            } else {
                posX = getPaddingLeft() + prevLinePosition;
                posY = getPaddingTop() + lineLength - childHeight;
            }
            lp.setPosition(posX, posY);

            controlMaxLength = Math.max(controlMaxLength, lineLength);
            controlMaxThickness = prevLinePosition + lineThickness;
        }

        if (orientation == HORIZONTAL) {
            this.setMeasuredDimension(resolveSize(controlMaxLength, widthMeasureSpec), resolveSize(controlMaxThickness, heightMeasureSpec));
        } else {
            this.setMeasuredDimension(resolveSize(controlMaxThickness, widthMeasureSpec), resolveSize(controlMaxLength, heightMeasureSpec));
        }
    }

    private int getVerticalSpacing(LayoutParams lp) {
        int vSpacing;
        if (lp.verticalSpacingSpecified()) {
            vSpacing = lp.verticalSpacing;
        } else {
            vSpacing = this.verticalSpacing;
        }
        return vSpacing;
    }

    private int getHorizontalSpacing(LayoutParams lp) {
        int hSpacing;
        if (lp.horizontalSpacingSpecified()) {
            hSpacing = lp.horizontalSpacing;
        } else {
            hSpacing = this.horizontalSpacing;
        }
        return hSpacing;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            LayoutParams lp = (LayoutParams) child.getLayoutParams();
            child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());
        }
    }

    @Override
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        boolean more = super.drawChild(canvas, child, drawingTime);
        this.drawDebugInfo(canvas, child);
        return more;
    }

    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
        return p instanceof LayoutParams;
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attributeSet) {
        return new LayoutParams(getContext(), attributeSet);
    }

    @Override
    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        return new LayoutParams(p);
    }

    private void readStyleParameters(Context context, AttributeSet attributeSet) {
        TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout);
        try {
            horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalSpacing, 0);
            verticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalSpacing, 0);
            orientation = a.getInteger(R.styleable.FlowLayout_orientation, HORIZONTAL);
            debugDraw = a.getBoolean(R.styleable.FlowLayout_debugDraw, false);
        } finally {
            a.recycle();
        }
    }

    private void drawDebugInfo(Canvas canvas, View child) {
        if (!debugDraw) {
            return;
        }

        Paint childPaint = this.createPaint(0xffffff00);
        Paint layoutPaint = this.createPaint(0xff00ff00);
        Paint newLinePaint = this.createPaint(0xffff0000);

        LayoutParams lp = (LayoutParams) child.getLayoutParams();

        if (lp.horizontalSpacing > 0) {
            float x = child.getRight();
            float y = child.getTop() + child.getHeight() / 2.0f;
            canvas.drawLine(x, y, x + lp.horizontalSpacing, y, childPaint);
            canvas.drawLine(x + lp.horizontalSpacing - 4.0f, y - 4.0f, x + lp.horizontalSpacing, y, childPaint);
            canvas.drawLine(x + lp.horizontalSpacing - 4.0f, y + 4.0f, x + lp.horizontalSpacing, y, childPaint);
        } else if (this.horizontalSpacing > 0) {
            float x = child.getRight();
            float y = child.getTop() + child.getHeight() / 2.0f;
            canvas.drawLine(x, y, x + this.horizontalSpacing, y, layoutPaint);
            canvas.drawLine(x + this.horizontalSpacing - 4.0f, y - 4.0f, x + this.horizontalSpacing, y, layoutPaint);
            canvas.drawLine(x + this.horizontalSpacing - 4.0f, y + 4.0f, x + this.horizontalSpacing, y, layoutPaint);
        }

        if (lp.verticalSpacing > 0) {
            float x = child.getLeft() + child.getWidth() / 2.0f;
            float y = child.getBottom();
            canvas.drawLine(x, y, x, y + lp.verticalSpacing, childPaint);
            canvas.drawLine(x - 4.0f, y + lp.verticalSpacing - 4.0f, x, y + lp.verticalSpacing, childPaint);
            canvas.drawLine(x + 4.0f, y + lp.verticalSpacing - 4.0f, x, y + lp.verticalSpacing, childPaint);
        } else if (this.verticalSpacing > 0) {
            float x = child.getLeft() + child.getWidth() / 2.0f;
            float y = child.getBottom();
            canvas.drawLine(x, y, x, y + this.verticalSpacing, layoutPaint);
            canvas.drawLine(x - 4.0f, y + this.verticalSpacing - 4.0f, x, y + this.verticalSpacing, layoutPaint);
            canvas.drawLine(x + 4.0f, y + this.verticalSpacing - 4.0f, x, y + this.verticalSpacing, layoutPaint);
        }

        if (lp.newLine) {
            if (orientation == HORIZONTAL) {
                float x = child.getLeft();
                float y = child.getTop() + child.getHeight() / 2.0f;
                canvas.drawLine(x, y - 6.0f, x, y + 6.0f, newLinePaint);
            } else {
                float x = child.getLeft() + child.getWidth() / 2.0f;
                float y = child.getTop();
                canvas.drawLine(x - 6.0f, y, x + 6.0f, y, newLinePaint);
            }
        }
    }

    private Paint createPaint(int color) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(color);
        paint.setStrokeWidth(2.0f);
        return paint;
    }

    public static class LayoutParams extends ViewGroup.LayoutParams {
        private static int NO_SPACING = -1;

        private int x;
        private int y;
        private int horizontalSpacing = NO_SPACING;
        private int verticalSpacing = NO_SPACING;
        private boolean newLine = false;

        public LayoutParams(Context context, AttributeSet attributeSet) {
            super(context, attributeSet);
            this.readStyleParameters(context, attributeSet);
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        public LayoutParams(ViewGroup.LayoutParams layoutParams) {
            super(layoutParams);
        }

        public boolean horizontalSpacingSpecified() {
            return horizontalSpacing != NO_SPACING;
        }

        public boolean verticalSpacingSpecified() {
            return verticalSpacing != NO_SPACING;
        }

        public void setHorizontalSpacing(int hs) {
            horizontalSpacing = hs;
        }

        public void setVerticalSpacing(int vs) {
            verticalSpacing = vs;
        }

        public void setPosition(int x, int y) {
            this.x = x;
            this.y = y;
        }

        private void readStyleParameters(Context context, AttributeSet attributeSet) {
            TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout_LayoutParams);
            try {
                horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_horizontalSpacing, NO_SPACING);
                verticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_verticalSpacing, NO_SPACING);
                newLine = a.getBoolean(R.styleable.FlowLayout_LayoutParams_layout_newLine, false);
            } finally {
                a.recycle();
            }
        }
    }

    @Override
    public Adapter getAdapter() {
        return mAdapter;
    }

    @Override
    public View getSelectedView() {
        throw new UnsupportedOperationException("Not supported");
    }

    @Override
    public void setAdapter(Adapter adapter) {
        if (mAdapter != null) {
            mAdapter.unregisterDataSetObserver(mObserver);
        }
        mAdapter = adapter;
        mAdapter.registerDataSetObserver(mObserver);

        refresh();
    }


    public void refresh() {
        removeAllViewsInLayout();        
        for (int i = 0; i < mAdapter.getCount(); i++) {
            final View view = mAdapter.getView(i, null, this);
            ViewGroup.LayoutParams params = view.getLayoutParams();
            if (params == null) {
                params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            }
            addViewInLayout(view, i, params, true);
        }
        postInvalidate();
        requestLayout();
    }

    public class AdapterObserver extends DataSetObserver {
        @Override
        public void onChanged() {
            refresh();
        }

        @Override
        public void onInvalidated() {
        }
    }

    @Override
    public void setSelection(int position) {
        throw new UnsupportedOperationException("Not supported");
    }

    // Touch detection
    @Override
    public boolean onTouchEvent(MotionEvent event) { 
        if (getChildCount() == 0) { 
            return false; 
        }

        switch (event.getAction()) { 
            case MotionEvent.ACTION_DOWN: 
                startTouch(event); 
                break; 

            case MotionEvent.ACTION_UP: 
                if (mTouchState == TOUCH_STATE_CLICK) { 
                    clickChildAt((int)event.getX(), (int)event.getY()); 
                } 
                endTouch(); 
                break; 

            default: 
                endTouch(); 
                break; 
        } 

        return true;
    }

    /**
     * Sets and initializes all things that need to when we start a touch
     * gesture.
     * 
     * @param event The down event
     */
    private void startTouch(final MotionEvent event) {
        mTouchStartX = (int)event.getX();
        mTouchStartY = (int)event.getY();
        startLongPressCheck();

        mTouchState = TOUCH_STATE_CLICK;
    }

    private void startLongPressCheck() {
        if (mLongPressRunnable == null) {
            mLongPressRunnable = new Runnable() {
                public void run() {
                    if (mTouchState == TOUCH_STATE_CLICK) {
                        final int index = getContainingChildIndex(mTouchStartX, mTouchStartY);
                        if (index != INVALID_INDEX) { longClickChild(index); mTouchState = TOUCH_STATE_RESTING; }
                    }
                }
            };
        }
        postDelayed(mLongPressRunnable, 300); //ViewConfiguration.getLongPressTimeout()
    }

    private void longClickChild(final int index) {
        final View itemView = getChildAt(index);
        final int position = index;
        final long id = mAdapter.getItemId(position);
        final OnItemLongClickListener listener = getOnItemLongClickListener();
        if (listener != null) { listener.onItemLongClick(this, itemView, position, id); }
    }

    private int getContainingChildIndex(final int x, final int y) {
        if (mRect == null) { mRect = new Rect(); }
        for (int index = 0; index < getChildCount(); index++) {
            getChildAt(index).getHitRect(mRect);
            if (mRect.contains(x, y)) { return index; }
        }
        return INVALID_INDEX;
    }

    private void endTouch() {
        removeCallbacks(mLongPressRunnable);
        mTouchState = TOUCH_STATE_RESTING;
    }

    private void clickChildAt(final int x, final int y) {
        final int index = getContainingChildIndex(x, y);
        if (index != INVALID_INDEX) {
            final View itemView = getChildAt(index);
            final int position = index;
            final long id = mAdapter.getItemId(position);
            performItemClick(itemView, position, id);
        }
    }
}
导入android.content.Context;
导入android.content.res.TypedArray;
导入android.database.DataSetObserver;
导入android.graphics.Canvas;
导入android.graphics.Paint;
导入android.graphics.Rect;
导入android.util.AttributeSet;
导入android.view.MotionEvent;
导入android.view.view;
导入android.view.ViewGroup;
导入android.widget.Adapter;
导入android.widget.AdapterView;
公共类FlowLayout扩展AdapterView{
公共静态最终int水平=0;
公共静态最终int垂直=1;
私有静态final int INVALID_INDEX=-1;
私有静态最终int触摸\状态\静止=0;
私有静态最终整数触摸\状态\点击=1;
private int mTouchState=触摸状态;
私人直肠;
私有可运行的mLongPressRunnable;
私有int mTouchStartX;
私家车;
私有int水平间距=0;
私有int垂直间距=0;
私有int方向=0;
私有布尔debugDraw=false;
专用适配器;
private final AdapterObserver mObserver=新AdapterObserver();
公共流程布局(上下文){
超级(上下文);
this.readStyleParameters(上下文,null);
}
公共流布局(上下文上下文,属性集属性集){
super(上下文、属性集);
readStyleParameters(上下文、属性集);
}
公共流布局(上下文上下文、属性集、属性集、int-defStyle){
super(上下文、属性集、定义样式);
readStyleParameters(上下文、属性集);
}
@凌驾
测量时的保护空隙(内部宽度测量等级、内部高度测量等级){
int-sizeWidth=MeasureSpec.getSize(widthmasurespec)-this.getPaddingRight()-this.getPaddingLeft();
int-sizeHeight=MeasureSpec.getSize(heightMeasureSpec)-this.getPaddingRight()-this.getPaddingLeft();
int modeWidth=MeasureSpec.getMode(widthmasurespec);
int modeHeight=MeasureSpec.getMode(heightMeasureSpec);
整数大小;
int模式;
如果(方向=水平){
尺寸=尺寸宽度;
模式=模式宽度;
}否则{
尺寸=尺寸高度;
模式=模式高度;
}
int linethicknesswithspace=0;
int lineThickness=0;
int LinethLengthWithSpacing=0;
int行长度;
int-prevLinePosition=0;
int controlMaxLength=0;
int controlMaxThickness=0;
最终整数计数=getChildCount();
for(int i=0;isize);
如果(换行){
prevLinePosition=prevLinePosition+带空格的线条厚度;
lineThickness=childThickness;
lineLength=childLength;
线宽与间距=子厚度+间距厚度;
线条纵向间距=线条长度+间距长度;
}
linethicknesswithspace=Math.max(linethicknesswithspace,childThickness+spachingthickness);
lineThickness=数学最大值(lineThickness,childThickness);
int-posX;
int-posY;
如果(方向=水平){
posX=getPaddingLeft()+lineLength-childLength;
posY=getPaddingTop()+prevLinePosition;
}否则{
posX=getPaddingLeft()+prevLinePosition;
posY=getPaddingTop()+线宽-儿童身高;
}
lp.设置位置(posX、posY);
controlMaxLength=Math.max(controlMaxLength,lineLength);
controlMaxThickness=prevLinePosition+lineThickness;
}
如果(方向=水平){
此.setMeasuredDimension(resolveSize(controlMaxLength,widthMeasureSpec),resolveSize(controlMaxThickness,heightMeasureSpec));
}否则{
此.setMeasuredDimension(resolveSize(controlMaxThickness,widthMeasureSpec)、resolveSize(controlMaxLength,heightMeasureSpec));
}
}
私有int getVerticalSpacing(LayoutParams lp){
间隔间隔;
if(lp.verticalSpacingSpecified()){
垂直间距=垂直间距;
}否则{
心室起搏
View.setEnabled(true);
@Override
public boolean onTouchEvent(MotionEvent event) { 
    if (getChildCount() == 0) { 
        return super.onTouchEvent(event); 
    }

    boolean handled = false;

    switch (event.getAction()) { 
        case MotionEvent.ACTION_DOWN: 
            startTouch(event); 
            handled = true;
            break;

        case MotionEvent.ACTION_UP: 
            if (mTouchState == TOUCH_STATE_CLICK) { 
                clickChildAt((int)event.getX(), (int)event.getY());
                handled = true;
            } 
            endTouch();
        break; 

        default: 
            // Do not do anything dramatic here because the system
            // may send different (eg. motion) information here which
            // may lead to you losing valid clicks if you simply cancel
            // the click in process.
        break;
    } 

if (handled == false) handled = super.onTouchEvent(event);

return handled;
}