SeekBar动态设置最大值和当前值有先后顺序

2014年12月08日 Android 2条评论 阅读13457次
SeekBar动态设置最大值和当前值有先后顺序

近期项目的APP中,有一个需要垂直SeekBar调整程度的需求。
首先继承了AbsSeekBar自己写了各VerticalSeekBar。

其次就是操作VerticalSeekBar了。

项目背景需求

项目需求中,一个画面中,多个项目需要VerticalSeekBar来调整程度,但每个项目不会同时显示这个VerticalSeekBar,根据不同条件显示不同的VerticalSeekBar的,并且每个设置项目的可调整的最大值还是不同的。

为了UI上布局上方便一些,在布局文件中,我就只添加了一个VerticalSeekBar的控件,然后到java逻辑中判断,每次VerticalSeekBar的初始默认值是多少,每个项目的最大值是多少。

出现的问题

在所有功能写完进行测试时,遇到了下面的问题。
点击功能A按钮,取出A对应的默认progress位置及A最大值,显示A对应的VerticalSeekBar
调整功能A的VerticalSeekBar的progress
点击功能B按钮,取出B对应的默认progress位置及B最大值,显示B对应的VerticalSeekBar
调整功能B的VerticalSeekBar的progress
再次点击功能A按钮,查看A对应的VerticalSeekBar,此时发生问题了,A的VerticalSeekBar的进度位置并不是上次设置的位置;但若再一次重复点击功能A按钮,此时A对应的VerticalSeekBar便有恢复回正常状态了。

查阅应用逻辑的代码后认为保存上次数值时没有错误,从而将目标转向自定义VerticalSeekBar。

自定义VerticalSeekBar的显示位置,由两个因素来决定。


  • progress:对应API中的setProgress(int)
  • max:对应API中的setMax(int)

在自定义VerticalSeekBar类中,我并没有重写这两个方法,也就是setProgress(int)和setMax(int)都是调用的父类方法。
从framework目录的下面两个文件中找到了setProgress(int)和setMax(int)的源代码
  frameworks\base\core\java\android\widget\AbsSeekBar.java
  frameworks\base\core\java\android\widget\ProgressBar.java

代码追踪

frameworks\base\core\java\android\widget\AbsSeekBar.java


@Override
    public synchronized void setMax(int max) {
        super.setMax(max);

        if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) {
            // It will take the user too long to change this via keys, change it
            // to something more reasonable
            setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20)));
        }
    }
frameworks\base\core\java\android\widget\ProgressBar.java



@android.view.RemotableViewMethod
    public synchronized void setMax(int max) {
        if (max < 0) {
            max = 0;
        }
        if (max != mMax) {
            mMax = max;
            postInvalidate();

            if (mProgress > max) {
                mProgress = max;
            }
            refreshProgress(R.id.progress, mProgress, false);
        }
    }

    @android.view.RemotableViewMethod
    public synchronized void setProgress(int progress) {
        setProgress(progress, false);
    }
    @android.view.RemotableViewMethod
    synchronized void setProgress(int progress, boolean fromUser) {
        if (mIndeterminate) {
            return;
        }

        if (progress < 0) {
            progress = 0;
        }

        if (progress > mMax) {
            progress = mMax;
        }

        if (progress != mProgress) {
            mProgress = progress;
            refreshProgress(R.id.progress, mProgress, fromUser);
        }
    }
这两段代码贴出来仅供参考,最后无论是setProgress(int)还是setMax(int),都走到了下面的refreshProgress方法。
frameworks\base\core\java\android\widget\ProgressBar.java
private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
        if (mUiThreadId == Thread.currentThread().getId()) {
            doRefreshProgress(id, progress, fromUser, true);
        } else {
            if (mRefreshProgressRunnable == null) {
                mRefreshProgressRunnable = new RefreshProgressRunnable();
            }

            final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
            mRefreshData.add(rd);
            if (mAttached && !mRefreshIsPosted) {
                post(mRefreshProgressRunnable);
                mRefreshIsPosted = true;
            }
        }
    }

在应用层的逻辑中,调换了setProgress(int)和setMax(int)的顺序之后,意外地发现上面说的问题竟然就解决了。
这里还没有确凿的证据来说明为什么之前先调用setProgress(int)再调用setMax(int)为什么的问题,但后来的实验结果证实了setProgress(int)和setMax(int)貌似有先后顺序的制约。
我最后成功的调用顺序是:setMax(int)--->setProgress(int)。
希望本文能对在使用自定义SeekBar时出现类似问题的读者能有些启发性的帮助。

分享本文至:

WRITTEN BY

avatar
本文标签:VerticalSeekBar
看了本文是不是觉得很赞,那就赶紧点击下面按钮分享给身边的朋友吧!

2 条评论

  1. avatar 地源热泵

    在茶树上就已经呈现白色,

  2. avatar 王语双

    [F4] 很专业的文章,打哈哈的路过。
    例行路过,快周末了,祝过得愉快。

欢迎留言




用户登录

sitemap