1

当屏幕旋转时,我的搜索栏的彩色条回到其初始值,而拇指保持在正确的位置。

基本上从这个:

在此处输入图像描述

它变成这样:

在此处输入图像描述

请注意,TextView显示15连接到搜索栏并正确显示相同的值,该值在搜索栏上onCreateView检索值时更新getProgress,因此搜索栏在内部具有正确的进度,但“忘记”更新其栏。另请注意,如果稍微移动,该栏将正确更新。

奇怪的是我有一个相同的搜索栏,我在上面执行完全相同的操作(方法调用等),但这个从来没有这个问题。

它们在 XML 布局文件中以相同的方式定义(除了id)。

这些搜索栏在 aFragment中显示为 a 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,但问题仍然存在。我也尝试过加入,但没有任何改变。我真的不明白发生了什么。onStartonResumelevelBar.setValue(levelBar.getValue())onResume

EDIT3:我添加了一个包含六个这样的条的另一个片段,只有levelBar上面代码中的行为奇怪。我想知道这怎么可能。要么有一些非常奇怪的错误,要么我做的不正确,即使我看不到哪里(并且在 android 4.x 中一切正常)。

EDIT4:我的第三次编辑不正确:现在几乎所有的酒吧都有这种行为。以上statsBar似乎是唯一不受影响的。

4

2 回答 2

1

我终于明白代码有什么问题了。

似乎更改 a 的最大值SeekBar不会触发彩条的重绘,但会触发拇指的重绘这可能是 android 2.x 中的一个错误(因为它不会在 android 4.x 中发生)。

要解决这个问题,您只需在设置搜索栏上的进度之前设置最大值。

在我的情况下,只有一些条受到影响,因为我将默认最大值设置NumericSeekBar为 100,并且只有具有不同最大值的条受到影响。

目前尚不清楚为什么使视图无效onResume不会产生正确的小部件重新绘制。

于 2013-01-20T12:03:01.990 回答
0

我找到了递归方法:

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();
}
}
于 2017-05-10T06:42:36.547 回答