我有一个ConstraintLayout。出于这个例子的目的,我们可以在里面有三个视图。
<android.support.constraint.ConstraintLayout ...>
<TextView
android:id="@+id/text"
.../>
<TextView
android:id="@+id/value"
.../>
<View
android:id="@+id/bar"
android:layout_width="0dp"
android:layout_height="8dp"
android:background="@color/bar_color"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/text"
app:layout_constraintEnd_toStartOf="@id/value"
/>
</android.support.constraint.ConstraintLayout>
在运行时,我想将bar
的宽度设置为text
和value
之间距离之间的某个值。
我已经有一个0到100之间的值,它是两个文本视图之间距离的百分比。
到目前为止我已经尝试了两种方法但是已经卡住了。
尝试1
为了做到这一点,我觉得我需要text
和value
之间的实际距离以及正确设置条形宽度的方法。
我可以通过执行以下操作来设置bar
的宽度:
val params: ConstraintLayout.LayoutParams = percentageBar.layoutParams as LayoutParams
params.matchConstraintMaxWidth = 300 // should be actual value rather than 300
percentageBar.layoutParams = params
这样可以将条的宽度设置得很好。但我需要一些方法来确定实际数字应该是多少而不是300.像(百分比值* text-value-distance / 100)。
尝试2
通过查看SO上的其他答案,我发现了约束百分比。
...
<View
android:id="@+id/bar"
android:layout_width="0dp"
android:layout_height="8dp"
android:background="@color/bar_color"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/value"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@id/text"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="1.0"/>
...
然后,在代码中,我可以做params.matchConstraintPercentWidth = item.percentageOfMaxValue.toFloat()
这个问题是,当百分比值设置为高时,它将占用父项的百分比并超过value
的开头。
我正朝着正确的方向前进吗?
我希望我已经清楚地描述了这个问题。
提前致谢。
//更新
我已经推出了一个类似于我遇到的问题的简化版本。 BarProblem on GitHub
您可以从布局编辑器的设计选项卡中看到问题。
//更新2
问题解决了。 GitHub repo现在包含解决方案的代码。
我对你的案子很好的解决方案是guidelines。这些帮助程序是不会在应用程序中显示的锚点,它们就像布局上方的一行网格,可用于将小部件附加或约束到它。
关键是我们需要等到ConstraintLayout
布局。我们可以通过使用ViewTreeObserver.OnGlobalLayoutListener
来做到这一点。
示例解决方案
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
text.text = "Text"
value.text = "Value"
val globalLayoutListener = MainActivityGlobalListener(item_view, text, value, percentage_bar)
item_view.viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener)
}
}
class MainActivityGlobalListener(private val itemView: View,
private val text: View,
private val value: View,
private val bar: View) : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
Log.i("yoyo", "in onGlobalLayout")
val width = value.x - (text.x)
Log.i("yoyo", "Width: $width")
val params: ConstraintLayout.LayoutParams = bar.layoutParams as ConstraintLayout.LayoutParams
params.matchConstraintMaxWidth = (1.0 * width).toInt() // using 0.1 here - this value is dynamic in real life scenario
bar.layoutParams = params
// required to prevent infinite loop
itemView.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
}
请注意需要删除最后一行的侦听器以防止发生无限循环(侦听布局 - >设置条宽度 - >触发重新布局等)
如果使用Android KTX,我们可以简化为以下内容:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
text.text = "Text"
value.text = "Value"
item_view.doOnLayout {
Log.i("yoyo", "in onGlobalLayout")
val width = value.x - (text.x)
Log.i("yoyo", "Width: $width")
val params: ConstraintLayout.LayoutParams = percentage_bar.layoutParams as ConstraintLayout.LayoutParams
params.matchConstraintMaxWidth = (1.0 * width).toInt() // using 0.1 here - this value is dynamic in real life scenario
percentage_bar.layoutParams = params
}
}
感谢CommonsWare的回答!