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" и просто прокрутите изображение, вы увидите полосы прокрутки.
Ответ 4
Метод "initializeScrollbars" был удален с уровня 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.html.
initializeScrollbars undefined?
FYI. Мы не можем использовать метод initializeScrollbars (a) больше в Lollipop.