Android:在基于画布的视图上启用滚动条

时间:2011-02-01 23:40:02

标签: android scroll android-canvas

我有一个扩展View的自定义视图。它显示绘制的形状,并允许用户通过onDraw将触摸事件绘制到视图中来添加到这些绘图。

我启用了ScaleGestureDetector,以便用户可以放大特定部分并进行绘制,但是当我使用单点触摸绘制时,他们无法使用手指在放大的视图中平移。

我尝试为View启用滚动条,当它们放大时,滚动条会显示,并且可供用户使用以进行平移......但我根本无法显示滚动条。

基本上,我正在做的是在用户放大时调用我的ScaleListener的awakenScrollBars()方法中的View onScale()方法,这会触发invalidate()。我通过XML启用了滚动条,并在onCreate()中以编程方式启用了滚动条,但我无法触发滚动条可见。这是我的XML:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.package.name.Canvas
    android:id="@+id/canvas"
    android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:focusable="true"
        android:scrollbars="horizontal|vertical" />
</FrameLayout>

这是我的onCreate():

// set scrollbars
setHorizontalScrollBarEnabled(true);
setVerticalScrollBarEnabled(true);

在onDraw中,我可以通过isHorizontalScrollBarEnabled()isVerticalScrollBarEnabled()验证滚动条是否已启用,awakenScrollBars()中的onScale()返回true,但滚动条只是不可见

有关如何进行的任何建议?在ScrollView布局中包含自定义视图似乎不是一个选项,因为它只支持垂直滚动。

谢谢,

4 个答案:

答案 0 :(得分:11)

如果以编程方式创建自定义视图,则答案如下: 为了在自定义视图类上显示滚动条,应该在初始化期间调用方法“initializeScrollbars”(例如在构造函数中)。

此方法采用TypedArray类型的一个非常模糊的参数。要获得合适的TypedArray实例,您需要创建自定义可样式条目 - 只需在“res \ values”目录中创建文件“attrs.xml”,其中包含以下内容:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="View">
    <attr name="android:background"/>
    <attr name="android:clickable"/>
    <attr name="android:contentDescription"/>
    <attr name="android:drawingCacheQuality"/>
    <attr name="android:duplicateParentState"/>
    <attr name="android:fadeScrollbars"/>
    <attr name="android:fadingEdge"/>
    <attr name="android:fadingEdgeLength"/>
    <attr name="android:fitsSystemWindows"/>
    <attr name="android:focusable"/>
    <attr name="android:focusableInTouchMode"/>
    <attr name="android:hapticFeedbackEnabled"/>
    <attr name="android:id"/>
    <attr name="android:isScrollContainer"/>
    <attr name="android:keepScreenOn"/>
    <attr name="android:longClickable"/>
    <attr name="android:minHeight"/>
    <attr name="android:minWidth"/>
    <attr name="android:nextFocusDown"/>
    <attr name="android:nextFocusLeft"/>
    <attr name="android:nextFocusRight"/>
    <attr name="android:nextFocusUp"/>
    <attr name="android:onClick"/>
    <attr name="android:padding"/>
    <attr name="android:paddingBottom"/>
    <attr name="android:paddingLeft"/>
    <attr name="android:paddingRight"/>
    <attr name="android:paddingTop"/>
    <attr name="android:saveEnabled"/>
    <attr name="android:scrollX"/>
    <attr name="android:scrollY"/>
    <attr name="android:scrollbarAlwaysDrawHorizontalTrack"/>
    <attr name="android:scrollbarAlwaysDrawVerticalTrack"/>
    <attr name="android:scrollbarDefaultDelayBeforeFade"/>
    <attr name="android:scrollbarFadeDuration"/>
    <attr name="android:scrollbarSize"/>
    <attr name="android:scrollbarStyle"/>
    <attr name="android:scrollbarThumbHorizontal"/>
    <attr name="android:scrollbarThumbVertical"/>
    <attr name="android:scrollbarTrackHorizontal"/>
    <attr name="android:scrollbarTrackVertical"/>
    <attr name="android:scrollbars"/>
    <attr name="android:soundEffectsEnabled"/>
    <attr name="android:tag"/>
    <attr name="android:visibility"/>
</declare-styleable>
</resources>

完整的滚动条初始化代码(将其放在自定义视图构造函数上):

setHorizontalScrollBarEnabled(true);
setVerticalScrollBarEnabled(true);

TypedArray a = context.obtainStyledAttributes(R.styleable.View);
initializeScrollbars(a);
a.recycle();

P.S。该解决方案在Android 2.0上进行了测试

我忘了添加: 还应该重写“computeVerticalScrollRange”和“computeHorizo​​ntalScrollRange”方法。它们应该只返回画布的假想宽度和高度。

答案 1 :(得分:3)

对于那些尝试将滚动条添加到自定义ViewGroup(而不是View)或其子类之一的人,请确保将setWillNotDraw(false);添加到构造函数中Ruslan Yanchyshyn在上面的回答中说了什么。

可以在此question和我的answer中看到更多信息。

答案 2 :(得分:3)

众所周知,Android视图可以滚动。

要显示滚动条,有两件事要做。

  1. 在视图的xml声明中添加android:scrollbars =“horizo​​ntal | vertical”
  2. 覆盖View类的computeHorizo​​ntalScrollRange / computeVerticalScrollRange方法,使返回值大于computeHorizo​​ntalScrollExtent / computeVerticalScrollExtent方法的返回值
  3. 之后,当您调用scrollTo或scrollBy方法时,滚动条应自动显示。

    对不起,我的英语很差,如果有任何咒语或语法错误。 你可以尝试一下:
    activity_main.xml中

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:paddingBottom="10dp"
    android:paddingLeft="10dp"
    android:paddingRight="10dp"
    android:paddingTop="10dp"
    tools:context=".MainActivity" >
    
    <com.netease.test.testscroll.ScrollImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#FFCCCCCC"
        android:scrollbars="horizontal|vertical"
        android:src="@drawable/pp" />
    
    </LinearLayout>
    

    ScrollImageView是一个自定义视图,您可以这样实现:

    public class ScrollImageView extends ImageView {
        static final String TAG = "ScrollImageView";
        private Rect mContentRect = new Rect();
        GestureDetector mDetector;
        OnGestureListener mListener = new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2,
                    float distanceX, float distanceY) {
                Log.i("onScroll", "before:distanceX = " + distanceX
                        + ", distanceY = " + distanceY);
                scrollBy((int)distanceX, (int)distanceY);
                // boolean value = awakenScrollBars();
                Log.i("onScroll", "after:current ScrollX=" + getScrollX()
                        + ", ScrollY=" + getScrollY());
                return true;
            }
        };
        public ScrollImageView(Context context) {
            this(context, null);
        }
        public ScrollImageView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
        public ScrollImageView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            setScaleType(ScaleType.MATRIX);
            mDetector = new GestureDetector(getContext(), mListener);
        }
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            mDetector.onTouchEvent(event);
            return true;
        }
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mContentRect.set(getPaddingLeft(), getPaddingTop(), getWidth()
                    - getPaddingRight(), getHeight() - getPaddingBottom());
        }
        @Override
        protected int computeHorizontalScrollRange() {
            return getDrawable().getIntrinsicWidth();
        }
        @Override
        protected int computeHorizontalScrollExtent() {
            return mContentRect.width();
        }
        @Override
        protected int computeHorizontalScrollOffset() {
            return Math.max(0, getScrollX());
        }
        private int getScrollRangeX() {
            return computeHorizontalScrollRange() - computeHorizontalScrollExtent();
        }
        @Override
        protected int computeVerticalScrollRange() {
            return getDrawable().getIntrinsicHeight();
        }
        @Override
        protected int computeVerticalScrollExtent() {
            return mContentRect.height();
        }
        @Override
        protected int computeVerticalScrollOffset() {
            return Math.max(0, getScrollY());
        }
        private int getScrollRangeY() {
            return computeVerticalScrollRange() - computeVerticalScrollExtent();
        }
    }
    

    指定一个名为“pp”的大png,只需滚动图像,就会看到滚动条。

答案 3 :(得分:0)

方法&#34; initializeScrollbars&#34;已从API级别21开始删除。

    final TypedArray a = context.obtainStyledAttributes(R.styleable.View);
    initializeScrollbars(a);//removed method in Lollipop.
    a.recycle();

请参阅。 https://developer.android.com/sdk/api_diff/21/changes/android.view.View.htmlinitializeScrollbars is undefined?

FYI。我们不能在Lollipop中使用initializeScrollbars(a)方法了。