1

I'm trying to build a view that works like the calendar agenda view (a vertical list of hours that user can select by dragging) but I'm stuck at the part where user begins to start pressing on the screen and dragging his finger over the hour rows to select them. How can I make am overlay representing the selection over the views that represents the hours and expand/shrink it as user drags the selection?

My current interface is composed of a vertical oriented LinearLayout that contains empty TextViews as placeholders that represents the hours of the day.

This is how my screen looks like:

enter image description here

Each green column is the LinearLayout with the TextViews representing the slots. I want to allow the user to start pressing on one of the slots and dragging down to make the selection and while the dragging is in progress to have an overlay that shrinks/expands to reflect the selection.

AlexL
  • 1,699
  • 12
  • 20
  • I'm not looking for a picker. I'm after a drag to select interface. Similar to Google's calendar view when viewing a week. – AlexL Apr 08 '15 at 22:25
  • It would be more understandable if you post some code or screenshots – Sai Phani Apr 08 '15 at 22:28
  • http://stackoverflow.com/questions/6858162/custom-calendar-dayview-in-android – Sai Phani Apr 08 '15 at 22:32
  • https://github.com/alamkanak/Android-Week-View – Sai Phani Apr 08 '15 at 22:35
  • @SaiPhani looks like this is what i'm after thanks. At least it will look better then mine :) – AlexL Apr 08 '15 at 22:36
  • You are welcome... Edit in question so that it will help others – Sai Phani Apr 08 '15 at 22:37
  • After checking the sample app for that library it doesn't allow the user to drag and select the time in the calendar to create an event. At best it can add events for single hours from user's interaction. So the original question still stands. – AlexL Apr 09 '15 at 00:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/74770/discussion-between-sai-phani-and-alexl). – Sai Phani Apr 09 '15 at 00:20
  • Actually i've manage to do it my way. I've extended the `LinearLayout` and hooked into the drawing mechanism to draw my overlay selection on touch events. – AlexL Apr 09 '15 at 21:24

1 Answers1

1

I've managed to solve it by extending the LinearLayout and hooking into the drawing mechanism like this:

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();
    }
}
AlexL
  • 1,699
  • 12
  • 20