android - 在视图上设置 y 值时,ScrollView 不滚动
问题描述
我对android开发相当陌生,而且我已经在这个问题上撞墙了两个多星期了。我通过学习 Kotlin 开始了我的 android 开发。
我有一个 ScrollView 作为应用程序布局的一部分,在 ScrollView 内部有一个布局。我以编程方式定位在 XML 中布局的基于 TextSwitcher 的按钮,主要是为了调整按钮的大小并将它们移出屏幕。这些按钮旨在通过 Spring 动画在屏幕上滑动。问题是当我设置按钮的 y 位置时,ScrollView 不会滚动。
我在 ScrollView 中使用了各种布局(LinearLayout、RelativeLayout、FrameLayout),它们的行为方式都相同。如果我不使用 y 值以编程方式定位按钮,这意味着让按钮纯粹通过 XML 定位(对于我当时在 ScrollView 内使用的任何布局),以便它们在屏幕上启动,ScrollView滚动很好。即使我以这种方式使用 Spring 动画,它仍然可以正常滚动,所以我认为使用动画不是问题。只有当我通过代码设置每个按钮视图的初始 y 值时,它才不会滚动。
我有一个精简的测试应用程序,没有应用程序的所有其他花里胡哨,它显示了问题。我让 ScrollView 滚动的方法是在 ScrollView 内添加布局可能需要的任何属性,并在 setButton 方法中注释掉“button.y = -y”行。例如,如果我只是将 ScrollView 中的 FrameLayout 更改为 LinearLayout,并在代码中注释掉设置 y 值,则按钮将在屏幕上布局,一个在另一个之上,并且滚动正常。单击“开始”按钮会使它们使用 Spring 动画制作动画,并且它仍然会在动画之后滚动。只需添加该 set y 行,就会导致 ScrollView 不滚动。
这是 XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusableInTouchMode="true"
android:orientation="horizontal"
tools:context="com.example.scrolltest.MainActivity">
<View
android:id="@+id/centerShim"
android:layout_height="match_parent"
android:layout_width="0dp"
android:visibility="invisible"
android:layout_centerHorizontal="true"/>
<ScrollView
android:id="@+id/buttonScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="2dp"
android:fillViewport="true"
android:orientation="vertical"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@id/centerShim"
android:scrollbars="none">
<FrameLayout
android:id="@+id/buttonLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.example.scrolltest.MyButton
android:id="@+id/button1View"
android:background="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
</com.example.scrolltest.MyButton>
<com.example.scrolltest.MyButton
android:id="@+id/button2View"
android:background="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
</com.example.scrolltest.MyButton>
<com.example.scrolltest.MyButton
android:id="@+id/button3View"
android:background="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
</com.example.scrolltest.MyButton>
<com.example.scrolltest.MyButton
android:id="@+id/button4View"
android:background="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
</com.example.scrolltest.MyButton>
<com.example.scrolltest.MyButton
android:id="@+id/button5View"
android:background="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
</com.example.scrolltest.MyButton>
<com.example.scrolltest.MyButton
android:id="@+id/button6View"
android:background="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
</com.example.scrolltest.MyButton>
<com.example.scrolltest.MyButton
android:id="@+id/button7View"
android:background="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
</com.example.scrolltest.MyButton>
<com.example.scrolltest.MyButton
android:id="@+id/button8View"
android:background="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
android:textSize="30sp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
</com.example.scrolltest.MyButton>
</FrameLayout>
</ScrollView>
<TextView
android:id="@+id/getStartedView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginEnd="5dp"
android:layout_marginBottom="5dp"
android:background="@color/black"
android:gravity="center"
android:text="Get Started"
android:textColor="@color/white"
android:textSize="30sp"/>
</RelativeLayout>
这是主要的活动代码:
package com.example.scrolltest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.util.TypedValue
import android.view.animation.AnimationUtils
import android.widget.*
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.SpringAnimation
import androidx.dynamicanimation.animation.SpringForce
class MainActivity : AppCompatActivity() {
private var buttonAnimationOffset: Float = 0f
// STIFFNESS_MEDIUM = 1500, higher is stiffer.
private val stiffnessValue = 300f
// DAMPING_RATIO_MEDIUM_BOUNCY = 0.5, higher dampens quicker.
private val dampeningValue = 0.7f
private val initialVelocity = 0.5f
private val fadeDuration = 500L
private var lastButtonAnim: SpringAnimation? = null
private var buttonWidth = 0f
private var buttonHeight = 0f
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val screenWidth = resources.displayMetrics.widthPixels
val screenHeight = resources.displayMetrics.heightPixels
var h = 0
buttonWidth = screenWidth * 0.33f
buttonHeight = screenHeight * 0.16f
buttonAnimationOffset = -buttonHeight
setButton(R.id.button1View, buttonHeight * 8, "Button 1")
setButton(R.id.button2View, buttonHeight * 7, "Button 2")
setButton(R.id.button3View, buttonHeight * 6, "Button 3")
setButton(R.id.button4View, buttonHeight * 5, "Button 4")
setButton(R.id.button5View, buttonHeight * 4, "Button 5")
setButton(R.id.button6View, buttonHeight * 3, "Button 6")
setButton(R.id.button7View, buttonHeight * 2, "Button 7")
setButton(R.id.button8View, buttonHeight, "Button 8")
val startButton = findViewById<TextView>(R.id.getStartedView)
startButton.setOnClickListener {
lastButtonAnim?.start()
}
/*
val buttonScrollView = findViewById<ScrollView>(R.id.buttonScrollView)
buttonScrollView.getViewTreeObserver()
.addOnScrollChangedListener(object : ViewTreeObserver.OnScrollChangedListener {
var lastScroll = 0
override fun onScrollChanged() {
Log.i("ScrollView", "[" + buttonScrollView.scrollX.toString() + "] [" + buttonScrollView.scrollX.toString() + "]")
val scrollY: Int =
buttonScrollView.getScrollY() // For ScrollView herzontial use getScrollX()
if (scrollY > lastScroll) {
Log.e("scroll", "down scroll$scrollY")
} else if (scrollY < lastScroll) {
Log.e("scroll", "up scroll$scrollY")
}
lastScroll = scrollY
}
})
*/
setButtonAnimationsAndListeners(buttonHeight)
}
private fun setButton( id: Int, y: Float, text: String ) {
val button = findViewById<MyButton>(id)
val mainLayout = findViewById<RelativeLayout>(R.id.mainLayout)
if ( button.layoutParams == null ) {
val buttonLayout = findViewById<FrameLayout>(R.id.buttonLayout)
button.layoutParams = FrameLayout.LayoutParams(buttonLayout.layoutParams)
}
button.layoutParams.height = buttonHeight.toInt()
button.layoutParams.width = buttonWidth.toInt()
button.y = -y
button.setOnClickListener {
val tv = button.currentView as TextView
if (tv.text.contains(" clicked"))
{
button.setText(tv.text.dropLast(8))
}
else
{
button.setText(tv.text.toString() + " clicked")
}
}
button.setCurrentText(text)
}
private fun setButtonAnimationsAndListeners(height: Float) {
val anim1 = setButtonAnimationAndListener(
R.id.button1View,
null,
0f
)
val anim2 = setButtonAnimationAndListener(
R.id.button2View,
anim1,
0f
)
val anim3 = setButtonAnimationAndListener(
R.id.button3View,
anim2,
0f
)
val anim4 = setButtonAnimationAndListener(
R.id.button4View,
anim3,
0f
)
val anim5 = setButtonAnimationAndListener(
R.id.button5View,
anim4,
0f
)
val anim6 = setButtonAnimationAndListener(
R.id.button6View,
anim5,
0f
)
val anim7 = setButtonAnimationAndListener(
R.id.button7View,
anim6,
0f
)
// Last button
lastButtonAnim = setButtonAnimationAndListener(
R.id.button8View,
anim7,
height
)
}
private fun setButtonAnimationAndListener(
buttonId: Int,
prevAnim: SpringAnimation?,
height: Float
): SpringAnimation {
val view = findViewById<MyButton>(buttonId)
val buttonLayout = findViewById<FrameLayout>(R.id.buttonLayout)
lateinit var anim: SpringAnimation
if (height > 0) {
Log.i("setAnim", "finalPosition = " + (height * ( buttonLayout.childCount - 1 )) )
anim = SpringAnimation(
view,
DynamicAnimation.TRANSLATION_Y
).apply {
spring = SpringForce().apply {
stiffness = stiffnessValue
dampingRatio = dampeningValue
finalPosition = height * ( buttonLayout.childCount - 1 )
}
}
} else {
anim = SpringAnimation(
view,
DynamicAnimation.TRANSLATION_Y
).apply {
spring = SpringForce().apply {
stiffness = stiffnessValue
dampingRatio = dampeningValue
}
}
}
anim.setStartVelocity(
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
initialVelocity,
resources.displayMetrics
)
)
anim.addUpdateListener { _, value, _ ->
Log.i("anim", "[" + getResources().getResourceEntryName(view.id) + "] value = " + value.toString() + " buttonAnimationOffset = " + buttonAnimationOffset.toString() + ", value + buttonAnimationOffset = " + (value + buttonAnimationOffset).toString())
prevAnim?.animateToFinalPosition(value + buttonAnimationOffset)
}
// Set fade in and out animations for changing the text.
val textAnimationIn = AnimationUtils.loadAnimation(this, android.R.anim.fade_in)
textAnimationIn.duration = fadeDuration
val textAnimationOut = AnimationUtils.loadAnimation(this, android.R.anim.fade_out)
textAnimationOut.duration = fadeDuration
view.setInAnimation(textAnimationIn)
view.setOutAnimation(textAnimationOut)
return anim
}
}
这是按钮类,主要是为了让我可以在 onMeasure 和 onLayout 方法中添加一些跟踪。否则,它只是一个 TextSwitcher:
package com.example.scrolltest
import android.content.Context
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.util.Log
import android.widget.ScrollView
import android.widget.TextSwitcher
class MyButton: TextSwitcher {
constructor( context: Context) : super( context ) {
}
constructor(context: Context, attrs: AttributeSet? ): super( context, attrs ) {
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val x = this.x
val y = this.y
val h = this.height
val w = this.width
val t = this.top
val ty = this.translationY
Log.i("onMeasure", "[" + getResources().getResourceEntryName(id) + "] y = " + y.toString() + ", top = " + t.toString() + ", translateY = " + ty.toString())
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
val x = this.x
val y = this.y
val h = this.height
val w = this.width
val t = this.top
val ty = this.translationY
Log.i("onLayout", "[" + getResources().getResourceEntryName(id) + "] y = " + y.toString() + ", top = " + t.toString() + ", translateY = " + ty.toString())
}
}
我不知道为什么在每个按钮的视图上调用 set y 会导致滚动问题。任何帮助表示赞赏。谢谢!
解决方案
推荐阅读
- cryptography - 大型交易所能否充当小型交易所的代理钱包?
- vue.js - nuxt/auth 的问题
- python - 我从 discord-lash-py "Task-1" sync_all_commands() 得到 403 但我的机器人工作正常0000
- r - 为什么数据框中不存在使用 dplyr 创建的变量?
- node.js - Amazon Linux 2 Docker 节点服务生成 core.[num] 个巨大的文件
- c - ncurses 链表未显示在屏幕中
- javascript - 数组错误,两个变量同时编辑
- ionic-framework - 我可以在 CapacitorJS 应用程序中使用 AdSense 在所有 3 个平台上展示广告:Web、iOS 和 Android?
- amazon-web-services - 如何在运行 nginx 和 jenkins 的 AWS ec2 Ubuntu 实例上释放空间?
- r - R - Cluster <- parallel::makeCluster(type='PSOCK', spec=spec) - 崩溃的窗口