Android按钮文字垂直滚动

时间:2015-12-22 14:22:18

标签: android button scroll

我正在开发一个Android应用程序,在一个屏幕上我有10个方形按钮。某些按钮上的文字太长而无法显示,所以目前只有一部分按钮显示。我想要做的是按钮'当按钮未对焦时,文本会自动垂直滚动(在按钮内)。因此屏幕加载并且文本无限滚动。每当它到达结尾时,它应该从文本的开头开始并再次向下滚动。我知道有一个marquee属性,这可以水平实现,但我需要它垂直。我研究了scrollTo方法,但它立即滚动到底部。我会发布一些代码,但无论我有什么来自其他SO帖子。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

@brokenstar提供了一个真正帮助我的链接。我必须做一些修改才能满足我的特定需求,所以这里是修改后的代码。

public class SquareButtonVScrolling extends SquareButton {

private boolean stop;
private boolean isNotDrawn = true;
private final Activity activity;
private long duration;
private int pixelYOffSet;

public SquareButtonVScrolling(Context context, AttributeSet attrs) {
    super(context, attrs);

    this.activity = (Activity) context;
}

public SquareButtonVScrolling(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    this.activity = (Activity) context;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int width = View.MeasureSpec.getSize(widthMeasureSpec);
    setMeasuredDimension(width, width);
}

public void init() {
    // If there are more lines than can be displayed startMarquee, otherwise don't do anything
    if ((SquareButtonVScrolling.this).getLineCount() > (SquareButtonVScrolling.this).getHeight() / (SquareButtonVScrolling.this).getLineHeight()) {
        setDuration(65l);
        setPixelYOffSet(1);

        stop = false;

        startMarquee();
    }
}

/**
 * @return Returns the (long) duration in milliseconds between calls to the
 *         next scrollBy(0, pixelYOffSet).
 */
public long getDuration() {
    return duration;
}

/**
 * @param duration
 *            Sets the (long) duration in milliseconds between calls to the
 *            next scrollBy(0, pixelYOffSet). Defaults to 65L if value is
 *            less than or equal to 0.
 */
public void setDuration(long duration) {
    if (duration <= 0) {
        this.duration = 65l;
    } else {
        this.duration = duration;
    }
}

/**
 * @return Returns the (int) amount of Y pixels to scroll by.
 */
public int getPixelYOffSet() {
    return pixelYOffSet;
}

/**
 * @param pixelYOffSet
 *            Sets the (int) amount of Y pixels to scroll by. Defaults to 1
 *            if value is less.
 */
public void setPixelYOffSet(int pixelYOffSet) {
    if (pixelYOffSet < 1) {
        this.pixelYOffSet = 1;
    } else {
        this.pixelYOffSet = pixelYOffSet;
    }
}

/**
 * Starts the marquee
 */
private void startMarquee() {
    new AutoScrollSquareButton().executeOnExecutor(Utils.CUSTOM_THREAD_POOL_EXECUTOR);
}

/**
 * Stop the marquee.
 */
public void stopMarquee() {
    stop = true;
}

private class AutoScrollSquareButton extends AsyncTask<Void, Void, Void> {

    private int pixelCount;

    @Override
    protected Void doInBackground(Void... params) {

        // Check to see if the VMSB has been drawn to get proper sizing.
        while (squareButtonNotDrawn()) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

            while (!stop) {
                // Sleep duration amount between scrollBy pixelYOffSet
                try {
                    Thread.sleep(duration);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                activity.runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                            // if VMSB has reached or exceeded the last
                            // Y pixel scroll back to top
                            if ((SquareButtonVScrolling.this).getScrollY() >= pixelCount) {
                                (SquareButtonVScrolling.this).scrollTo(0, 0);

                            } else { // Otherwise scroll by the pixelYOffSet
                                (SquareButtonVScrolling.this).scrollBy(0, pixelYOffSet);
                            }

                            (SquareButtonVScrolling.this).invalidate();
                    }
                });
            }

        return null;
    }

    @Override
    protected void onProgressUpdate(Void... values) {
        super.onProgressUpdate(values);
    }

    private boolean squareButtonNotDrawn() {
        activity.runOnUiThread(new Runnable() {

            @Override
            public void run() {
                // Checks to see if VMSB has been drawn.
                if ((SquareButtonVScrolling.this).isShown()) {
                    // Calculate the total pixel height that needs to be scrolled.
                    // May need additional calculations if there is additional padding.
                    pixelCount = (SquareButtonVScrolling.this).getLineHeight() * (SquareButtonVScrolling.this).getLineCount();
                    isNotDrawn = false;
                }
            }
        });

        return isNotDrawn;
    }
}

}

调用init()函数时,需要确保getLineCount(),getHeight()和getLineHeight()将返回所需的值而不是0.这些函数需要在绘制视图后调用我的情况我这样调用了init():

myView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    myView.init();
                }
            }, 20);

20ms的小延迟就足够了。此外,因为我有多达30个垂直自动滚动按钮,我需要使用executeOnExecutor来启动带有自定义线程池的AsyncTask(为了让多个按钮同时滚动)。这是我使用的定义:

/**
     * A custom {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor CUSTOM_THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(30, 30, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(128));

希望这有助于某人!