비슷한 요구 사항이있어서 얼마간 ActionBarDrawerToggle
코드를 사용했습니다. 현재 갖고있는 것이 최선의 방법입니다.
더
가 와서 :
애니메이션을 화살표로 햄버거 그릴 수 구현에 의해 제공됩니다 - DrawerArrowDrawableToggle
합니다. 현재 우리는이 드로어 블이 서랍 상태에 어떻게 반응하는지에 대해 많은 통제력을 가지고 있지 않습니다. 여기 actionVarDrawerToggle
의 패키지 액세스 생성자의 말씀입니다 :
/**
* In the future, we can make this constructor public if we want to let developers customize
* the
* animation.
*/
<T extends Drawable & DrawerToggle> ActionBarDrawerToggle(Activity activity, Toolbar toolbar,
DrawerLayout drawerLayout, T slider,
@StringRes int openDrawerContentDescRes,
@StringRes int closeDrawerContentDescRes)
slider
의 자신의 구현을 제공함으로써, 당신은 상태를 서랍에 반응하는 방법을 제어 할 수 있습니다. - 모든 서랍 상태 변화가 서랍 표시를 업데이트를 호출
/**
* Interface for toggle drawables. Can be public in the future
*/
static interface DrawerToggle {
public void setPosition(float position);
public float getPosition();
}
setPosition(float)
여기에 하이라이트 : slider
이 구현해야하는 인터페이스입니다.
원하는 동작을 위해 slider
구현의 setPosition(float position)
은 아무 작업도 수행하지 않습니다.
당신은 여전히 필요합니다
if (showHomeAsUp) {
mDrawerToggle.setDrawerIndicatorEnabled(false);
// Can be set in theme
mDrawerToggle.setHomeAsUpIndicator(R.drawable.lib_ic_arrow_back_light);
mDrawerToggle.setToolbarNavigationClickListener(view -> finish());
}
이 setDrawerIndicatorEnabled(false)
, 당신은 setToolbarNavigationClickListener(view -> finish());
설정 한 OnClickListener
가 발생하지 않습니다되지는 않는 경우.
우리가 할 수있는 일은 무엇입니까 지금?
더 자세히 살펴보면 귀하의 요구 사항이 ActionBarDrawerToggle
인 것으로 나타났습니다. 나는이 조항이 당신이 현재 가지고있는 것보다 훨씬 더 많은 해킹을 발견합니다. 하지만, 내가 결정하게 할께.
ActionBarDrawerToggle
Delegate을 통해 서랍 표시기를 통해 일부를 제어 할 수 있습니다. 당신은 당신의 활동이 다음과 같은 방식으로이 인터페이스를 구현할 수 있습니다 :
public class TheActivity extends ActionBarActivity implements ActionBarDrawerToggle.Delegate {
....
@Override
public void setActionBarUpIndicator(Drawable drawableNotUsed, int i) {
// First, we're not using the passed drawable, the one that animates
// Second, we check if `displayHomeAsUp` is enabled
final boolean displayHomeAsUpEnabled = (getSupportActionBar().getDisplayOptions()
& ActionBar.DISPLAY_HOME_AS_UP) == ActionBar.DISPLAY_HOME_AS_UP;
// We'll control what happens on navigation-icon click
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (displayHomeAsUpEnabled) {
finish();
} else {
// `ActionBarDrawerToggle#toggle()` is private.
// Extend `ActionBarDrawerToggle` and make provision
// for toggling.
mDrawerToggle.toggleDrawer();
}
}
});
// I will talk about `mToolbarnavigationIcon` later on.
if (displayHomeAsUpEnabled) {
mToolbarNavigationIcon.setIndicator(
CustomDrawerArrowDrawable.HOME_AS_UP_INDICATOR);
} else {
mToolbarNavigationIcon.setIndicator(
CustomDrawerArrowDrawable.DRAWER_INDICATOR);
}
mToolbar.setNavigationIcon(mToolbarNavigationIcon);
mToolbar.setNavigationContentDescription(i);
}
@Override
public void setActionBarDescription(int i) {
mToolbar.setNavigationContentDescription(i);
}
@Override
public Drawable getThemeUpIndicator() {
final TypedArray a = mToolbar.getContext()
.obtainStyledAttributes(new int[]{android.R.attr.homeAsUpIndicator});
final Drawable result = a.getDrawable(0);
a.recycle();
return result;
}
@Override
public Context getActionBarThemedContext() {
return mToolbar.getContext();
}
....
}
ActionBarDrawerToggle
가 여기에 제공된 setActionBarUpIndicator(Drawable, int)
을 사용합니다. Drawable
이 전달되는 것을 무시하므로 표시 할 내용을 완전히 제어 할 수 있습니다.
캐치 :
@Nullable
@Override
public ActionBarDrawerToggle.Delegate getV7DrawerToggleDelegate() {
return this;
}
: 당신이 당신의 활동에
getV7DrawerToggleDelegate()
를 오버라이드 (override) 할 필요가 있습니다,
public ActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout,
Toolbar toolbar, @StringRes int openDrawerContentDescRes,
@StringRes int closeDrawerContentDescRes) { .... }
을 그리고 : ActionBarDrawerToggle
우리가 여기 널 (null)로 Toolbar
매개 변수를 전달하는 경우 대리자 우리의 Activity
행동을 드릴 것입니다
알다시피 적절한 방법은 많은 추가 작업입니다. 그리고 우리는 아직 끝나지 않았습니다.
애니메이션 DrawerArrowDrawableToggle
은 these attributes을 사용하여 스타일을 지정할 수 있습니다. 당신이 당신의 당김 상태 (homeAsUp & 햄버거) 디폴트 같은 정확히을 원하는 경우에, 당신은 같은 그것을 구현해야합니다
/**
* A drawable that can draw a "Drawer hamburger" menu or an Arrow
*/
public class CustomDrawerArrowDrawable extends Drawable {
public static final float DRAWER_INDICATOR = 0f;
public static final float HOME_AS_UP_INDICATOR = 1f;
private final Activity mActivity;
private final Paint mPaint = new Paint();
// The angle in degress that the arrow head is inclined at.
private static final float ARROW_HEAD_ANGLE = (float) Math.toRadians(45);
private final float mBarThickness;
// The length of top and bottom bars when they merge into an arrow
private final float mTopBottomArrowSize;
// The length of middle bar
private final float mBarSize;
// The length of the middle bar when arrow is shaped
private final float mMiddleArrowSize;
// The space between bars when they are parallel
private final float mBarGap;
// Use Path instead of canvas operations so that if color has transparency, overlapping sections
// wont look different
private final Path mPath = new Path();
// The reported intrinsic size of the drawable.
private final int mSize;
private float mIndicator;
/**
* @param context used to get the configuration for the drawable from
*/
public CustomDrawerArrowDrawable(Activity activity, Context context) {
final TypedArray typedArray = context.getTheme()
.obtainStyledAttributes(null, R.styleable.DrawerArrowToggle,
R.attr.drawerArrowStyle,
R.style.Base_Widget_AppCompat_DrawerArrowToggle);
mPaint.setAntiAlias(true);
mPaint.setColor(typedArray.getColor(R.styleable.DrawerArrowToggle_color, 0));
mSize = typedArray.getDimensionPixelSize(R.styleable.DrawerArrowToggle_drawableSize, 0);
mBarSize = typedArray.getDimension(R.styleable.DrawerArrowToggle_barSize, 0);
mTopBottomArrowSize = typedArray
.getDimension(R.styleable.DrawerArrowToggle_topBottomBarArrowSize, 0);
mBarThickness = typedArray.getDimension(R.styleable.DrawerArrowToggle_thickness, 0);
mBarGap = typedArray.getDimension(R.styleable.DrawerArrowToggle_gapBetweenBars, 0);
mMiddleArrowSize = typedArray
.getDimension(R.styleable.DrawerArrowToggle_middleBarArrowSize, 0);
typedArray.recycle();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.SQUARE);
mPaint.setStrokeWidth(mBarThickness);
mActivity = activity;
}
public boolean isLayoutRtl() {
return ViewCompat.getLayoutDirection(mActivity.getWindow().getDecorView())
== ViewCompat.LAYOUT_DIRECTION_RTL;
}
@Override
public void draw(Canvas canvas) {
Rect bounds = getBounds();
final boolean isRtl = isLayoutRtl();
// Interpolated widths of arrow bars
final float arrowSize = lerp(mBarSize, mTopBottomArrowSize, mIndicator);
final float middleBarSize = lerp(mBarSize, mMiddleArrowSize, mIndicator);
// Interpolated size of middle bar
final float middleBarCut = lerp(0, mBarThickness/2, mIndicator);
// The rotation of the top and bottom bars (that make the arrow head)
final float rotation = lerp(0, ARROW_HEAD_ANGLE, mIndicator);
final float topBottomBarOffset = lerp(mBarGap + mBarThickness, 0, mIndicator);
mPath.rewind();
final float arrowEdge = -middleBarSize/2;
// draw middle bar
mPath.moveTo(arrowEdge + middleBarCut, 0);
mPath.rLineTo(middleBarSize - middleBarCut, 0);
final float arrowWidth = Math.round(arrowSize * Math.cos(rotation));
final float arrowHeight = Math.round(arrowSize * Math.sin(rotation));
// top bar
mPath.moveTo(arrowEdge, topBottomBarOffset);
mPath.rLineTo(arrowWidth, arrowHeight);
// bottom bar
mPath.moveTo(arrowEdge, -topBottomBarOffset);
mPath.rLineTo(arrowWidth, -arrowHeight);
mPath.moveTo(0, 0);
mPath.close();
canvas.save();
if (isRtl) {
canvas.rotate(180, bounds.centerX(), bounds.centerY());
}
canvas.translate(bounds.centerX(), bounds.centerY());
canvas.drawPath(mPath, mPaint);
canvas.restore();
}
@Override
public void setAlpha(int i) {
mPaint.setAlpha(i);
}
// override
public boolean isAutoMirrored() {
// Draws rotated 180 degrees in RTL mode.
return true;
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getIntrinsicHeight() {
return mSize;
}
@Override
public int getIntrinsicWidth() {
return mSize;
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
public void setIndicator(float indicator) {
mIndicator = indicator;
invalidateSelf();
}
/**
* Linear interpolate between a and b with parameter t.
*/
private static float lerp(float a, float b, float indicator) {
if (indicator == HOME_AS_UP_INDICATOR) {
return b;
} else {
return a;
}
}
}
CustomDrawerArrowDrawable's
구현 AOSP에서 빌려 만의 드로잉을 할 수 있도록 옷을 벗었되었습니다 두 상태 : homeAsUp & 햄버거. setIndicator(float)
을 호출하여 이러한 상태를 전환 할 수 있습니다. 우리가 구현 한 Delegate
에서 이것을 사용합니다. 또한 CustomDrawerArrowDrawable
을 사용하면 xml : barSize
, color
등으로 스타일을 지정할 수 있습니다.이 설정이 필요하지 않더라도 위의 구현을 사용하면 드로어 열기 및 닫기에 맞춤 애니메이션을 제공 할 수 있습니다.
내가 이것을 추천해야 할지를 솔직하게 알 수 있습니다.
<item name="android:homeAsUpIndicator">@drawable/some_back_drawable</item>
는 현재이 ToolbarCompatDelegate#getThemeUpIndicator()
에 있기 때문에 가능한 버그 발생하지 않습니다 :
@Override
public Drawable getThemeUpIndicator() {
final TypedArray a = mToolbar.getContext()
// Should be new int[]{android.R.attr.homeAsUpIndicator}
.obtainStyledAttributes(new int[]{android.R.id.home});
final Drawable result = a.getDrawable(0);
a.recycle();
return result;
}
당신이 인수
null
와
ActionBarDrawerToggle#setHomeAsUpIndicator(...)
를 호출 할 경우
, 그것은 당신의 테마에 정의 된 드로어 블을 선택해야
이 문제에 대해 대충 설명하는 버그 보고서 (사례 4 읽기) : Link
당신이 이미 가지고있는 솔루션을 고수하기로 결정하면, PNG 파일 대신에 (R.drawable.lib_ic_arrow_back_light & R.drawable.lib_ic_menu_light)를 CustomDrawerArrowDrawable
사용을 고려하시기 바랍니다. 밀도/크기 버킷에는 여러 드로어 블이 필요하지 않으며 XML로 스타일링이 수행됩니다. 또한 최종 제품은 프레임 워크와 동일합니다.
mDrawerToggle.setDrawerIndicatorEnabled(false);
CustomDrawerArrowDrawable toolbarNavigationIcon
= new CustomDrawerArrowDrawable(this, mToolbar.getContext());
if (showHomeAsUp) {
toolbarNavigationIcon.setIndicator(
CustomDrawerArrowDrawable.HOME_AS_UP_INDICATOR);
mDrawerToggle.setToolbarNavigationClickListener(view -> finish());
} else {
mToolbarNavigationIcon.setIndicator(
CustomDrawerArrowDrawable.DRAWER_INDICATOR);
mDrawerToggle.setToolbarNavigationClickListener(view -> toggleDrawer());
}
mDrawerToggle.setHomeAsUpIndicator(toolbarNavigationIcon);
을하지만 뒤로 화살표는 화면 회전 후 볼 수 있습니다. 서랍을 열고, 화면을 회전하고, 서랍을 닫습니다. 햄버거가 아닌 뒤쪽 화살표가 보입니다. – tomrozb
재현 할 수 없습니다. 다른 코드가이 사건과 관련이있는 것 같습니다. –
onDrawerOpened/Closed에서 onPostCreate에서 mDrawerToggle.syncState()를 호출하고 invalidateOptionsMenu()를 호출합니다. 당신은 또한이 방법들을 부릅니까? – tomrozb