NumberPicker showing wrong value after setValue()

岁酱吖の 提交于 2019-12-20 03:14:15

问题


I was trying to create a NumberPicker that would meet my needs, but I stumbled upon something and I don't understand what it is.

The behavior is simple, I have three number pickers and each one of them can have a value from -15 to 15; when the user presses the Ok button the values selected, if valid, are saved in a "structure" and in a SharedPreferences for convenience.

The problem is shown in this screenshot.

When I save a number that is not -1 it works without problems. If I save a -1 the result is the one above (it happens in every number picker).
Even though is displayed a -15 the actual value that is stored is -1: above and below the -15 the values are correct, if I slide one pixel the value turns -1, in the OnClick the value that is parsed is -1 and the value returned by

value < 0 ? value + maxValue + 1 : value - 1

in setPickers() is correct (29, the last index of the array).

I tried to move the various initialization in different parts of the code and I made it run on three devices; two physical (with Android 5.0.2 and 5.1.1) and one emulated with Android Studio (using a KitKat image) and the problem is always showing.
Now I'm starting to think that either I'm missing something really basic or the exact opposite.

Thanks for any help you can provide.

The .java:

public class CoefficientsDialog extends DialogFragment {

    private Activity activity;
    private MyView myView;
    private AlertDialog alertDialog;
    private AlertDialog.Builder builder;
    private NumberPicker startPicker, endPicker, stepPicker;

    final private String C     = "C_Coefficient";
    final private String Gamma = "Gamma_Coefficient";

    private String cStartKey;
    private String cEndKey;
    private String cStepKey;
    private String gStartKey;
    private String gEndKey;
    private String gStepKey;

    String[] defaultValues = new String[]{
            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
            "12", "13", "14", "15", "-15", "-14", "-13", "-12", "-11",
            "-10", "-9", "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1"
    };

    final int minValue = 0;
    final int maxValue = defaultValues.length - 1;

    private SharedPreferences settings;

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final String tag = getTag();


        cStartKey   = getString(R.string.c_start_key);
        cEndKey     = getString(R.string.c_end_key);
        cStepKey    = getString(R.string.c_step_key);
        gStartKey   = getString(R.string.g_start_key);
        gEndKey     = getString(R.string.g_end_key);
        gStepKey    = getString(R.string.g_step_key);

        activity    = getActivity();
        settings    = PreferenceManager.getDefaultSharedPreferences(activity);
        builder     = new AlertDialog.Builder(activity);
        myView      = new MyView(activity);

        setPickers();

        switch (tag) {
            case (C):
                String cTitle = "C coefficient range";
                init(cTitle, tag);
                break;
            case (Gamma):
                String gTitle = "Gamma coefficient range";
                init(gTitle, tag);
                break;
            default:
                dismiss();
                break;
        }

        return alertDialog;
    }

    private void init(String title, final String tag) {
        builder
                .setView(myView)
                .setTitle(title)
                .setPositiveButton("Ok", null)
                .setNegativeButton("Back", null);

        alertDialog = builder.create();

        alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(final DialogInterface dialog) {

                Button button = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);

                button.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        int start   = startPicker.getValue();
                        int end     = endPicker.getValue();
                        int step    = stepPicker.getValue();
                        int middle  = defaultValues.length / 2;

                        // The index is different from the actual value, method valid only if the
                        // array is antisymmetric
                        start = start <= middle ? start + 1 : start - maxValue - 1;
                        end   = end   <= middle ? end   + 1 : end   - maxValue - 1;
                        step  = step  <= middle ? step  + 1 : step  - maxValue - 1;

                        // If true, the user is trying to go from a positive value to a negative
                        // value with a positive step or vice versa
                        if ((end - start) / step < 0)
                            Toast.makeText(activity, R.string.wrong_direction, Toast.LENGTH_SHORT)
                                    .show();
                            // If true, start + (n * step) isn't equal to end given any value of n
                        else if ((end - start) % step != 0)
                            Toast.makeText(activity, R.string.step_inadequate, Toast.LENGTH_SHORT)
                                    .show();
                        else if (end == start)
                            Toast.makeText(activity, R.string.one_value_validation,
                                    Toast.LENGTH_SHORT)
                                    .show();
                        else {
                            savePreferences(tag, start, end, step);
                            alertDialog.dismiss();
                        }
                    }
                });
            }
        });
    }

    private void savePreferences(final String tag, int start, int end, int step) {

        SharedPreferences.Editor editor = settings.edit();

        switch (tag) {
            case (C): {
                ModelingStructure.cStart = start;
                ModelingStructure.cEnd   = end;
                ModelingStructure.cStep  = step;

                editor.putInt(cStartKey, start);
                editor.putInt(cEndKey, end);
                editor.putInt(cStepKey, step);
                editor.apply();
                break;
            }
            case (Gamma): {
                ModelingStructure.gStart = start;
                ModelingStructure.gEnd   = end;
                ModelingStructure.gStep  = step;

                editor.putInt(gStartKey, start);
                editor.putInt(gEndKey, end);
                editor.putInt(gStepKey, step);
                editor.apply();
                break;
            }
        }
    }

    private void setPickers() {
        // Initialize startPicker
        startPicker = (NumberPicker) myView.findViewById(R.id.cStartPicker);
        startPicker.setMaxValue(maxValue);
        startPicker.setMinValue(minValue);
        startPicker.setDisplayedValues(defaultValues);

        // Initialize endPicker
        endPicker = (NumberPicker) myView.findViewById(R.id.cEndPicker);
        endPicker.setMinValue(minValue);
        endPicker.setMaxValue(maxValue);
        endPicker.setDisplayedValues(defaultValues);

        // Initialize stepPicker
        stepPicker = (NumberPicker) myView.findViewById(R.id.cStepPicker);
        stepPicker.setMinValue(minValue);
        stepPicker.setMaxValue(maxValue);
        stepPicker.setDisplayedValues(defaultValues);

        // Check if the pickers were previously changed
        int start = settings.getInt(cStartKey, 1);
        int end   = settings.getInt(cEndKey, 1);
        int step  = settings.getInt(cStepKey, 1);

        // The index is different from the actual value
        startPicker.setValue(start < 0 ? start + maxValue + 1 : start - 1);
        endPicker.setValue  (end   < 0 ? end   + maxValue + 1 : end   - 1);
        stepPicker.setValue (step  < 0 ? step  + maxValue + 1 : step  - 1);
    }

    public void showDialog() {
        alertDialog.show();
    }
[...]
}

The .xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/c_start"
        android:id="@+id/cStartView"
        android:layout_alignStart="@+id/cStartPicker"
        android:layout_alignEnd="@+id/cStartPicker"
        android:gravity="center_horizontal" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/c_end"
        android:id="@+id/cEndView"
        android:layout_alignStart="@+id/cEndPicker"
        android:layout_alignEnd="@+id/cEndPicker"
        android:gravity="center_horizontal" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/c_step"
        android:id="@+id/cStepView"
        android:gravity="center_horizontal"
        android:layout_alignStart="@+id/cStepPicker"
        android:layout_alignEnd="@+id/cStepPicker" />


    <NumberPicker
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/cEndPicker"
        android:layout_centerInParent="true" />

    <NumberPicker
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/cStartPicker"
        android:layout_centerInParent="true"
        android:layout_toStartOf="@id/cEndPicker"
        android:layout_marginEnd="10dp" />

    <NumberPicker
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/cStepPicker"
        android:layout_centerInParent="true"
        android:layout_toEndOf="@id/cEndPicker"
        android:layout_marginStart="10dp" />

</RelativeLayout>

回答1:


I had a similar issue. I was using the scrollBy() method to set the value of the number picker programmatically and on two of the values, wrong numbers were shown. After some investigation I realized that there was some code in the onTouch of the NumberPicker, which was not being called when setting values programmatically.

So I simulate a touch right after I set a value.

public void changeValueByOne(final boolean increment) {

    int scrollStep = getHeight() / 3;

    scrollBy(0, increment ? scrollStep : (-1 * scrollStep));

    simulateTouchHack();
}

private void simulateTouchHack() {
    MotionEvent motionEventDown = MotionEvent.obtain(
            SystemClock.uptimeMillis(),
            SystemClock.uptimeMillis() + 100,
            MotionEvent.ACTION_DOWN,
            getWidth() / 2,
            getHeight() / 2,
            0
    );

    dispatchTouchEvent(motionEventDown);

    MotionEvent motionEventUp = MotionEvent.obtain(
            SystemClock.uptimeMillis() + 200,
            SystemClock.uptimeMillis() + 300,
            MotionEvent.ACTION_UP,
            getWidth() / 2,
            getHeight() / 2,
            0
    );

    dispatchTouchEvent(motionEventUp);
}



回答2:


Calling invalidate() on the NumberPicker might help. I called it from Fragment.onViewCreated and so far so good



来源:https://stackoverflow.com/questions/31882051/numberpicker-showing-wrong-value-after-setvalue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!