Skip to content

Instantly share code, notes, and snippets.

@tobiasschuerg
Last active August 21, 2019 12:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tobiasschuerg/9186a955ae8e11366701a24f1a447af9 to your computer and use it in GitHub Desktop.
Save tobiasschuerg/9186a955ae8e11366701a24f1a447af9 to your computer and use it in GitHub Desktop.
Activity which let's you easily color toolbar, its back button and overflow menu items
import android.annotation.SuppressLint;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatImageView;
import android.support.v7.widget.AppCompatTextView;
import android.support.v7.widget.Toolbar;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import java.util.ArrayList;
/**
* {@link android.app.Activity} which supports quick and easy customizations.
* <p>
* Needs a {@link Toolbar} and optionally a {@link CollapsingToolbarLayout}
* <p>
* Created by Tobias Schürg on 14.11.2016.
*/
public abstract class EasyColorableActivity extends AppCompatActivity {
private Toolbar toolbar;
@Nullable private CollapsingToolbarLayout collapsingToolbarLayout;
@Nullable private AppBarLayout appbarLayout;
private Integer foregroundColor;
@Override
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getTopView(); // make sure view is set up correctly
}
@NonNull
private View getTopView() {
if (toolbar != null) {
return toolbar;
} else if (collapsingToolbarLayout != null) {
return collapsingToolbarLayout;
} else {
throw new NullPointerException(
"No toolbar set! Call setToolbar(toolbar) or setToolbar(collapsingToolbarLayout) during onCreate");
}
}
/**
* For the use with just a 'simple' {@link Toolbar}
*/
protected void setToolbar(@NonNull Toolbar toolbar) {
setToolbar(toolbar, null, null);
}
/**
* For the use with a collapsing toolbar.
*/
protected void setToolbar(@NonNull Toolbar toolbar, CollapsingToolbarLayout collapsingToolbarLayout, AppBarLayout appBarLayout) {
this.toolbar = toolbar;
this.collapsingToolbarLayout = collapsingToolbarLayout;
this.appbarLayout = appBarLayout;
}
protected void setBarBackgroundColor(@ColorInt int color) {
// status bar
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(ColorHelper.darken(color));
}
// actionbar
if (appbarLayout != null) {
appbarLayout.setBackgroundColor(color);
} else {
toolbar.setBackgroundColor(color);
}
setSupportActionBar(toolbar);
ActionBar actionbar = getSupportActionBar();
if (actionbar != null) {
actionbar.setHomeButtonEnabled(true);
actionbar.setDisplayHomeAsUpEnabled(true);
}
}
@SuppressLint("PrivateResource")
protected void setBarForegroundColor(@ColorInt int color) {
foregroundColor = color;
if (collapsingToolbarLayout != null) {
collapsingToolbarLayout.setCollapsedTitleTextColor(color);
} else if (toolbar != null) {
toolbar.setTitleTextColor(color);
}
ActionBar actionbar = getSupportActionBar();
if (actionbar != null) {
Drawable upArrow = ContextCompat.getDrawable(this, android.support.v7.appcompat.R.drawable.abc_ic_ab_back_material);
upArrow.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
actionbar.setHomeAsUpIndicator(upArrow);
}
setOverflowButtonColor(color);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
for (int i = 0; i < menu.size(); i++) {
final MenuItem item = menu.getItem(i);
final CharSequence itemTitle = item.getTitle();
SpannableString s = new SpannableString(itemTitle);
s.setSpan(new ForegroundColorSpan(Color.DKGRAY), 0, s.length(), 0);
item.setTitle(s);
AppCompatTextView tv = new AppCompatTextView(getApplicationContext());
LinearLayout.LayoutParams params = new LinearLayout
.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT,
1f);
tv.setPadding(dpToPx(8), 0, dpToPx(8), 0);
tv.setLayoutParams(params);
tv.setGravity(Gravity.CENTER);
tv.setText(itemTitle.toString());
tv.setTextAppearance(this, android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Menu);
tv.setTextColor(foregroundColor);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onOptionsItemSelected(item);
}
});
addRippleEffect(tv);
item.setActionView(tv);
}
return super.onCreateOptionsMenu(menu);
}
private void addRippleEffect(View view) {
int[] attrs = new int[]{R.attr.selectableItemBackgroundBorderless};
TypedArray typedArray = obtainStyledAttributes(attrs);
Drawable drawable = typedArray.getDrawable(0);
view.setBackground(drawable);
typedArray.recycle();
view.setClickable(true);
view.setFocusable(true);
}
/**
* Changes the color of the overflow dots.
* Great cinema ^^
* Based on http://stackoverflow.com/a/36278375/570168
*/
public void setOverflowButtonColor(final int color) {
@SuppressLint("PrivateResource") final String overflowDescription = getString(R.string.abc_action_menu_overflow_description);
final ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
final ArrayList<View> outViews = new ArrayList<>();
decorView.findViewsWithText(outViews, overflowDescription, View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if (outViews.isEmpty()) {
return;
}
for (View outView : outViews) {
AppCompatImageView overflow = (AppCompatImageView) outView;
overflow.setColorFilter(color);
}
}
});
}
public static int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment