В Android ListView
, как я могу сделать scrollbar
с левой стороны?Как сделать «полосу прокрутки» на левой стороне?
ответ
пример:
mView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT);
Вы можете перемещать позицию полосы прокрутки влево для любого вида, используя View.SCROLLBAR_POSITION_LEFT.
В двух других ответов уже упоминалось, одним из возможных вариантов является использование View.setVerticalScrollbarPosition() с SCROLLBAR_POSITION_LEFT. Однако один гигантский оговорка заключается в том, что для этого требуется уровень API 11+, который на момент написания составляет менее 10% установок Android. Для большинства приложений это неприемлемо.
Одна из возможностей, которая приходит на ум для достижения того, что вы хотите в более старых версиях Android, - это сделать что-то очень неприятное: выключите полосу прокрутки, зеркально отразите основной макет с узким расположением слева от него, просто достаточно, чтобы соответствовать полосе прокрутки, и вручную прокрутите левый вид с помощью scrollyBy(), когда ваш основной вид прокручивается (путем переопределения onScrollChanged()).
Это, я бы не рекомендовал это, если нет веских причин для перемещения полосы прокрутки влево. В большинстве случаев вы хотите, чтобы ваше приложение вписывалось и вел себя как любое другое приложение на устройстве, просто позволяя Android следовать своим настройкам по умолчанию.
Попробуйте взломать, как представляется, работает как минимум на 2.2 и выше.
import java.lang.reflect.Field;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
/**
* This class fixes the lack of setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT) before API level 11
* @author Genadz Batsyan
*/
public class ListViewWithLeftScrollBar extends ListView {
private static final String LOG_TAG = ListViewWithLeftScrollBar.class.getSimpleName();
private static final boolean DEBUG = true;
private boolean patchInvalidate;
public ListViewWithLeftScrollBar(Context context) {
super(context);
moveVerticalScrollbarToTheLeft();
}
public ListViewWithLeftScrollBar(Context context, AttributeSet attrs) {
super(context, attrs);
moveVerticalScrollbarToTheLeft();
}
public ListViewWithLeftScrollBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
moveVerticalScrollbarToTheLeft();
}
@Override
public void invalidate(Rect r) {
invalidate(r.left, r.top, r.right, r.bottom);
}
@Override
public void invalidate(int left, int top, int right, int bottom) {
int width = right - left;
if (DEBUG) log("invalidate original w:"+ getWidth() +" h:"+ getHeight()+" rect:"+left+", "+top+", "+right+", "+bottom);
if (patchInvalidate && right == getWidth() && top == 0 && bottom == getHeight() && width < 30) {
// The above condition should ensure that ListView is VERY likely to be invalidating the scrollbar.
// In fact ListView appears to not invalidate anything except the scrollbar, ever.
left = 0;
right = left + width;
if (DEBUG) log("invalidate patched w:"+ getWidth() +" h:"+ getHeight()+" rect:"+left+", "+top+", "+right+", "+bottom);
}
super.invalidate(left, top, right, bottom);
}
private void moveVerticalScrollbarToTheLeft() {
try {
if (DEBUG) log("moveVerticalScrollbarToTheLeft: Trying API Level >=11");
tryApiLevel11();
if (DEBUG) log("moveVerticalScrollbarToTheLeft: API Level >=11 success");
} catch (Throwable t1) {
if (DEBUG) {
log("moveVerticalScrollbarToTheLeft: API Level >=11 FAILED");
t1.printStackTrace();
}
try {
if (DEBUG) log("moveVerticalScrollbarToTheLeft: Trying hack for API Level <11");
tryApiLevelPre11();
patchInvalidate = true;
if (DEBUG) log("moveVerticalScrollbarToTheLeft: API Level <11 hack success");
} catch (Throwable t2) {
if (DEBUG) {
log("moveVerticalScrollbarToTheLeft: API Level <11 hack FAILED");
t2.printStackTrace();
}
}
}
}
@SuppressLint("NewApi")
private void tryApiLevel11() {
setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT);
}
private void tryApiLevelPre11() throws Exception {
Class<?> viewClass = View.class;
Field scrollCacheField = viewClass.getDeclaredField("mScrollCache");
scrollCacheField.setAccessible(true);
Object scrollCache = scrollCacheField.get(this);
if (DEBUG) log("scrollCache: "+ scrollCache);
Field scrollBarField = scrollCache.getClass().getDeclaredField("scrollBar");
scrollBarField.setAccessible(true);
Object scrollBar = scrollBarField.get(scrollCache);
if (DEBUG) log("scrollBar: "+ scrollBar);
Field verticalThumbField = scrollBar.getClass().getDeclaredField("mVerticalThumb");
verticalThumbField.setAccessible(true);
Object verticalThumb = verticalThumbField.get(scrollBar);
if (DEBUG) log("verticalThumb: "+ verticalThumb);
Drawable verticalThumbDrawable = (Drawable) verticalThumb;
Drawable replacementVerticalThumbDrawable = new LayerDrawable(new Drawable[]{ verticalThumbDrawable }) {
@Override
public void setBounds(int left, int top, int right, int bottom) {
if (DEBUG) log("setBounds original: "+left+", "+top+", "+right+", "+bottom);
int width = right - left;
left = 0;
right = left + width;
if (DEBUG) log("setBounds patched: "+left+", "+top+", "+right+", "+bottom);
super.setBounds(left, top, right, bottom);
}
};
verticalThumbField.set(scrollBar, replacementVerticalThumbDrawable);
}
private static void log(String msg) {
Log.d(LOG_TAG, msg);
}
}
Я пробовал это на 2.2.1, и это не сработало. –
Ну, это работает, если я вызываю 'tryApiLevelPre11()' внутри тела 'if (Build.VERSION.SDK_INT
это также возможно с помощью XML: андроид: verticalScrollbarPosition = "левый" –
К сожалению, не работает в [NavigationView] (http://developer.android.com/intl/ru/reference/android/support/design/ widget/NavigationView.html) (API 23). – Luten