Цветная полоса SeekBar не соответствует прогрессу и большому пальцу

Когда экран вращается, цветная полоса моей панели поиска возвращается к своему первоначальному значению, в то время как большой палец остается в правильном положении.

В основном из этого:

Это становится так:

Обратите внимание, что TextView показ 15 подключен к панели поиска и правильно показывает то же значение, которое обновляется в onCreateView получение значения с getProgress на панели поиска, поэтому панель поиска имеет правильный внутренний прогресс, но "забывает" обновить свою панель. Также обратите внимание, что при небольшом перемещении панель будет обновлена ​​правильно.

Странно то, что у меня есть идентичная панель поиска, на которой я выполняю точно такие же действия (вызовы методов и т. Д.), Но эта проблема никогда не возникает.

Они определены таким же образом в файле макета XML (за исключением id).

Эти панели поиска находятся внутри Fragment показано в ViewPagerВот более или менее код для фрагмента:

public class NewCharacterNameFragment extends Fragment
        implements NumericSeekBar.OnValueChangedListener {

    private static final String LEVEL = "org.my.package.LEVEL";
    private static final String STATS = "org.my.package.STATS";

    private NumericSeekBar levelBar;   // Causing problems
    private NumericSeekBar statsBar;   // Well behaved

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        super.onCreateView(inflater, container, savedInstanceState);

        if (savedInstanceState == null) {  // defaults values to avoid multiple checks later
            savedInstanceState = new Bundle();
            savedInstanceState.putInt(LEVEL, 1);
            savedInstanceState.putInt(STATS, 30);
        }

        View view = inflater.inflate(R.layout.new_character_name_fragment, container,
                                     false);

        levelBar = (NumericSeekBar) view.findViewById(R.id.levelSeekBar);
        statsBar = (NumericSeekBar) view.findViewById(R.id.statPointsSeekBar);

        levelBar.setValue(savedInstanceState.getInt(LEVEL));
        levelBar.setMax(20);
        levelBar.setValueChangedListener(this);

        statsBar.setValue(savedInstanceState.getInt(STATS));
        statsBar.setMax(100);
        statsBar.setValueChangedListener(this);

        // Initialize the text-views with the progress values:
        TextView tView = (TextView) view.findViewById(R.id.statPointsNumTextView);
        tView.setText(Integer.valueOf(statsBar.getValue()).toString());
        tView = (TextView) view.findViewById(R.id.levelNumTextView);
        tView.setText(Integer.valueOf(levelBar.getValue()).toString());

        return view;
    }


    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {

        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putInt(LEVEL, levelBar.getValue());
        savedInstanceState.putInt(STATS, statsBar.getValue());
    }


    @Override
    public void onNumericSeekBarValueChanged(NumericSeekBar bar, int value,
                                             boolean fromUser) {
        // Called whenever the seekbar value changes
        if (bar == statsBar) {
            TextView view = (TextView) getView().findViewById(R.id.statPointsNumTextView);
            view.setText(Integer.valueOf(value).toString());
        } else if (bar == levelBar) {
            TextView view = (TextView) getView().findViewById(R.id.levelNumTextView);
            view.setText(Integer.valueOf(value).toString());
        }
    }
}

куда NumericSeekBar это виджет, который я создал, и в основном LinearLayout с двумя кнопками увеличения и уменьшения и панелью поиска:

public class NumericSeekBar extends LinearLayout
        implements SeekBar.OnSeekBarChangeListener, View.OnClickListener {


    public interface OnValueChangedListener {
        public void onNumericSeekBarValueChanged(NumericSeekBar bar, int value,
                                                 boolean fromUser);
    }

    private Button incButton;
    private Button decButton;
    private SeekBar seekBar;

    private OnValueChangedListener listener = null;

    private int maxValue = 100;
    private int value = 0;


    public NumericSeekBar(Context ctx) {
        super(ctx);
        setOpts();
        setWidgets();
    }

    public NumericSeekBar(Context ctx, AttributeSet attributes) {
        super(ctx, attributes);
        setOpts();
        setWidgets();
    }

    public void setValueChangedListener(OnValueChangedListener listener) {
        this.listener = listener;
    }

    public void setMax(int maxValue) {
        this.maxValue = maxValue;
        seekBar.setMax(maxValue);
    }


    public int getValue() {
        return this.value;  // using seekBar.getProgress() obtains same results
    }

    public boolean setValue(int value) {
        if (value < 0 || value > maxValue) {
            return false;
        }
        this.value = value;
        seekBar.setProgress(value);
        return true;
    }

    @Override
    public void onStopTrackingTouch(SeekBar bar) {
        bar.setSecondaryProgress(bar.getProgress());
    }

    @Override
    public void onStartTrackingTouch(SeekBar bar) {
    }

    @Override
    public void onProgressChanged(SeekBar bar, int value, boolean fromUser) {
        this.value = value;
        if (listener != null ){
            listener.onNumericSeekBarValueChanged(this, value, fromUser);
        }

        if (!fromUser) {
            bar.setSecondaryProgress(0);
        }
    }


    @Override
    public void onClick(View v) {
        // Handle increment/decrement button clicks
        if (v.equals(incButton)) {
            this.setValue(this.getValue() + 1);
        } else if(v.equals(decButton)) {
            this.setValue(this.getValue() - 1);
        }
    }


    private void setOpts() {
        setOrientation(HORIZONTAL);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            setShowDividers(SHOW_DIVIDER_NONE);
        }
    }

    private void setWidgets() {
        incButton = new Button(getContext());
        decButton = new Button(getContext());
        seekBar = new SeekBar(getContext());

        incButton.setText("+");
        incButton.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
        incButton.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                                   ViewGroup.LayoutParams.WRAP_CONTENT,
                                                   (float) 0.4));
        incButton.setOnClickListener(this);
        decButton.setText("-");
        decButton.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
        decButton.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                                   ViewGroup.LayoutParams.WRAP_CONTENT,
                                                   (float) 0.4));

        decButton.setOnClickListener(this);

        LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                                     ViewGroup.LayoutParams.WRAP_CONTENT,
                                                     (float) 0.2);
        layoutParams.gravity = Gravity.CENTER;

        seekBar.setLayoutParams(layoutParams);

        setMax(this.maxValue);
        setValue(this.value);


        addView(incButton);
        addView(seekBar);
        addView(decButton);

        seekBar.setOnSeekBarChangeListener(this);
    }
}

Это происходит как на эмуляторе, так и на физическом устройстве.

РЕДАКТИРОВАТЬ: я только что проверил мое приложение на эмуляторе Android 4, и это не происходит, так что, похоже, что-то связано 2.x.

EDIT2: я пытался invalidate() бары в onCreateView, onStart а также onResume но проблемы все еще возникают. Я также пытался поставить levelBar.setValue(levelBar.getValue()) в onResume но ничего не изменилось. Я действительно не понимаю, что происходит.

EDIT3: я добавил другой фрагмент, который содержит шесть из этих столбцов и только levelBar в коде выше ведет себя странно. Интересно, как это возможно? Либо есть какая-то действительно странная ошибка, либо я делаю что-то не так, хотя я не могу видеть, где (и в Android 4.x все работает хорошо).

EDIT4: мое третье редактирование неверно: теперь почти все бары имеют такое поведение. statsBar выше, кажется, единственный, который никогда не затрагивается.

2 ответа

Решение

Я наконец понял, что не так с кодом.

Кажется, что изменение максимального значения SeekBar не вызывает перерисовку цветовой шкалы, пока она вызывает перерисовку большого пальца. Это, вероятно, ошибка в Android 2.x(так как это не происходит в Android 4.x).

Чтобы решить эту проблему, вам просто нужно установить максимальное значение, прежде чем устанавливать прогресс на панели поиска.

В моем случае только некоторые бары были затронуты, потому что я установил максимум по умолчанию для NumericSeekBar до 100, и только бары с другим максимумом, где затронуты.

До сих пор не ясно, почему аннулировать представление в onResume не производит правильную перерисовку виджета.

Я нахожу метод повторения:

final SeekBar seekBar = (SeekBar) findViewById(R.id.test_seekbar);
seekBar.setMax(4000);
seekBar.setProgress(1500);
new Thread(new Runnable() {
    public void run() {
        seekBar.setProgress(500);
    }
}).start();
for (int i = 0; i < 5000; i++) {
    seekBar.setProgress(2000);
}

код выше, называется ProgressBar#setProgress в рабочем потоке это вызывает ошибку. Официальный совет Android по документации назвал его в главном потоке, например так:

public class MyActivity extends Activity {
private static final int PROGRESS = 0x1;

private ProgressBar mProgress;
private int mProgressStatus = 0;

private Handler mHandler = new Handler();

protected void onCreate(Bundle icicle) {
    super.onCreate(icicle);

    setContentView(R.layout.progressbar_activity);

    mProgress = (ProgressBar) findViewById(R.id.progress_bar);

    // Start lengthy operation in a background thread
    new Thread(new Runnable() {
        public void run() {
            while (mProgressStatus < 100) {
                mProgressStatus = doWork();

                // Update the progress bar
                mHandler.post(new Runnable() {
                    public void run() {
                        mProgress.setProgress(mProgressStatus);
                    }
                });               
            }
        }
    }).start();
}
}
Другие вопросы по тегам