1

画面が回転すると、シークバーの色付きのバーが初期値に戻りますが、親指は正しい位置に留まります。

基本的にこれから:

ここに画像の説明を入力

次のようになります。

ここに画像の説明を入力

TextView表示はシークバーに接続されており、シークバーで値を取得する際に15更新される同じ値を正しく表示することに注意してください。そのため、シークバー内部で正しい進行を示しますが、バーの更新を「忘れる」ことになります。また、わずかに移動すると、バーが正しく更新されることに注意してください。onCreateViewgetProgress

奇妙なことに、私はまったく同じアクション(メソッド呼び出しなど)を行う同一のシークバーを持っていますが、これにはこの問題はありません。

これらは、XML レイアウト ファイルで同じ方法で定義されます ( を除くid)。

これらのシークバーは の中にありFragmentViewPagerフラグメントのコードは多かれ少なかれ次のとおりです。

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には 2 つのインクリメント ボタンとデクリメント ボタンとシークバーがあります。

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、まだ問題が発生します。私も入れようとしましたが、何も変わりませんでした。何が起こっているのか本当にわかりません。onStartonResumelevelBar.setValue(levelBar.getValue())onResume

EDIT3:これらのバーのうち 6 つを含む別のフラグメントを追加しましたがlevelBar、上記のコードのみが奇妙に動作します。これがどのように可能なのだろうか。本当に奇妙なバグがあるか、場所がわかりませんが、適切に何かをしていません(Android 4.xではすべて正常に動作します)。

EDIT4:私の 3 番目の編集は正しくありません: 現在、ほぼすべてのバーがこの動作をしています。上記statsBarは影響を受けない唯一のもののようです。

4

2 に答える 2

1

私はついにコードの何が問題なのかを理解しました。

aの最大値を変更しても、親指の再描画はトリガーされますが、カラーバーの再描画トリガーされないようですSeekBar。これはおそらくandroid2.xのバグです(android 4.xでは発生しないため)。

この問題を解決するには、シークバーで進行状況を設定する前に最大値を設定する必要があります。

私の場合、影響を受けるのは一部のバーのみでした。これは、デフォルトの最大値NumericSeekBarを100に設定したためであり、影響を受けるのは最大値が異なるバーのみです。

onResumeのビューを無効にしても、ウィジェットが正しく再描画されない理由はまだ明らかではありません。

于 2013-01-20T12:03:01.990 に答える