I have been struggling with this for a few days now, i have tried lots of the articles on SO and none seem to match my requirements, i have set the Toolbar.xml and set the theme as below
<style name="ToolbarStyle" parent="Theme.AppCompat.Light">
<!-- Customize color of navigation drawer icon and back arrow -->
<item name="colorControlNormal">#color/white</item>
</style>
This works on a per app basis, but i need to alternate between white and black arrows depending on the content page i am on, i have tried custom renderers as well but this doesn't work dynamically as well
Any pointers massively appreciated, even if i can clarify, is the Xamarin forms navigation a Toolbar or an ActionBar?
Cheers
Anthony
is the Xamarin forms navigation a Toolbar or an ActionBar?
It is a Toolbar and not an ActionBar
Android.Support.V7.Widget.Toolbar
You can set the color via the ToolBar.NavigationIcon.SetColorFilter(...), but you have to find it first as Xamarin is not applying it via SetSupportActionBar...
Red backbutton PlatformEffect example:
public class RedBackButtonColorNameEffect : PlatformEffect
{
protected override void OnAttached()
{
void ViewGroups(ViewGroup viewGroup)
{
for (int i = 0; i < viewGroup.ChildCount; i++)
{
Android.Views.View v = viewGroup.GetChildAt(i);
switch (v)
{
case Toolbar tb:
tb.NavigationIcon?.SetColorFilter(viewGroup.Resources.GetColor(Android.Resource.Color.HoloRedDark), PorterDuff.Mode.SrcAtop);
return;
case ViewGroup vg:
ViewGroups(vg);
break;
}
}
}
var rootView = (Control.Context as AppCompatActivity).FindViewById(Android.Resource.Id.Content).RootView as ViewGroup;
ViewGroups(rootView);
}
protected override void OnDetached()
{
}
}
Usage:
someControl.Effects.Add(Effect.Resolve("Effects.RedBackButtonColorNameEffect"));
(remember set your ResolutionGroupName & ExportEffect attributes...)
Note: Xamarin does not apply a value for the Control instance within a PlatformEffect if you attach the effect at the page level or a container level and thus this will not work. You could store the Activity context somewhere (static var) from the MainActivity in order to workaround that issue and thus have the proper Context to search within, your choice..
Note!: PlatformEffects are whack in so many ways, especially since they never get garage collected and thus are a memory leak, they are nice for a quick example/prototype, but use a custom renderer for production code).
Related
Since Android released the new Splash Screen API with Android 12, a lot of apps had issues with duplicate splash screens, lack of customization, etc.
Right now, it is possible to set the background color and icon in the middle of it, but is it possible to customize it a bit more? Since right now we are limited to use single-colored background and non-resizable logo icon which doesn't look quite good.
What I'm trying to achieve is a custom splash screen, with an image drawable as background (or layer-list with 2 items - one background image and one centered logo), as it could be used before Android 12.
Did someone succeed to achieve this type of behavior?
There is a workaround to set windowIsTranslucent attribute to true and show only the second splash (the right one), but it introduces bad UX since it seems like the app is not responding for a few seconds.
Short answer is No, but here in my answer you can find more info:
Android: How to set a drawable as a windowSplashScreenBackground parameter in the new SplashScreen API?
I did something like this.
First remove default drawable
<style name="Theme.App.Starting" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">#color/...</item>
<item name="windowSplashScreenAnimatedIcon">#android:color/transparent</item>
<item name="postSplashScreenTheme">#style/AppTheme</item>
</style>
Then inflate your custom splash view
class MainActivity : AppCompatActivity(), SplashScreen.OnExitAnimationListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val installSplashScreen = installSplashScreen()
installSplashScreen.setOnExitAnimationListener(this)
setContentView(R.layout.activity_main)
}
override fun onSplashScreenExit(splashScreenViewProvider: SplashScreenViewProvider) {
val view = splashScreenViewProvider.view
if (view is ViewGroup) {
val binding = ActivityMainSplashBinding.inflate(layoutInflater,view, true)
// Do what you want with your inflated view
animate(view) {
// Remove splash
splashScreenViewProvider.remove()
}
}
}
private fun animate(view: View, doOnFinish: () -> Unit) {
view.animate()
.withEndAction(doOnFinish)
.start()
}
}
At the end remember to call splashScreenViewProvider.remove() to remove splash.
I'm using NativeScript with Angular, and I can't seem to change the StatusBar color in my project or set it to transparent (any of these would be fine). Instead, it is not totally transparent, but is translucent black, so the background scrolls behind it but it is darkened by the StatusBar. I would like to set it to transparent or to change the color (to the same one as the page background)
What I've tried:
Changing the "ns_primaryDark" and "ns_primary" colors in App_Resources/Android/src/main/res/values/colors.xml (works on launch screen if i set the TranslucentStatus" to false;
Setting <item name="android:windowTranslucentStatus"></item> in <style name="AppThemeBase" parent="Theme.AppCompat.Light.NoActionBar"> in App_Resources/Android/src/main/res/values/styles.xml doesn't make any difference, despite working fine on <style name="LaunchScreenThemeBase" parent="Theme.AppCompat.Light.NoActionBar"> (the launch screen);
Setting <item name="android:windowLightStatusBar">true</item> changes the text color to black and works on both the launch screen and the main app;
Using the code below in any component's constructor doesn't change anything in my app, but it worked on the other project i tried (details below), setting the color to black:
let window = app.android.startActivity.getWindow();
window.setStatusBarColor(new Color("black").android);
One thing i also tried was doing these steps on another project i had downloaded (https://github.com/NativeScript/nativescript-ui-samples/tree/master/chart this one, to be exact) and it worked, so i thought the template i used in my application might be "overlaying" any settings for the StatusBar.
I then tried to make a new project with the same template as mine and i figured out that it didn't work either. Is the template my problem? If so, is there any way to get around it?
The template i used is this one: https://github.com/NativeScript/nativescript-app-templates/tree/master/packages/template-tab-navigation-ng (also works with "tns create my-app-name --template tns-template-tab-navigation-ng").
Big thanks in advance.
Add the following code to your main.ts, that should do the job.
import * as application from "tns-core-modules/application";
declare var android;
application.android.on(application.AndroidApplication.activityCreatedEvent, (event) => {
const activity = event.activity;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
activity.getWindow().setStatusBarColor(android.graphics.Color.TRANSPARENT);
} else {
activity.getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
const parent = activity.findViewById(android.R.id.content);
for (let i = 0; i < parent.getChildCount(); i++) {
const childView = parent.getChildAt(i);
if (childView instanceof android.view.ViewGroup) {
childView.setFitsSystemWindows(true);
childView.setClipToPadding(true);
}
}
});
It's pretty much as in the library. If you like to use the library, you will have to include it in your app grad and access the StatusBarUtil class.
You can use this library to transparent your status bar Library
compile 'com.jaeger.statusbarutil:library:1.4.0'
To make any specific activity to transparent you can simply use this
StatusBarUtil.setTransparent(Activity activity)
It will look like this
I am working with an activity that has a few different stages. It is designed like a wizard so a few sections of it are tutorial like pages where I hide the toolbar and status bar. The Activity starts off with the toolbar hidden. In each of the fragments, I have an onToolbarShown(ActionBar ab) (called in the base fragments onStart() method) which I use to edit the title, if the back button shows etc, and then I call the showToolbar method below:
public void showSystemUi(boolean show){
if(show){
KKDeviceUtil.showSystemUI(mRootLayout);
}else {
KKDeviceUtil.hideSystemUI(mRootLayout);
}
}
#Override
public void showToolbar(boolean show){
if(getSupportActionBar() != null){
showSystemUi(show);
if(show) {
mRootLayout.setFitsSystemWindows(true);
getSupportActionBar().show();
}else{
getSupportActionBar().hide();
mRootLayout.setFitsSystemWindows(false);
}
}
}
(showSystemUi is the stock show/hide method suggested by android here)
The problem is that the first time I show the toolbar, the status bar is the wrong colour and the layout is shunted down by the height of the status bar. As seen here:
When I next switch fragments, the problem clears up:
And if I go back to the previous fragment, it looks correct:
I don't get this problem if I never hide the toolbar/system windows in the first place. I originally had some of the operations in a different order and thought that re-arranging them could help, but It didn't seem to make any difference. I also tried calling setStatusBarColor but that had no effect. I also have <item name="android:statusBarColor">#color/status_bar_color</item> in my v21/styles.xml which is the correct colour for my status bar, and my primaryDark is the same colour as the screenshot (buggy) above shows.
I can't seem to find what I am doing wrong here, is this the correct way to show/hide my toolbar/system ui and why does this only happen on the first showing of the toolbar?
(Note: it is hard to see from the screenshots, but in the first screenshot, the 'Done' button is much closer to the bottom than the correct placing in the third screenshot)
Please see below i've shown you demo style that will reflect color on the status bar.
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/side_bar_color</item>
<item name="colorPrimaryDark">#color/side_bar_color</item>
<item name="colorAccent">#color/side_bar_color</item>
</style>
There "colorPrimaryDark" is that color which will used at status bar, you need to set this style to your application or activity at manifest class
My question is more or less similar to this question, but the response approved as the answer for the same doesn't solve my issue.
I'm implementing tab structures using the FragmentTabHost class. When the tab background color is not explicitly specified, the tab indicator line seems to appear as Android provides. But when I programatically change the tab's background color, the tab indicators disappear (hidden).
Currently, I assign the tab background color this way :
private void customizeTabbs() {
for (int i = 0; i < mTabHost.getTabWidget().getTabCount(); i++) {
View tabChild= mTabHost.getTabWidget().getChildAt(i);
..
..
tabChild.setBackgroundResource(someColorResource);
}
}
I also tried to change the background color in the XML way by adding to styles.xml , following this as:
<item name="tabBackground">#color/someColor</item>
<item name="tabIndicatorColor">?#color/someOtherColor</item>
The solution suggested for one similar question also did not help me.
After updating Android Support Libary v7 AppCompat
I'm not able to change style to the title and the following
is not wotking anymore:
int myTitleId = Resources.GetIdentifier("action_bar_title", "id", "android");
TextView barTitle = FindViewById<TextView>(myTitleId);
barTitle.SetTypeface(FontFactory.GetMyFont(this), TypefaceStyle.Normal);
That's because AppCompat now uses a ToolBar widget as replacement for ActionBar. ToolBar creates a TextView instance for the title on-the-fly; if you dig into the (android.support.v7.widget.)ToolBar code, you'll find something like this:
mTitleTextView = new TextView(context);
(Refer to line 607 of android.support.v7.widget.ToolBar in appcompat-v7-23.0.1-sources.jar)
More importantly, no id is ever assigned to the view. This can also easily be seen by inspecting the view hierarchy:
That TextView that you see is the one that holds the title. The id is a generated value and not predefined (like i.e. the one for the ActionBarContainer), which means you can no longer look it up through some sort of static reference.
That explains why your code, which does an id-lookup-by-name, no longer works: the action_bar_title id is simply no longer being used here.
There are several solutions to make setting a custom font to the ActionBar title work again. The cleanest is probably to leverage the fact that setTitle() takes a CharSequence, which means you can attach a custom typeface span to it that enables the custom font and/or style to work. Doing this is some sort of a 'base' Activity would probably make most sense.
You can of course also iterate over the local view hierarchy, starting at ToolBar, but I'd say that's not quite as robust and prone to suffer from future changes (like your current code ;)).
Alternatively, consider using a library to simplify dealing with applying custom fonts. Calligraphy is usually my first stop for this.
After integrating the new Toolbar this is how I changed style.
inside protected override void OnCreate(Bundle bundle) of my Activity (that now extends AppCompatActivity)
where before there was the previous code now I have:
toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
var f = toolbar.Class.GetDeclaredField("mTitleTextView");
f.Accessible = true;
var barTitle = (TextView)f.Get(toolbar);
barTitle.SetTypeface(FontFactory.GetMyFont(this), TypefaceStyle.Normal);
I needed also to add this on the top:
using Java.Lang; //for the reflection
using Toolbar = Android.Support.V7.Widget.Toolbar;
and in the layout.axml I included the toolbar.axml in this way:
//...
<include
android:id="#+id/toolbar"
layout="#layout/toolbar" />
//...