使用活动图像视图将Android WindowBackground居中 上下文
第1步:目前我有一个活动,它使用使用活动图像视图将Android WindowBackground居中 上下文,android,splash-screen,Android,Splash Screen,第1步:目前我有一个活动,它使用android:windowBackground在我们等待活动加载时设置初始背景。这将加载一个应该居中对齐的位图 Step2:一旦加载活动,它会执行一个简单的setContentView来设置活动的背景,该背景现在将取代android:windowBackground中的step1。这将加载一个应居中对齐的imageView 问题是它们不是都对准了中心,一个或另一个上存在某种偏移,使它们不对准。可能是状态栏按下了那个?我不确定。你知道为什么它们不一致吗 我想让它们
android:windowBackground
在我们等待活动加载时设置初始背景。这将加载一个应该居中对齐的位图
Step2:一旦加载活动,它会执行一个简单的setContentView
来设置活动的背景,该背景现在将取代android:windowBackground
中的step1。这将加载一个应居中对齐的imageView
问题是它们不是都对准了中心,一个或另一个上存在某种偏移,使它们不对准。可能是状态栏按下了那个?我不确定。你知道为什么它们不一致吗
我想让它们都居中对齐。我尝试过使用fitSystemWindows=“true”
,但运气不佳
当我将android:layout\u marginTop=“12dp”
添加到活动(activity\u start\u onboarding.xml
)布局imageView
两者对齐良好,但并非所有密度都对齐,其他密度未对齐
是否有一种方法可以动态计算此偏移以对齐所有密度
比较图像 左侧(灰色)-步骤1(窗口背景):
右侧(蓝色)-步骤2(活动布局):
代码 AndroidManifest.xml
styles.xml
@可绘制/飞溅背景
@可绘制/飞溅\u背景
活动StartOnboard.java
公共类活动StartOnboard扩展AppCompative活动{
@凌驾
创建时受保护的void(@Nullable Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity\u start\u Onboard);
}
}
activity\u start\u onboard.xml
这是你的问题。您的FrameLayout在statusbar下开始膨胀,其高度约为25dp,因此AppCompatImageView稍高一些
第一个解决方案:
从activity\u start\u onboarding.xml
FrameLayout中删除android:fitsystemwindows=“true”
第二种解决方案:
将
true
添加到您的ColdstartSplashTheme
。背景在状态栏下开始绘制,位图将更高。使用背景而不是windowBackground
<style name="ColdstartSplashTheme" parent="SuperbalistTheme.Dark">
<item name="android:background">@drawable/splash_background</item>
</style>
@可绘制/飞溅背景
对我来说,接受的解决方案不起作用。但我发现了,它就像一个符咒。
这也是一个更灵活的解决方案,因为它不依赖于API 21,无论出于何种原因,其他任何解决方案都不适合我。因此,我编写了一个类似于ImageView的quick类,只是它将给定的可绘制对象相对于整个窗口居中,而不是在其自身的视图范围内 主题中的
windowBackground
基本上使用了窗口的边界。您的图像视图
,即使它填充了其父视图,仍然受到活动的限制,这是一种不同的形状(例如,不包括系统栏)。因此,在窗口中居中放置一个可绘制图形(如windowBackground所做的)与在视图中居中放置一个可绘制图形(如图像视图所做的)会产生不同的结果。我编写的视图
类在窗口中居中绘制,因此它的功能与主题相同
下面是课程:
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中:
为什么要在活动\u start\u onboard.xml中使用splash\u background
,而在splash\u background
中使用ic\u delivery\u free\u光栅。因此,主题/样式使用与活动相同的布局@drawable/splash_background
您好,谢谢您的输入!当我使用android:background
而不是android:windowBackground
setContentView(R.layout.activity\u start\u onboarding)时代码>无效,因此我从未看到第二个屏幕(Step2/蓝屏)。有什么想法吗?@Francois嗨!我昨天回答了()。你试过我的解决方法吗?它应该会工作的嗨,我明天会看一看:)tx!对不起,回复太慢了!1.删除android:fitsSystemWindows=“true”
实际上会使它的绘制略低。让他们更接近2<代码>真的
事实上确实把它调高了,现在两者都完美地对齐了。谢谢你的回答,我为没有早点回来而道歉:哦
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()
}
}
<declare-styleable name="WindowCenteredImageView">
<!-- Sets a drawable as the content of this ImageView. -->
<attr name="src" format="reference" />
</declare-styleable>
<your.package.name.WindowCenteredImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:src="@drawable/ic_delivery_free_raster"/>