WheelView icon indicating copy to clipboard operation
WheelView copied to clipboard

handle sticky mode

Open shayanpourvatan opened this issue 8 years ago • 7 comments

I've created following class to handle sticky mode for wheelView.

use this if you need sticky mode for your wheelView.

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.MotionEvent;

import com.lukedeighton.wheelview.WheelView;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by shayan on 10/20/17.
 */
public class StickyWheelView extends WheelView implements WheelView.OnWheelAngleChangeListener {


    Timer timer;
    TimerTask timerTask;

    boolean handleSticky;
    Handler uiHandler;

    OnWheelAngleChangeListener onWheelAngleChangeListener;

    public StickyWheelView(Context context) {
        super(context);
        init();
    }


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

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

    private void init() {
        super.setOnWheelAngleChangeListener(this);
        uiHandler = new Handler(Looper.getMainLooper());
    }

    @Override
    public void setOnWheelAngleChangeListener(OnWheelAngleChangeListener listener) {
        this.onWheelAngleChangeListener = listener;
    }

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent event) {

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            handleSticky = false;
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            handleSticky = true;
            onWheelAngleChange(getAngle());
        }

        return super.onTouchEvent(event);
    }

    @Override
    public void onWheelAngleChange(float angle) {
        timer = invalidateTimerAndCreateNew(timer, timerTask);
        timerTask = new TimerTask() {
            @Override
            public void run() {
                goToNearestFixItem();
            }
        };

        timer.schedule(timerTask, 100);

        // call listener if is not null
        if (onWheelAngleChangeListener != null) {
            onWheelAngleChangeListener.onWheelAngleChange(angle);
        }
    }

    private void goToNearestFixItem() {


        if (!handleSticky) {
            return;
        }
        // getAngle is wide range, we map it too 0 - 360
        float correctAngle = Math.abs(getAngle()) % 360;

        // each item angle
        float itemAngle = 360 / getWheelItemCount();

        // item is currently sticky.
        if (correctAngle % itemAngle == 0) {
            return;
        }

        int power = Math.abs((int) (getAngle() / 360));

        float nextAngle = ((int) (correctAngle / itemAngle) + 1) * itemAngle + (360 * power);
        float preAngle = ((int) (correctAngle / itemAngle)) * itemAngle + (360 * power);
        int sign = getAngle() < 0 ? -1 : 1;


        if (correctAngle % itemAngle > itemAngle / 2) {
            goToAngleWithAnimation(nextAngle * sign);
        } else {
            goToAngleWithAnimation(preAngle * sign);
        }
    }

    private float temporaryFinalAngel;

    private void goToAngleWithAnimation(float angle) {
        temporaryFinalAngel = angle;

        final boolean increase;
        increase = getAngle() <= angle;

        uiHandler.post(new Runnable() {
            @Override
            public void run() {

                if (temporaryFinalAngel == getAngle()) {
                    return;
                }

                // user changed angle again, don't set angle again
                if (!handleSticky) {
                    return;
                }

                float nextAngle;
                if (increase) {
                    nextAngle = Math.min(getAngle() + 3, temporaryFinalAngel);
                } else {
                    nextAngle = Math.max(getAngle() - 3, temporaryFinalAngel);
                }

                setAngle(nextAngle);
                uiHandler.postDelayed(this, 10);
            }
        });
    }


    private Timer invalidateTimerAndCreateNew(Timer timer, TimerTask timerTask) {
        if (timer != null) {
            timer.cancel();
            timer.purge();
        }


        if (timerTask != null) {
            timerTask.cancel();
        }

        timer = new Timer();
        return timer;
    }
}

for use this class add StickyWheelView instead of WheelView in your xml or java code

shayanpourvatan avatar Oct 22 '17 05:10 shayanpourvatan

I know this is kind of a late time, but were you able to test this with an odd number of items? I found a bug where it doesn't sticks properly with in this case

jinchuika avatar Sep 09 '19 23:09 jinchuika

@shayanpourvatan For which purpose it is used and how to use this component? Can you please share some more info about StickyWheelView.

prem-p-simform avatar Mar 02 '21 09:03 prem-p-simform

@jinchuika Sorry for the late answer: I don't remind this class actually, in one project we need to show one item as sticky, the project started in the hackathon and I write this code, actually, I don't test it in the real application with the dynamic case,

@prem-p-simform For using this class you need to replace it with default wheelView, in XML or Java class, everywhere you have wheelView, simply replace it with this class, but as Jinchuika mentioned, this class might have some issue in the odd number of the items.

I can spend some time fixing it for odd number items, if it's an emergency to you tell me, I will fix issues.

shayanpourvatan avatar Mar 03 '21 07:03 shayanpourvatan

@shayanpourvatan I have requirement of sticky item, For example sticky headers. I want to stick item at start of the list.

prem-p-simform avatar Mar 03 '21 07:03 prem-p-simform

@prem-p-simform I think you need to search for other libraries, this library as shown on the start page, used for wheel items, I think you need a recyclerView sticky header.

shayanpourvatan avatar Mar 03 '21 07:03 shayanpourvatan

I searched for that, Could not find RecyclerView LayoutManager which satisfy my needs. I need half cirlce layout and it should start from bottom and end in right side. Also item at bottom can be sticky, other can be scrolled.

prem-p-simform avatar Mar 03 '21 07:03 prem-p-simform

@prem-p-simform This library is not what you want, I think you must write it by your self or do some hacky way ( I don't have an idea right now )

shayanpourvatan avatar Mar 03 '21 13:03 shayanpourvatan