使用Activity ImageView将Android WindowBackground居中

时间:2019-03-03 01:47:27

标签: android splash

上下文

步骤1:当前,我有一个活动在等待加载活动时使用hand设置初始背景。这样会加载应居中对齐的位图。

第2步::加载活动后,它会执行一个简单的stand来设置活动的背景,现在它将替换 step1中的android:windowBackground 。这会加载setContentView,该位置应居中对齐。

问题是它们不是都对齐中心,一个或另一个偏移它们。 Maby状态栏推下一个吗?我不确定。有什么想法为什么它们不能对齐?

我希望它们都居中对齐。我尝试使用android:windowBackground时没有运气。

当我将imageView添加到活动(fitSystemWindows="true")布局android:layout_marginTop="12dp"时,两者都可以很好地对齐,但不能对所有密度都对齐,而其他密度都无法对齐。

Maby有一种方法可以动态计算此偏移量,然后针对所有密度进行对齐?


比较图像

左(灰色)-Step1(窗口背景):
右(蓝色)-步骤2(活动布局): enter image description here


代码

AndroidManifest.xml

activity_start_onboarding.xml

styles.xml

imageView

@ drawable / splash_background

<activity android:name=".view.onboarding.ActivityStartOnboarding"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"
            android:theme="@style/ColdstartSplashTheme">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

ActivityStartOnboarding.java

<style name="ColdstartSplashTheme" parent="SuperbalistTheme.Dark">
    <item name="android:windowBackground">@drawable/splash_background</item>
</style>

activity_start_onboarding.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/grey_mid_dark" />

<item>
    <bitmap
        android:gravity="center"
        android:src="@drawable/ic_delivery_free_raster" />
</item>

4 个答案:

答案 0 :(得分:5)

var db = new Dexie(dbName);
        db.version(dbVersion).stores({
            smthtbl: '++id, data, creationTime'});

db.smthtbl.each(function (item) {
    return proccessItem(item);
}).then(function() {
    console.log("done");
    return "done"
});


function proccessItem(item) {
    console.log(item.id + " : " + item.data);
};

那是你的问题。您的FrameLayout在状态栏下开始膨胀,高度约为25dp,因此AppCompatImageView会更高。

第一个解决方案: 从android:fitsSystemWindows="true" FrameLayout中删除android:fitsSystemWindows="true"

第二个解决方案: 将activity_start_onboarding.xml添加到您的<item name="android:windowDrawsSystemBarBackgrounds">true</item>中。背景会在状态栏下开始绘制,并且位图会更高。

答案 1 :(得分:1)

对我来说,公认的解决方案没有用。但是我发现了this,它像一个咒语一样起作用。 它也更灵活,因为它不依赖于API 21

答案 2 :(得分:0)

使用背景代替windowBackground

<style name="ColdstartSplashTheme" parent="SuperbalistTheme.Dark">
    <item name="android:background">@drawable/splash_background</item>
</style>

答案 3 :(得分:0)

无论出于何种原因,其他解决方案都不适合我。因此,我编写了一个类似于 ImageView 的快速类,不同之处在于 它使可绘制对象相对于整个窗口居中,而不是在其自己的视图范围内。

本质上,您的主题中的 windowBackground 使用了窗口的边界。您的 ImageView,即使填满其父项,仍受您的 activity 边界的限制,这是一种不同的形状(例如,不包括系统栏)。因此,在 window 中居中绘制可绘制(windowBackground 所做的)与在 视图 中居中绘制可产生不同的结果(ImageView 所做的) .我编写的 View 类在 窗口 中将可绘制对象居中,因此它的作用与您的主题相同。

这是课程:

package your.package.name

import android.app.Activity
import android.content.Context
import android.graphics.Canvas
import android.graphics.Point
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.View
import android.widget.ImageView
import your.package.name.R

/**
 * Simply draws the given drawable in the center of the current window with no scaling. This is not
 * very sophisticated, so cannot handle a lot of the features that a regular [ImageView] can. If
 * these features are required, you might want to try subclassing [ImageView].
 */
class WindowCenteredImageView(context: Context, attrs: AttributeSet): View(context, attrs) {

    // Obtain drawable from attributes.
    private val d: Drawable?
    init {
        context.theme.obtainStyledAttributes(
            attrs,
            R.styleable.WindowCenteredImageView,
            0, 0
        ).apply {
            try {
                d = getDrawable(R.styleable.WindowCenteredImageView_src)
            } finally {
                recycle()
            }
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        if (d != null) {
            // We have a drawable, so try to draw it!
            if (d.intrinsicWidth >= 0 && d.intrinsicHeight >= 0) {
                // Our drawable doesn't fill the screen, so we should calculate its bounds. This is
                // where we take into account the current view's offset within the window...
                val viewTopLeftRelativeToWindow = onDrawCachedObjects.point1.apply {
                    val array = onDrawCachedObjects.array.apply { getLocationInWindow(this) }
                    set(array[0], array[1])
                }

                // And the window's dimensions...
                // (Casting here can't fail as views are always given activity context.)
                val window = (context as Activity).window.decorView
                val windowHeight = window.height
                val windowWidth = window.width

                // Do the calculations.
                // First, find out where we want the image to go in the window
                val imageTopLeftRelativeToWindow = onDrawCachedObjects.point2.apply {
                    set(
                        (windowWidth / 2) - (d.intrinsicWidth / 2),
                        (windowHeight / 2) - (d.intrinsicHeight / 2)
                    )
                }

                // Now we can calculate where the image should go in the view
                val imageTopLeftRelativeToView = onDrawCachedObjects.point3.apply {
                    set(
                        imageTopLeftRelativeToWindow.x - viewTopLeftRelativeToWindow.x,
                        imageTopLeftRelativeToWindow.y - viewTopLeftRelativeToWindow.y
                    )
                }

                // We have all the information needed to set the image bounds
                d.setBounds(
                    imageTopLeftRelativeToView.x,
                    imageTopLeftRelativeToView.y,
                    imageTopLeftRelativeToView.x + d.intrinsicWidth,
                    imageTopLeftRelativeToView.y + d.intrinsicHeight
                )
            }

            // Draw the drawable onto the canvas
            d.draw(canvas)
        }
    }

    /** Optimization: Objects to use in [onDraw] to avoid instantiations */
    private val onDrawCachedObjects = object {
        val array = IntArray(2)
        val point1 = Point()
        val point2 = Point()
        val point3 = Point()
    }
}

这里是如何使用它:

  • 首先你需要把它放在你的 res/values/attrs.xml 中:
    <declare-styleable name="WindowCenteredImageView">
        <!-- Sets a drawable as the content of this ImageView. -->
        <attr name="src" format="reference" />
    </declare-styleable>
  • 现在用这个替换你的 ImageView(它需要比它要绘制的可绘制对象大,因为包装内容可能无法正常工作:我只是使用 {{1} 将此视图设为活动的整个大小} - 在你给它的 drawable 之外,它将是透明的):
match_parent