我怎样才能在Android中制作一个真正的启动画面?我不想用计时器或延迟,只需要一个显示直到应用程序加载完成的启动画面。
我怎样才能在Android中制作一个真正的启动画面?我不想用计时器或延迟,只需要一个显示直到应用程序加载完成的启动画面。
android:theme="@style/Theme.Light.NoTitleBar"
android:theme="@style/Theme.Black.NoTitleBar"
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>
标签将其定义为SplashView类的子元素插入XML定义的元素。这是一个示例(应放置在您的应用程序的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>
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's
// 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);
}
类似于
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();
}
.execute()
,复制粘贴时一定出了问题 :) - nhaarman这并不难,你只需要创建一个视图作为启动屏幕(它具有简单的布局且不需要大量测量),使用setContentView将其设置为活动内容;
然后再次在活动上调用setContentView,并使用需要花费时间来构建的复杂布局。你甚至可以使用Asynctask在第二次使用复杂布局之前加载数据。这取决于你是受数据加载还是视图构建的限制。
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.
}
}
做启动画面的最佳方式是:
我找到了这个好的解决方案:
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);
}
} }
有时候使用启动屏幕(Splash)时,应用程序需要几毫秒或几秒钟来加载 Activity 的内容。
如果你只想要一个“背景图像”作为通常的启动屏幕,我认为最好的方法是使用主题(Themes)。
例如,可以使用 SherlockActionBar:
<style name="SplashTheme" parent="Theme.Sherlock.NoActionBar">
...
<item name="android:windowBackground">@drawable/splash</item>
...
</style>
其中闪屏可以是一个.9文件来填充屏幕。
而在清单中的Activity必须是类似于以下内容:
<activity
android:name=".SplashActivity"
...
android:theme="@style/SplashTheme"
...>
...
</activity>
如果您的代码中没有setContent(View)行,则不需要它。主题将比内容加载更快。
这使您可以在应用程序加载开始时拥有启动画面。没有黑色窗口、操作栏或类似的东西。
//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);
}
}