Toolbar
をハンバーガーで逆矢印アニメーションに実装するのは非常に簡単です。私の意見では、このアニメーションは無意味です。なぜなら、マテリアルデザイン仕様に従って、ナビゲーションドロワーは開いたときにToolbar
をカバーするからです。私の質問は、このアニメーションを適切に無効にして、getSupportActionBar().setDisplayHomeAsUpEnabled(true);
を使用してハンバーガーまたは戻る矢印を表示する方法です。
これは私がそれをやった方法ですが、汚いハックのように見えます:
mDrawerToggle.setDrawerIndicatorEnabled(false);
if (showHomeAsUp) {
mDrawerToggle.setHomeAsUpIndicator(R.drawable.lib_ic_arrow_back_light);
mDrawerToggle.setToolbarNavigationClickListener(view -> finish());
} else {
mDrawerToggle.setHomeAsUpIndicator(R.drawable.lib_ic_menu_light);
mDrawerToggle.setToolbarNavigationClickListener(view -> toggleDrawer());
}
ハンバーガーと戻る矢印アイコンを切り替えるためにsetDisplayHomeAsUpEnabled
だけを使用するためにこれを適切に実装する方法の手がかりはありますか?
これにより、drawerToggleの作成時にアニメーションが無効になり、onDrawerSlide()がオーバーライドされます。
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout,
getToolbar(), R.string.open, R.string.close) {
@Override
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
}
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, 0); // this disables the animation
}
};
矢印を完全に削除する場合は、追加できます
super.onDrawerSlide(drawerView, 0); // this disables the arrow @ completed state
onDrawerOpened関数の最後。
私の意見では、このアニメーションは無意味です
まあ、ActionBarDrawerToggle
はアニメーション化するためのものです。
ActionBarテーマでdrawerArrowStyleを定義することにより、animatedトグルをカスタマイズできます。
SetDisplayHomeAsUpEnabledを使用してハンバーガーと戻る矢印アイコンを切り替えるために、これを適切に実装する手がかりはありますか?
ActionBarDrawerToggle
は、単に _ActionBar.setHomeAsUpIndicator
_ を呼び出すための派手な方法です。そのため、いずれにしても、表示するには_ActionBar.setDisplayHomeAsUpEnabled
_をtrue
に呼び出す必要があります。
使用する必要があると確信している場合は、それぞれ ActionBarDrawerToggle.onDrawerOpened(View drawerView)
および ActionBarDrawerToggle.onDrawerClosed(View drawerView)
を呼び出すことをお勧めします。
これにより、 DrawerIndicator
の位置が_1
_または_0
_に設定され、矢印と DrawerArrowDrawable
のハンバーガー状態が切り替わります。
そして、あなたの場合、ActionBarDrawerToggle
を _DrawerLayout.DrawerListener
_ としてアタッチする必要さえありません。次のように:
_mYourDrawer.setDrawerListener(mYourDrawerToggle);
_
しかし、はるかに前向きなアプローチは、_ActionBar.setHomeAsUpIndicator
_を一度呼び出して、独自のハンバーガーアイコンを適用することです。これは、スタイルを介して行うこともできます。次に、戻る矢印を表示する場合は、_ActionBar.setDisplayHomeAsUpEnabled
_を呼び出して、AppCompatまたはフレームワークに残りを処理させます。あなたが行ったコメントから、私はこれがあなたが探しているものであると確信しています。
どのアイコンを使用するのかわからない場合は、 デフォルトのDrawerArrowDrawable
サイズは_24dp
_ です。つまり、_ic_menu_white_24dp
_または_ic_menu_black_24dp
_を取得します。 ナビゲーションアイコンセット Googleの公式マテリアルデザインアイコンパック。
DrawerArrowDrawable
をプロジェクトにコピーして、必要に応じて矢印またはハンバーガーの状態を切り替えることもできます。自己完結型で、いくつかのリソースがありません。
これは、すべてのフラグメントのonActivityCreatedコールバックで呼び出すNavigationDrawerFragmentにあるActionBarDrawableToggleを制御するための私の関数です。投稿機能が必要です。ハンバーガーのアイコンが戻る矢印に変わり、戻る矢印がクリック可能になります。向きの変更は、ハンドラーによって適切に処理されます。
...
import Android.support.v7.app.ActionBar;
import Android.support.v7.app.ActionBarActivity;
import Android.support.v7.app.ActionBarDrawerToggle;
...
public class NavigationDrawerFragment extends Fragment
{
private ActionBarDrawerToggle mDrawerToggle;
...
public void syncDrawerState()
{
new Handler().post(new Runnable()
{
@Override
public void run()
{
final ActionBar actionBar = activity.getSupportActionBar();
if (activity.getSupportFragmentManager().getBackStackEntryCount() > 1 && (actionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != ActionBar.DISPLAY_HOME_AS_UP)
{
new Handler().post(new Runnable()
{
@Override
public void run()
{
mDrawerToggle.setDrawerIndicatorEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(true);
mDrawerToggle.setToolbarNavigationClickListener(onToolbarNavigationClickListener());
}
});
} else if (activity.getSupportFragmentManager().getBackStackEntryCount() <= 1 && (actionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) == ActionBar.DISPLAY_HOME_AS_UP)
{
actionBar.setHomeButtonEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(false);
mDrawerToggle.setDrawerIndicatorEnabled(true);
mDrawerToggle.syncState();
}
}
});
}
}
これは、ベースフラグメントのonActivityCreatedメソッドです。
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
navigationDrawerFragment.syncDrawerState();
}
同様の要件があり、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
の独自の実装を提供することにより、引き出しの状態に対する反応を制御できます。 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
実装の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
は起動しません。
正しいことは何ですかnow?
よく調べてみると、ActionBarDrawerToggle
に要件の規定があることがわかりました。私は、この規定があなたが現在持っているものよりもさらにハッキングだと思います。しかし、私はあなたに決めさせます。
ActionBarDrawerToggle
を使用すると、インターフェイス デリゲート を介してドロワーインジケータをsome制御できます。次の方法で、アクティビティにこのインターフェイスを実装できます。
_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
を無視しているため、表示されるものを完全に制御できます。
キャッチ:ActionBarDrawerToggle
パラメータをnullとしてここに渡すと、Activity
はToolbar
をデリゲートとして機能させます。
_public ActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout,
Toolbar toolbar, @StringRes int openDrawerContentDescRes,
@StringRes int closeDrawerContentDescRes) { .... }
_
また、アクティビティでgetV7DrawerToggleDelegate()
をオーバーライドする必要があります。
_@Nullable
@Override
public ActionBarDrawerToggle.Delegate getV7DrawerToggleDelegate() {
return this;
}
_
ご覧のとおり、適切な方法で作業を行うには多くの追加作業が必要です。そして、まだ完了していません。
アニメーション化DrawerArrowDrawableToggle
は、 これらの属性 を使用してスタイル設定できます。デフォルトのように描画可能な状態(homeAsUpハンバーガー)exactlyが必要な場合は、次のように実装する必要があります。
_/**
* 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から借用され、2つの状態(homeAsUpハンバーガー)のみを描画できるように削除されました。 setIndicator(float)
を呼び出すことにより、これらの状態を切り替えることができます。これを実装したDelegate
で使用します。さらに、CustomDrawerArrowDrawable
を使用すると、xmlでスタイルを設定できます:barSize
、color
など。これは必要ありませんが、上記の実装により、引き出しの開閉にカスタムアニメーションを提供できます。
私はこれを推薦すべきかどうか正直に知りません。
引数null
を指定してActionBarDrawerToggle#setHomeAsUpIndicator(...)
を呼び出す場合、テーマで定義されたドロウアブルを選択する必要があります。
_<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;
}
_
これについて大まかに説明しているバグレポート(ケース4をお読みください): Link
すでに持っているソリューションを使用することにした場合は、pngs(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);
_
アニメーションを無効にする専用の方法があります:toggle.setDrawerSlideAnimationEnabled(false)
私が使用するスニペットは次のとおりです。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
[...]
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
toggle.setDrawerSlideAnimationEnabled(false);
drawer.addDrawerListener(toggle);
toggle.syncState();
}
onDrawerSlide()
メソッドで夕食の呼び出しを無効にすると、ArrowとBurgerの間のアニメーションが停止します。ドロワーが完全に開いているか完全に閉じている場合にのみ、切り替えが表示されます(アニメーションなし)。
mActionBarDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.open, R.string.closed) {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
//super.onDrawerSlide(drawerView, slideOffset);
}
};
mDrawerLayout.setDrawerListener(mActionBarDrawerToggle);