1

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

我已启用 ScaleGestureDetector,以便用户可以放大特定部分并进行绘制,但由于我使用单点触控进行绘制,他们无法使用手指在放大的视图周围平移。

我试图为视图启用滚动条,以便在放大它们时显示滚动条并且用户可以使用它来平移......但我根本无法显示滚动条。

本质上,我所做的是在用户放大时awakenScrollBars()在我的 ScaleListener 方法中调用 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);

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

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

谢谢,

保罗

4

4 回答 4

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();

PS 该解决方案在 Android 2.0 上进行了测试

我忘了补充:“computeVerticalScrollRange”和“computeHorizo​​ntalScrollRange”方法也应该被覆盖。他们应该只返回画布的假想宽度和高度。

于 2011-06-01T09:56:38.360 回答
3

众所周知,Android 视图具有滚动功能。

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

  1. 在视图的 xml 声明中添加 android:scrollbars="horizo​​ntal|vertical"
  2. 覆盖View类的computeHorizo​​ntalScrollRange/computeVerticalScrollRange方法,使得返回值大于computeHorizo​​ntalScrollExtent/computeVerticalScrollExtent方法的返回值

之后,当您调用 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,然后滚动图像,您应该会看到滚动条。

于 2013-06-03T02:54:22.050 回答
3

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

在这个问题和我的回答中可以看到更多信息。

于 2011-12-20T22:52:00.613 回答
0

从 API 级别 21 开始,方法“initializeScrollbars”已被删除。

    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 未定义?

供参考。我们不能再在 Lollipop 中使用方法 initializeScrollbars(a)。

于 2014-11-27T05:22:02.100 回答