Looking online I've found more than one way to implement a splash screen on Android apps. Someone create a new "splashActivity" with a "splash.xml" layout and a "splash_theme" (often fullscreen), some others use a "splashActivity" with no "splash.xml" layout, but just a theme with a "splashscreenDrawable.xml" as background. I'm using the last one because it seems more fast compared to the first case (maybe the theme+drawable is not heavy as the layout?), but which is better? In which cases should I use the first or the second one?
The app uses android oreo 8.0 and I'm using kotlin
This is the code (just in case the question is not well expressed sry)
MainActivity.kt (do nothing)
package com.example.mobileprogrammingproject
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
activity_main.xml (just a test layout with a tv and a btn)
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/titleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/app_name"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0"
android:layout_marginStart="10dp"
android:textSize="26sp">
</TextView>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="press me"
app:layout_constraintTop_toBottomOf="#+id/titleTextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
</Button>
</androidx.constraintlayout.widget.ConstraintLayout>
SplashScreen.kt (the launcher activity that calls the MainActivity.kt)
package com.example.mobileprogrammingproject
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
class SplashScreen : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startActivity(Intent(applicationContext, MainActivity::class.java))
finish()
}
}
AndroidManifest.xml (i've changed the laucher activity from MainActivity.kt to SplashScreen.kt)
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mobileprogrammingproject">
<application
android:allowBackup="true"
android:icon="#drawable/icon"
android:label="#string/app_name"
android:roundIcon="#drawable/icon"
android:supportsRtl="true"
android:theme="#style/Theme.MobileProgrammingProject">
<activity
android:name=".SplashScreen" android:theme="#style/SplashScreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity">
</activity>
</application>
and the splash theme (using a drawable)
<style
name="SplashScreen" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="android:windowBackground">#drawable/splash_screen_drawable</item>
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">#null</item>
</style>
this is the splash_screen_drawable:
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/splash_background_color"
android:drawable="#android:color/black" />
<item>
<bitmap
android:src="#drawable/dicce_logo"
android:gravity="center"/>
</item>
</layer-list>
The use of the two modes is completely left to the developer as he is the only one who knows what the app must do before starting and above all he decides the flow to follow.
Personally I can tell you that the spash screen created by xml, style etc. is the one suggested for everything because you have the right waiting time for the start (about a second) and you have the opportunity to have a unique experience for the user who interface with yours instead of with the most famous and used apps.
Someone implements the class with xml layout etc in case they want to manage the splash duration based on services and actions that they need to check or validate before bringing the user into the app.
Related
Currently I'm using Styles-only method and I was using WEBP formatted logo. Works fine. Now I have a GIF and I'm trying to show this GIF while my application starting.
I added this GIF to drawable folder but I have issues.
Problem is; firstly I see my new gif's first frame (I can say, motionless preview of my gif in android studio) as picture, and then I can see my gif but this picture and gif are both visible and overlapped.
My structure is in below.
start_screen.xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="#color/my_dark_color" />
</shape>
</item>
<item>
<bitmap
android:gravity="center"
android:src="#drawable/my_gif_file"
android:alpha="0.5"/>
</item>
</layer-list>
themes.xml:
<style name="AppTheme.Launch" parent="AppTheme.Dark">
<item name="android:windowBackground">#drawable/start_screen</item>
<item name="android:windowAnimationStyle">#null</item>
</style>
AndroidManifest.xml:
<activity
android:name=".LaunchActivity"
android:configChanges="orientation|screenSize"
android:label="#string/application_name"
android:launchMode="singleTask"
android:resizeableActivity="${debug}"
android:theme="#style/AppTheme.Launch">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
activity_launch.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/splash_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
LaunchActivity.kt:
class LaunchActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_launch)
Glide.with(this).asGif()
.load(R.drawable.my_gif_file)
.into(splashlogo)
...
...
...
}
}
I tried to debug the code. I realize that, the Glide... codeline is executed a few seconds after seeing first motionless picture.
What is wrong ? Can you help me to find the solution?
So, when I compile the code for my splash screen and run it, it only shows a blank screen. The layout editor perfectly renders the screen. I recently switched to Kotlin, so maybe I did some mistake in the code.
package com.superstar.scrolls2
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.PersistableBundle
import androidx.appcompat.app.AppCompatActivity
class LauncherActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
setContentView(R.layout.launcher_layout)
Handler().postDelayed({
var i : Intent=Intent(this#LauncherActivity, LoginActivity::class.java)
startActivity(i)
}, 5000)
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.superstar.scrolls2">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.Scrolls2" >
<meta-data
android:name="preloaded_fonts"
android:resource="#array/preloaded_fonts" />
<activity android:name=".LauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".LoginActivity"/>
</application>
</manifest>
and the layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#drawable/parchment_chinese"
android:id="#+id/linearLayout">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="124dp"
android:background="#00FFFFFF"
android:src="#drawable/scroll_one_coloured"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.499"
tools:layout_conversion_absoluteHeight="124dp"
tools:layout_conversion_absoluteWidth="163dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="144dp"
android:fontFamily="#font/medievalsharp"
android:text="Scrolls"
android:textColor="#9A5712"
android:textSize="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.511"
app:layout_constraintStart_toStartOf="parent"
tools:layout_conversion_absoluteHeight="59dp"
tools:layout_conversion_absoluteWidth="157dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
So, the splash screen is completely black with the toolbar at the top showing the app name. Just to test, I wrote the same screen with java which works all good. The app doesn't crash or anything. And just for testing purposes, I didn't finish() launcher activity to know if it actually starts the LoginActivity, but it doesn't since there's only one activity in the stack.
The problem is you are overriding the wrong onCreate(),it will never be called and you content won't be set
use
override fun onCreate(savedInstanceState: Bundle?)
instead of
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?)
I have a single activity app which uses a settings fragment (PreferenceFragmentCompat) with a custom layout (set via overriding the PreferenceThemeOverlay style). From the fragment's onViewCreated method I'm using setSupportActionBar to reference the toolbar which is present on that layout. This works fine until it runs on API 28+, at which point the reference to toolbarSettings is null and an error is raised.
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.appcompat.app.ActionBar.setTitle(java.lang.CharSequence)' on a null object reference
at androidx.navigation.ui.ActionBarOnDestinationChangedListener.setTitle(ActionBarOnDestinationChangedListener.java:48)
at androidx.navigation.ui.AbstractAppBarOnDestinationChangedListener.onDestinationChanged(AbstractAppBarOnDestinationChangedListener.java:104)
at androidx.navigation.NavController.addOnDestinationChangedListener(NavController.java:204)
at androidx.navigation.ui.NavigationUI.setupActionBarWithNavController(NavigationUI.java:228)
at androidx.navigation.ui.ActivityKt.setupActionBarWithNavController(Activity.kt:74)
at androidx.navigation.ui.ActivityKt.setupActionBarWithNavController$default(Activity.kt:89)
at com.simplenotes.notes.presentation.ui.SettingsFragment.setupActionBar(SettingsFragment.kt:39)
at com.simplenotes.notes.presentation.ui.SettingsFragment.onViewCreated(SettingsFragment.kt:20)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:332)
I've seen mention of changes to custom preference fragments in this version however can't see anything specific to this behaviour. Does anyone know a solution or can point out what has been done wrong?
SettingsFragment.kt
class SettingsFragment : PreferenceFragmentCompat() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupActionBar()
}
private fun setupActionBar() {
setHasOptionsMenu(true)
val hostActivity = requireActivity() as AppCompatActivity
hostActivity.setSupportActionBar(toolbarSettings)
hostActivity.setupActionBarWithNavController(findNavController())
val actionBar = hostActivity.supportActionBar
actionBar?.title = resources.getString(R.string.title_settings)
actionBar?.setDisplayHomeAsUpEnabled(true)
}
}
fragment_settings.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbarSettings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbarSettings"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:id="#android:id/list_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
styles.xml
<resources>
<style name="Theme.MaterialComponents.DayNight.NoActionBar.Bridge" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge" />
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar.Bridge">
<item name="preferenceTheme">#style/AppTheme.PreferenceThemeOverlay</item>
</style>
<style name="AppTheme.PreferenceThemeOverlay" parent="PreferenceThemeOverlay">
<item name="android:layout">#layout/fragment_settings</item>
</style>
</resources>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.simplenotes.notes">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".presentation.ui.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Dependencies
implementation 'androidx.preference:preference:1.1.0'
implementation 'com.google.android.material:material:1.1.0'
In case anyone else runs into this issue I found the problem.
In addition to the styles.xml file in the question, there was also a styles-v27.xml file which was being used to override the windowLightNavigationBar attribute...
<resources>
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar.Bridge">
<item name="android:windowLightNavigationBar">false</item>
</style>
</resources>
On API v28 though this meant the preferenceTheme value wasn't getting picked up. When the settings fragment was inflated it effectively didn't have the custom layout, hence the toolbar not being created.
In styles-v27.xml I simply repeated the preferenceTheme attribute like below and hey presto it works fine on v28 and above.
<resources>
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar.Bridge">
<item name="android:windowLightNavigationBar">false</item>
<item name="preferenceTheme">#style/AppTheme.PreferenceThemeOverlay</item>
</style>
</resources>
I have just started learning development on Android, and I am not able to view "Hellow World!" TextView in the Design Tab.
MainActivity.java:
package com.dummy.demoapp;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dummy.demoapp">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
The TextView appears in the Component Tree, but the preview of the activity is totally blank:
I tried zooming in, but the TextView is just not there.
[EDIT]: The red exclamation (!) gives me the following message:
And refreshing doesn't solve the problem. Any help?
Go to style.xml and change this:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
to
<style name="AppTheme" parent="Base.Theme.AppCompat.Light.DarkActionBar">
Android Studio sometimes does not appear upto you've success build,
Build->Build&Run, then select your virtual device if there is a helloworld it's okay, it's not your code problem it's related with IDE.
I think it's you default AppTheme with color white , try to add color to TextView
android:textColor="#android:color/black"
Click on the blue icon at the top left corner and then click on force layout. and You will see the Hello World!
I am working on a xamarin project (has no relevance here as far as I can tell - the android layout properties are the same)
I am using Window.SetFeatureInt (WindowFeatures.CustomTitle, ...) to set the title (2 "columns". I wish to make two rows of text though for my title. Is this possible? I have not had much success. I have an upper left, upper right and lower left and lower right TextViews to set.
My previous attempts have ended up with the TextViews overwriting each other.
Here I am designing a XML file with an image, text for title & button. This is the XML file. U can use it however you want, for a complete application or perticular activity.
In case of activity add this activity's theme tag. For multi line just use text view in side the below linear layout, set it as multline true.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="35dip"
android:gravity="center_vertical"
android:background="#android:color/darker_gray">
<ImageView
android:id="#+id/header"
android:background="#drawable/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Custom Window Text"
android:textColor="#android:color/black"
android:textStyle="bold"/>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
Create a theme in Custom_theme.xml,
<resources>
<style name="CustomWindowTitleBarBG">
<item name="android:background">#323331</item>
</style>
<style name="TitleBarTheme" parent="android:Theme">
<item name="android:windowTitleSize">35dip</item>
<item name="android:windowTitleBackgroundStyle"> #style/CustomWindowTitleBarBG</item>
</style>
Modify the AndroidManifest.xml file as follows for applying custom theme
<application
android:icon="#drawable/icon"
android:label="#string/app_name"
android:theme="#style/TitleBarTheme" >
<activity
android:name=".CustomWindowTitle"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Now in main java file add “requestWindowFeature(Window.FEATURE_CUSTOM_TITLE)” &
“getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.window_title)”
This is the code snippet for CustomWindowTitle.java
package com.example.android;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
public class CustomWindowTitle extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.main);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.window_title);
}
}