Android: включение полос прокрутки в режиме холста

У меня есть пользовательский вид, который расширяет представление. Он отображает нарисованные фигуры и позволяет пользователю добавлять эти чертежи посредством рисования событий касания к представлению через onDraw.

Я включил ScaleGestureDetector, чтобы пользователь мог увеличить масштаб в определенном разделе и рисовать, но поскольку я использую однократное нажатие для рисования, они не могут использовать свой палец для панорамирования увеличенного изображения в представлении.

Я попытался включить полосы прокрутки для представления так, чтобы при их увеличении полосы прокрутки отображались и могут использоваться пользователем для панорамирования... но я просто не могу заставить полосы прокрутки отображаться.

По существу, я пытаюсь вызвать метод View awakenScrollBars() в моем методе ScaleListener 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, похоже, не является опцией, так как поддерживается только вертикальная прокрутка.

Спасибо,

Пол

Ответ 1

Если вы произвольно создаете свой пользовательский вид, тогда ответ следующий: для того, чтобы показывать полосы прокрутки в пользовательском классе представления, метод "initializeScrollbars" должен вызываться во время инициализации (например, в конструкторе).

Этот метод использует один очень неясный параметр типа TypedArray. Чтобы получить подходящий экземпляр TypedArray, вам нужно создать пользовательскую запись в стиле - просто создайте файл "attrs.xml" в каталоге "res\values" со следующим содержимым:

<?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" и "computeHorizontalScrollRange". Они должны просто вернуть мнимую ширину и высоту холста.

Ответ 2

Для тех из вас, кто пытается добавить полосы прокрутки в пользовательский ViewGroup (а не View) или один из своих подклассов, убедитесь, что вы добавили setWillNotDraw(false); к своему конструктору в дополнение к тому, что Руслан Янчишин сказал в своих ответьте выше.

Больше информации можно найти в этом вопросе и в ответе .

Ответ 3

Как мы все знаем, Android-представление имеет возможность прокрутки.

Для показа полос прокрутки есть две вещи.

  • добавить android: scrollbars = "horizontal | vertical" в объявлении xml вашего представления
  • переопределяет метод computeHorizontalScrollRange/computeVerticalScrollRange класса View, делая возвращаемые значения большими, чем возвращаемые значения метода comporHorizontalScrollExtent/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();
    }
}

укажите большой png с именем "pp" и просто прокрутите изображение, вы увидите полосы прокрутки.