Android 以编程方式自定义滚动条

Android 以编程方式自定义滚动条,android,scrollbar,Android,Scrollbar,我的要求是每当视图的总高度大于列表允许的高度时,用滚动条显示视图的垂直列表 此外,我需要以编程方式自定义滚动条的外观(背景和拇指)。(在运行时,“我的活动”将接收进行渲染的所有数据:用作滚动条背景的位图、滚动条宽度和用作滚动条拇指的位图。) A似乎是一个很好的选择,除了我找不到一种方法来以编程方式自定义滚动条。 我读了这个问题,但是,它使用了一个主题,而且很抱歉,它不可能以编程方式创建一个新的主题 因此,我的问题是: 有没有办法通过编程自定义滚动条(在ListView中)的外观 [只有在第一个问

我的要求是每当视图的总高度大于列表允许的高度时,用滚动条显示视图的垂直列表

此外,我需要以编程方式自定义滚动条的外观(背景和拇指)。(在运行时,“我的活动”将接收进行渲染的所有数据:用作滚动条背景的位图、滚动条宽度和用作滚动条拇指的位图。)

A似乎是一个很好的选择,除了我找不到一种方法来以编程方式自定义滚动条。 我读了这个问题,但是,它使用了一个主题,而且很抱歉,它不可能以编程方式创建一个新的主题

因此,我的问题是:

  • 有没有办法通过编程自定义滚动条(在ListView中)的外观

  • [只有在第一个问题的答案是“绝对不可能”的情况下]您是否看到了实现这些要求的其他方法(以及实现这些要求的一些工作示例)

  • 谢谢

    编辑(23/12)


    我发现了这个隐藏的类 ;
    android.widget.ScrollBarDrawable
    。可能是构建解决方案的良好起点(现在没有时间进行研究)。

    只需更改
    android:scrollbarThumbVertical=“@drawable/scrollbar\u vertical\u thumb”
    并根据您的需要创建一个可拉伸的

    
    
    在可抽出式中:

    <shape xmlns:android="http://schemas.android.com/apk/res/android" > 
        <gradient android:angle="0" android:endColor="#6699FF" android:startColor="#3333FF" />
        <corners android:radius="1dp" /> 
        <size android:width="1dp" /> 
    </shape>
    
    
    
    我想这就是你想要的

    有没有办法以编程方式自定义滚动条(在ListView中)的外观

    从字面上看,它看起来不像它,只是因为没有用于操纵它的设置器

    可以想象,您可以创建自己的
    BenView
    子类
    View
    ,该子类将隐藏的
    ScrollBarDrawable
    替换为处理动态更改的
    BenScrollBarDrawable
    。但是,您需要创建
    BenViewGroup
    BenAbsListView
    BenListView
    ,克隆它们的无本对等源代码,使它们链接到
    BenView
    ,以继承此行为。而且,由于
    ViewGroup
    AbsListView
    ListView
    中的一个在任何Android版本中都会发生变化,因此您实际上需要这些类的N个副本,并在运行时根据API级别选择正确的副本。然后,你的应用程序可能在一些设备上仍会表现异常,制造商在这些设备上修改了
    ViewGroup
    AbsListView
    ListView
    ,你将无法使用他们的代码

    我怀疑这是否值得,特别是因为滚动条在默认情况下是不可见的,除非在滚动时

    您是否看到了实现这些要求的其他方法(以及实现这些要求的一些工作示例)


    处理您自己的触摸事件以进行您自己的滚动和滚动条操作。这是否比上述解决方案的工作量少,还有待讨论。

    您可以使用jquery插件(jquery.nicesroll.js)来实现这一点。更多详情请访问

    我刚刚为RecyclerView遇到了同样的问题,并这样解决了它

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.PorterDuff;
    import android.graphics.drawable.Drawable;
    import android.support.annotation.ColorInt;
    import android.support.v7.widget.RecyclerView;
    import android.util.AttributeSet;
    
    /**
     * Created on 22.3.2016.
     *
     * @author Bojan Kseneman
     * @description A recycler view that will draw the scroll bar with a different color
     */
    public class CustomScrollBarRecyclerView extends RecyclerView {
    
        private int scrollBarColor = Color.RED;
    
        public CustomScrollBarRecyclerView(Context context) {
            super(context);
        }
    
        public CustomScrollBarRecyclerView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public CustomScrollBarRecyclerView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public void setScrollBarColor(@ColorInt int scrollBarColor) {
            this.scrollBarColor = scrollBarColor;
        }
    
        /**
         * Called by Android {@link android.view.View#onDrawScrollBars(Canvas)}
         **/
        protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b) {
            scrollBar.setColorFilter(scrollBarColor, PorterDuff.Mode.SRC_ATOP);
            scrollBar.setBounds(l, t, r, b);
            scrollBar.draw(canvas);
        }
    
        /**
         * Called by Android {@link android.view.View#onDrawScrollBars(Canvas)}
         **/
        protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b) {
            scrollBar.setColorFilter(scrollBarColor, PorterDuff.Mode.SRC_ATOP);
            scrollBar.setBounds(l, t, r, b);
            scrollBar.draw(canvas);
        }
    }
    

    这些方法是在视图类中定义的,因此相同的原则应该适用于其他视图,如ScrollView和ListView。

    如果您只需要支持API 24或更高版本,则可以使用自定义绘图来完成此任务。您需要决定如何允许drawable与活动进行通信。这里有一个可能的解决方案

    res/drawable/my_custom_scrollbar_thumb.xml

    res/drawable/my\u custom\u scrollbar\u track.xml

    在布局文件的某个地方


    抱歉,但我认为您不理解这个问题:我需要以编程方式完成,而不是使用静态xml。抱歉,不是寻找浏览器解决方案。它正在拉伸滚动条以匹配父项。您的意思是滚动条与父项一样宽还是什么?
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.PorterDuff;
    import android.graphics.drawable.Drawable;
    import android.support.annotation.ColorInt;
    import android.support.v7.widget.RecyclerView;
    import android.util.AttributeSet;
    
    /**
     * Created on 22.3.2016.
     *
     * @author Bojan Kseneman
     * @description A recycler view that will draw the scroll bar with a different color
     */
    public class CustomScrollBarRecyclerView extends RecyclerView {
    
        private int scrollBarColor = Color.RED;
    
        public CustomScrollBarRecyclerView(Context context) {
            super(context);
        }
    
        public CustomScrollBarRecyclerView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public CustomScrollBarRecyclerView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public void setScrollBarColor(@ColorInt int scrollBarColor) {
            this.scrollBarColor = scrollBarColor;
        }
    
        /**
         * Called by Android {@link android.view.View#onDrawScrollBars(Canvas)}
         **/
        protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b) {
            scrollBar.setColorFilter(scrollBarColor, PorterDuff.Mode.SRC_ATOP);
            scrollBar.setBounds(l, t, r, b);
            scrollBar.draw(canvas);
        }
    
        /**
         * Called by Android {@link android.view.View#onDrawScrollBars(Canvas)}
         **/
        protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b) {
            scrollBar.setColorFilter(scrollBarColor, PorterDuff.Mode.SRC_ATOP);
            scrollBar.setBounds(l, t, r, b);
            scrollBar.draw(canvas);
        }
    }
    
    public class RegisteredMutableDrawable extends DrawableWrapper
    {
        public static interface Registrar
        {
            public void register(int _id, RegisteredMutableDrawable _drawable);
        }
    
        public static Registrar registrar;
    
        private static int[] ATTRS = new int[] { android.R.attr.id };
    
        public RegisteredMutableDrawable()
        {
            super(null);
        }
    
        public void inflate(Resources _res, XmlPullParser _parser, AttributeSet _as, Theme _theme)
            throws XmlPullParserException, IOException
        {
            super.inflate(_res, _parser, _as, _theme);
            final Registrar r = registrar;
            if (r != null)
            {
                final TypedArray ta = _res.obtainAttributes(_as, ATTRS);
                final int id = ta.getResourceId(0, 0);
                ta.recycle();
                r.register(id, this);
            }
        }
    }
    
    public class MyActivity extends Activity implements RegisteredMutableDrawable.Registrar
    {
        @Override public void onCreate(Bundle _icicle)
        {
            super.onCreate(_icicle);
            RegisteredMutableDrawable.registrar = this;
            setContentView(R.layout.whatever);
            RegisteredMutableDrawable.registrar = null; // don't leak our activity!
        }
    
        @Override public void register(int _id, RegisteredMutableDrawable _drawable)
        {
            switch(_id)
            {
                case R.id.scroll_thumb:
                    _drawable.setDrawable(myThumbDrawable);
                    break;
                case R.id.scroll_track:
                    _drawable.setDrawable(myTrackDrawable);
                    break;
            }
        }
    }