Как показать DrawerLayout при скольжении слева направо, независимо от того, где?
фон
Google представил DrawerLayout, который показывает меню в левой части экрана, когда вы нажимаете кнопку "вверх" на панели действий.
поскольку библиотека еще не поддерживается в actionBarSherlock, уже есть способ преодолеть ее с помощью этого проекта.
у него уже есть варианты во многих приложениях: токи, Gmail, видеовстречи, YouTube...
вопрос
в приложении "токи" (и в YouTube), когда пользователь перемещает (левую) страницу слева направо, появляется DrawerLayout, независимо от того, где палец начал касание.
Как я могу достичь того же эффекта? возможно я должен использовать onInterceptTouchEvent?
не так много документации и учебных пособий о том, что можно сделать, кроме этой ссылки (хорошо, и эта тоже) . они говорят (в части "Дайте пользователю быстрый взгляд"), что для этой функциональности используется около 20dp слева, но я вижу, что "токи" работают с гораздо большей площадью.
кажется, что библиотека еще не совсем закончена, и поэтому XML-файл макета не может быть даже показан в визуальном редакторе пользовательского интерфейса...
РЕДАКТИРОВАТЬ: кажется, что библиотека с открытым исходным кодом. код доступен на:
.../android-sdk\sources\android-18\android\support\v4\widget\DrawerLayout.java
.../android-sdk\sources\android-18\android\support\v4\widget\SlidingPaneLayout.java
.../android-sdk\sources\android-18\android\support\v4\app\ActionBarDrawerToggle.java
Теперь вопрос заключается в том, как заставить его работать так, как я написал, чтобы он работал так же, как на youtube, что позволяет нам настраивать его внешний вид и откуда его прокручивать.
8 ответов
SlidingMenu - лучшая библиотека слайдов, которую я когда-либо нашел. Это очень хорошая библиотека.
Вы можете установить getSlidingMenu().setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN)
Включение броска для всего экрана.
Проблема в том, что DrawerLayout использует ViewDragHelper, который имеет EDGE_SIZE по умолчанию 20dp, который используется для вычисления mEdgeSize следующим образом:
mEdgeSize = (int) (EDGE_SIZE * density + 0.5f);
Вот функция, которая устанавливает mEdgeSize в процентах от ширины экрана:
public static void setDrawerLeftEdgeSize(Activity activity, DrawerLayout drawerLayout, float displayWidthPercentage) {
if (activity == null || drawerLayout == null)
return;
try {
// find ViewDragHelper and set it accessible
Field leftDraggerField = drawerLayout.getClass().getDeclaredField("mLeftDragger");
leftDraggerField.setAccessible(true);
ViewDragHelper leftDragger = (ViewDragHelper) leftDraggerField.get(drawerLayout);
// find edgesize and set is accessible
Field edgeSizeField = leftDragger.getClass().getDeclaredField("mEdgeSize");
edgeSizeField.setAccessible(true);
int edgeSize = edgeSizeField.getInt(leftDragger);
// set new edgesize
Point displaySize = new Point();
activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
edgeSizeField.setInt(leftDragger, Math.max(edgeSize, (int) (displaySize.x * displayWidthPercentage)));
} catch (NoSuchFieldException e) {
// ignore
} catch (IllegalArgumentException e) {
// ignore
} catch (IllegalAccessException e) {
// ignore
}
}
Итак, предположим, что вы хотите, чтобы 30% левого края реагировали на события слайдов и открывали Навигационный ящик, а затем просто вызывайте:
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
setDrawerLeftEdgeSize(this, mDrawerLayout, 0.3f);
Я попытался изменить стандартное решение EDGE_SIZE и столкнулся с проблемой длинных нажатий. Наконец, Ifound переопределяет dispatchTouchEvent и открывает ящик в зависимости от направления скольжения, вычисляя смещение X.
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
startX = ev.getX();
startY = ev.getY();
break;
case MotionEvent.ACTION_UP:
endX = ev.getX();
endY = ev.getY();
float sensitivity = 5;
// From left to right
if (endX - startX >= sensitivity) {
if (mDrawerLayout.isDrawerOpen(Gravity.RIGHT)) {
mDrawerLayout.closeDrawer(Gravity.RIGHT);
} else {
mDrawerLayout.openDrawer(Gravity.LEFT);
}
}
// From right to left
if (startX - endX >= sensitivity) {
if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
mDrawerLayout.closeDrawer(Gravity.LEFT);
} else {
mDrawerLayout.openDrawer(Gravity.RIGHT);
}
}
break;
}
Используя чужую помощь: (первая) (вторая)
Я обнаружил, что с помощью отражений можно изменить значение по умолчанию 20dp-screen-edge, чтобы меню ящика скользило
После объявления содержимого и ящиков, вы можете сделать это:
public class MainActivity extends Activity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
// set a custom shadow that overlays the main content when the drawer opens
mDrawerLayout.setDrawerShadow(R.drawable.your_drawer_shadow, GravityCompat.START);
// set up the drawer's list view with items and click listener
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.your_drawer_list, yourItems));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// enable ActionBar app icon to behave as action to toggle nav drawer
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
Field mDragger = null;
try {
mDragger = mDrawerLayout.getClass().getDeclaredField(
"mLeftDragger"); //mRightDragger for right obviously
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mDragger.setAccessible(true);
ViewDragHelper draggerObj = null;
try {
draggerObj = (ViewDragHelper) mDragger
.get(mDrawerLayout);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Field mEdgeSize = null;
try {
mEdgeSize = draggerObj.getClass().getDeclaredField(
"mEdgeSize");
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mEdgeSize.setAccessible(true);
int edge = 0;
try {
edge = mEdgeSize.getInt(draggerObj);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
mEdgeSize.setInt(draggerObj, edge * 5); //optimal value as for me, you may set any constant in dp
//You can set it even to the value you want like mEdgeSize.setInt(draggerObj, 150); for 150dp
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon
mDrawerToggle = new ActionBarDrawerToggle(
this, /* host Activity */
mDrawerLayout, /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
R.string.drawer_open, /* "open drawer" description for accessibility */
R.string.drawer_close /* "close drawer" description for accessibility */
) {
public void onDrawerClosed(View view) {
}
public void onDrawerOpened(View drawerView) {
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
}
Ну, это работает для меня человек!
Вы можете использовать это с Навигационным Ящиком
DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
Field mDragger = mDrawerLayout.getClass().getDeclaredField(
"mLeftDragger");//mRightDragger or mLeftDragger based on Drawer Gravity
mDragger.setAccessible(true);
ViewDragHelper draggerObj = (ViewDragHelper) mDragger
.get(mDrawerLayout);
Field mEdgeSize = draggerObj.getClass().getDeclaredField(
"mEdgeSize");
mEdgeSize.setAccessible(true);
int edge = mEdgeSize.getInt(draggerObj);
mEdgeSize.setInt(draggerObj, edge * 3);
Когда мы переопределяем сторону края по умолчанию, наш экран той части, на которой он перекрывается, перестает работать, я использовал приведенный выше код в viewpager, но теперь, когда я прокручиваю влево-направо, вместо перехода на следующую страницу просмотра, он остается постоянным. Каково будет решение для этого? я использовал setDrawerLeftEdgeSize(this,mDrawerLayout,distance );
public static void setDrawerLeftEdgeSize(Activity activity,
DrawerLayout drawerLayout, float displayWidthPercentage) {
if (activity == null || drawerLayout == null)
return;
try {
// find ViewDragHelper and set it accessible
Field leftDraggerField = drawerLayout.getClass().getDeclaredField(
"mLeftDragger");
leftDraggerField.setAccessible(true);
ViewDragHelper leftDragger = (ViewDragHelper) leftDraggerField
.get(drawerLayout);
// find edgesize and set is accessible
Field edgeSizeField = leftDragger.getClass().getDeclaredField(
"mEdgeSize");
edgeSizeField.setAccessible(true);
int edgeSize = edgeSizeField.getInt(leftDragger);
// set new edgesize
Point displaySize = new Point();
activity.getWindowManager().getDefaultDisplay()
.getSize(displaySize);
edgeSizeField.setInt(leftDragger, Math.max(edgeSize,
(int) (displaySize.x * displayWidthPercentage)));
} catch (NoSuchFieldException e) {
// ignore
} catch (IllegalArgumentException e) {
// ignore
} catch (IllegalAccessException e) {
// ignore
}
}
так же, как и выше..
Используя этот проект SlidingMenu, вы можете добиться этого эффекта и интегрироваться с ActionBarSherlock.
Чтобы сдвинуть меню слева направо, просто настройте меню при его создании и добавьте:
slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN);
Надеюсь это поможет.
Во-первых, я не уверен, что вы имеете в виду, что ActionBarSherlock не поддерживает DrawerLayout. Вы можете работать с DrawerLayout и ActionBarSherlock довольно счастливо, у меня есть приложения, которые используют эту комбинацию. Вам нужно будет изменить версию jar поддержки, но я обнаружил, что у ActionbarSherlock нет проблем с этим.
Реализуйте DrawerLayout обычным способом. Затем в своем фрагменте реализуйте onTouchEvent или interceptTouchEvent, а когда тип является событием типа "перемещение", скользящим слева направо, вы можете вызвать метод openDrawer в DrawerLayout. Вам нужно будет добавить обработку для расстояния, которое проходит палец, чтобы убедиться, что вызов, чтобы открыть ящик, не был слишком чувствительным.