Как я могу сделать настоящий заставку в Android? Я не хочу таймеров или задержек. Просто заставка, отображаемая до загрузки приложения.
Создайте настоящий заставку
Ответ 1
Что-то вроде
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
handler = new Handler();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
//Do some heavy stuff
return null;
}
@Override
public void onPostExecute(Void result){
handler.post(new Runnable(){
@Override
public void run(){
setContentView(R.layout.main);
}
});
}
}.execute();
}
Ответ 2
Ниже показано решение с кодом, которое, по-видимому, безупречно работало на нескольких тестовых устройствах в течение последних шести недель.
Однако есть несколько предварительных условий, которые следует учитывать перед погружением в полный экран заставки.
Прежде всего, если вы можете избежать необходимости использовать заставку, сразу создав основной вид приложения, предоставляя пользователю немедленный доступ к вашему приложению, это ваш самый лучший вариант.
Вы можете часто выполнять это, сразу создавая графику своего основного дисплея, а затем создавая рабочий поток для выполнения любых трудоемких задач инициализации, таких как загрузка таблицы, которая всегда используется приложением.
Однако, может быть, графики вашего основного представления сами занимают много времени, чтобы настроить и отобразить, и вы хотите, чтобы во время этой инициализации было видно что-то еще.
Теперь, если ваше основное действие имеет простой (например, по умолчанию), светлый или черный, непрозрачный фон, который обеспечит немедленное подтверждение того, что по крайней мере что-то происходит, когда пользователь запускает ваше приложение. Фоновые темы, которые я лично нашел в качестве примитивных "всплесков", включают следующее (для добавления в тег активности вашего основного действия в вашем файле манифеста):
android:theme="@style/Theme.Light.NoTitleBar"
android:theme="@style/Theme.Black.NoTitleBar"
В этом отношении я хотел бы отметить, что если для фона вашей деятельности требуется какой-либо растровый рисунок или анимация или другое значение, выходящее за пределы темы по умолчанию (или простая светлая или черная тема, как показано выше), мой опыт в том, что фон активности не будет отображаться до тех пор, пока ваше основное представление не будет отображаться в любом случае, и поэтому просто изменение фона вашей деятельности для себя будет вашим всплесковым дисплеем (по моему опыту) не будет выполнять более непосредственный ответ, чем ваш основной экран уже предоставляет.
Несмотря на то, что вышеуказанные простые темы будут работать как примитивные "всплески", возможно, вы считаете, что простой светлый или черный фон активности слишком неописуемый, что ваше приложение запустилось, и вы хотите что-то, что показывает имя или логотип вашего когда пользователь ждет. Или, может быть, ваш фокус активности должен быть прозрачным, потому что вы хотите, чтобы иметь возможность накладывать какое-то другое приложение на свои собственные приложения (такой прозрачный фон, конечно, невидим во время запуска, и поэтому не будет сигнализировать пользователю о том, что ваше приложение был запущен).
Если после рассмотрения всех альтернатив, представленных выше, вы все же думаете, что вам нужен заставку, вот такой подход, который, как я лично нашел, работает очень хорошо.
Для этого подхода вам нужно будет определить новый класс, который расширяет LinearLayout. Причина, по которой вам нужен ваш собственный класс, заключается в том, что вам нужно получить положительное подтверждение того, что ваш экран заставки фактически отобразился, поэтому вы можете сразу перейти к отображению основного вида без какого-либо клонирования таймера, который может только догадываться, сколько времени потребуется появится ваш экран заставки. В этой связи я хотел бы отметить, что если вы сразу же начнете показывать свой основной вид после отображения своего всплеска, всплывающее представление никогда не будет видно; использование этого подхода позволяет избежать этой возможности.
Вот пример такого класса:
public class SplashView extends LinearLayout {
public interface SplashEvents {
//This event is signaled after the splash and all of its child views,
// if any, have been drawn.
// As currently implemented, it will trigger BEFORE any scrollbars are drawn.
// We are assuming that there will BE no scrollbars on a SplashView.
public void onSplashDrawComplete();
}
private SplashEvents splashEventHandler = null;
public void setSplashEventHandler(SplashEvents splashEventHandler) {
this.splashEventHandler = splashEventHandler;
}
private void fireSplashDrawCompleteEvent() {
if(this.splashEventHandler != null) {
this.splashEventHandler.onSplashDrawComplete();
}
}
public SplashView(Context context) {
super(context);
//This is set by default for a LinearLayout, but just making sure!
this.setWillNotDraw(true);
//If the cache is not enabled, then I think that helps to ensure that
// dispatchDraw override WILL
// get called. Because if caching were enabled, then the
//drawing might not occur.
this.setDrawingCacheEnabled(false);
setGravity(Gravity.CENTER);
//This splices in your XML definition (see below) to the SplashView layout
LayoutInflater.from(context).inflate(R.layout.splashscreen, this, true);
}
@Override
protected void dispatchDraw(Canvas canvas) {
//Draw any child views
super.dispatchDraw(canvas);
//Signal client objects (in this case, your main activity) that
// we have finished initializing and drawing the view.
fireSplashDrawCompleteEvent();
}
}
Поскольку мы загружаем наш XML из представления, нам нужно определить его в XML, используя тег <merge>
для "сращивания" в XML-определенных элементах как дочерние элементы нашего класса SplashView. Вот пример (для размещения в папке res/layout приложения), которую вы можете настроить для своих нужд:
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
>
<TextView android:id="@+id/tvHeading"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:textSize="30dp"
android:textStyle="bold"
android:text="Loading..."
android:layout_weight="1.0"
android:textColor="#00ff00"
android:background="#AA000000"
/>
</merge>
Обратите внимание, что TextView определен с полупрозрачным черным фоном, так что это приведет к уменьшению отображения панели запуска, при этом текст "Загрузка..." накладывается сверху зеленым цветом.
Все, что осталось - это отредактировать что-то вроде следующего в (и выше) методе onCreate() вашего основного действия:
private Handler uiThreadHandler = new Handler();
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Create an instance of the splash view, and perform a setContentView()
SplashView splashView = new SplashView(this);
//Doing this allows you to access the "this" pointer of the main
// activity inside the Runnable below.
final main mainThis = this;
// Set an event handler on the SplashView object, so that as soon
// as it completes drawing we are
// informed. In response to that cue, we will *then* put up the main view,
// replacing the content view of the main activity with that main view.
splashView.setSplashEventHandler(new SplashView.SplashEvents() {
@Override
public void onSplashDrawComplete() {
//Post the runnable that will put up the main view
uiThreadHandler.post(new Runnable() {
@Override
public void run() {
//This method is where you will have moved
// the entire initialization of your app
// main display, which normally would have been
// in your onCreate() method prior to adding the
// splash display.
launchMainView(mainThis, savedInstanceState);
}
});
}
});
//This will cause your splash view to draw. When it finishes, it will trigger the code above.
this.setContentView(splashView);
//At this point, do *not* move directly on to performing a setContentView() on your main view.
// If you do, you will never see the splash view at all.
// You simply wait for the splash view to signal you that it has completed drawing itself, and
// *then* call launchMainView(), which will itself call setContentView() again, passing it
// your main view.
}
//Here is a stripped-down version of launchMainView(). You will typically have some additional
// initializations here - whatever might have been present originally in your onCreate() method.
public void launchMainView(main mainThis, Bundle savedInstanceState) {
myRootView = new MyRootView(mainThis);
setContentView(myRootView);
}
Этот подход работает для меня очень хорошо. Я использовал его только для уровня API 8 и тестировал этот код на разных устройствах, включая как телефоны, так и планшеты, работающие под управлением Android 2.2.1, 2.3.3 и 4.0.1 (ICS).
Протест:
Потенциальная ответственность вышеупомянутого подхода заключается в том, что при некоторой комбинации обстоятельств изображение всплеска может не сигнализировать о том, что оно завершено, и поэтому всплеск будет "застревать" на главном дисплее без основного вида чтобы заменить его. Это никогда не случалось со мной, но я хотел бы получить комментарии здесь относительно того, может ли переопределить dispatchDraw() в SplashView выше, возможно, когда-либо не будет вызван. Я выполнил визуальный осмотр кода, который запускает dispatchDraw(), и он выглядит так, как будто он всегда будет вызван, учитывая инициализации, которые я сделал в конструкторе SplashView.
Если у кого-то есть лучший способ переопределить для этой же цели, я был бы рад услышать об этом. Я был удивлен тем, что не смог найти никакого переопределения, специально приспособленного для стрельбы, когда представление закончило отображение, и поэтому, если он существует, и я каким-то образом его пропустил, отправьте комментарий ниже. Комментарии, подтверждающие, что этот подход будет работать, также очень приветствуются!
Ответ 3
Это не так сложно; вы просто создаете представление, которое вы будете использовать в качестве своего заставки (тот, который имеет простой макет и не требует большого количества измерений), установите его как содержимое для действия с помощью setContentView;
Затем снова вызовите setContentView в действии со сложной компоновкой, которая требует времени для сборки. Вы даже можете использовать Asynctask для загрузки данных, прежде чем вы вызовите setContent во второй раз с помощью сложной компоновки. Это зависит от того, насколько вы связаны с загрузкой или просмотром здания.
Ответ 4
public class MyLocationListener extends Activity {
public Handler myHandler = new Handler(){
public void handlerMessage(Message msg){
set you contentView here after splash screen
}
}
public MyLocationListener(Context context){
this.context = context;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splashscreen);
// don't set Content View here instead start a thread here to do the task yiou want to do.
// Now post message from new thread to UI Thread using handlers.
}
}
Ответ 5
Лучший способ сделать заставку:
- если пользователь нажимает назад, вам нужно быстро перейти на главный экран.
- нет анимации.
Я пришел в это хорошее решение:
import android.app.Activity; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.view.WindowManager; import br.eti.fml.android.sigame.R;
import java.util.concurrent.atomic.AtomicBoolean;
public class LauncherActivity extends Activity {
private AsyncTask goingToNextScreen;
private AtomicBoolean alreadyShown = new AtomicBoolean(false);
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.launcher);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//noinspection unchecked
goingToNextScreen = new AsyncTask() {
@Override
protected Object doInBackground(Object... objects) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
// ignores
}
return null;
}
@Override
protected void onPostExecute(Object o) {
goNext();
}
}.execute();
}
@Override
public void onBackPressed() {
if (goingToNextScreen != null) {
goingToNextScreen.cancel(true);
goNext();
}
}
private void goNext() {
if (alreadyShown.compareAndSet(false, true)) {
startActivity(new Intent(LauncherActivity.this, HomeActivity.class));
overridePendingTransition(0, 0);
finish();
overridePendingTransition(0, 0);
}
} }
Ответ 6
Когда-нибудь, используя всплеск, для загрузки содержимого Activity потребуется несколько миллисекунд или секунду.
Если вам нужен только "обратный образ", как обычный всплеск экрана. Я думаю, что лучший способ - использовать Темы.
Использование SherlockActionBar, например:
<style name="SplashTheme" parent="Theme.Sherlock.NoActionBar">
...
<item name="android:windowBackground">@drawable/splash</item>
...
</style>
где splash может быть файлом .9, чтобы заполнить экран.
И активность в манифесте должна быть чем-то вроде
<activity
android:name=".SplashActivity"
...
android:theme="@style/SplashTheme"
...>
...
</activity>
тогда вам не нужна строка setContent (View) в вашем коде. И тема будет загружена быстрее, чем содержимое.
Это позволяет вам иметь заставку с начала загрузки приложения. Без черных окон или ActionBars или что-то в этом роде.
Ответ 7
//код для кода Splash
public class SplashScreen extends Activity {
static int SPLASH_TIMEOUT = 5000;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_layout);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startActivity(new Intent(SplashScreen.this, MainActivity.class));
finish();
}
}, SPLASH_TIMEOUT);
}
}
Здесь SPLASH_TIMEOUT будет определять после того, как будет отображаться ваше собственное действие, поэтому измените это значение в соответствии с вашими потребностями.
//код для MainActivity.class
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}