拖动视图时的选择叠加

时间:2015-04-08 22:20:02

标签: android android-layout

我正在尝试构建一个类似于日历议程视图的视图(用户可以通过拖动选择的垂直时间列表)但是我被困在用户开始按下的部分屏幕并在小时行上拖动他的手指以选择它们。如何在表示小时的视图上进行覆盖表示选择,并在用户拖动选择时展开/缩小它?

我当前的界面由垂直导向的LinearLayout组成,其中包含空TextViews作为占位符,表示当天的小时数。

这就是我的屏幕的样子:

enter image description here

每个绿色列都是LinearLayoutTextViews代表广告位。我想允许用户开始按下其中一个插槽并向下拖动以进行选择,同时拖动正在进行,以使缩放缩小/扩展以反映选择。

1 个答案:

答案 0 :(得分:1)

我设法通过扩展LinearLayout并挂钩到这样的绘图机制来解决它:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

public class AvailabilityCalendarColumnLayout extends LinearLayout{

    private Drawable overlay;

    public AvailabilityCalendarColumnLayout(Context context) {
        super(context);
        setWillNotDraw(false);
    }

    public AvailabilityCalendarColumnLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        setWillNotDraw(false);
    }

    public AvailabilityCalendarColumnLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setWillNotDraw(false);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if(overlay != null) {
            overlay.draw(canvas);
        }
    }

    public boolean startSelectionOverlay(View startingView) {
        if(startingView == null) {
            return false;
        }
        overlay = getResources().getDrawable(R.drawable.overlay);
        float[] l = new float[2];
        l[0] = startingView.getX();
        l[1] = startingView.getY();
        int w = startingView.getWidth();
        int h = startingView.getHeight();
        overlay.setBounds((int) l[0], (int) l[1], (int) l[0] + w, (int) l[1] + h);
        invalidate();
        return true;
    }

    private void extendSelectionOverlay(View endView) {
        if(endView == null) {
            return;
        }
        float[] l = new float[2];
        l[0] = endView.getX();
        l[1] = endView.getY();
        int w = endView.getWidth();
        int h = endView.getHeight();

        Rect r = overlay.getBounds();
        r.bottom = (int)l[1] + h;
        overlay.setBounds(r);
        invalidate();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        final int action = MotionEventCompat.getActionMasked(ev);
        float[] pos = new float[2];
        pos[0] = ev.getX();
        pos[1] = ev.getY();

        if(action == MotionEvent.ACTION_DOWN && overlay == null) {
            View view = getChildViewUnderPosition(pos);
            if(view != null) {
                startSelectionOverlay(view);
            }
        }

        if(action == MotionEvent.ACTION_MOVE && overlay != null) {
            View view = getChildViewUnderPosition(pos);
            extendSelectionOverlay(view);
        }

        if(action == MotionEvent.ACTION_UP && overlay != null) {
            endSelectionOverlay();
            invalidate();
        }
        return true;
    }

    private View getChildViewUnderPosition(float[] pos) {
        int num = getChildCount();
        View v;
        for(int x = 0; x < num; x++) {
            v = getChildAt(x);
            if(v.getX() <= pos[0] && (v.getX() + v.getWidth()) >= pos[0] && v.getY() <= pos[1] && (v.getY() + v.getHeight()) >= pos[1] && !v.isSelected()) {
                return v;
            }
        }

        return null;
    }

    private void endSelectionOverlay() {
        overlay = null;
        invalidate();
    }
}