简体   繁体   English

以编程方式更改视图属性

[英]change programmatically view propieties

i'm new to kotlin.我是科特林的新手。

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val btnDivide : Button = findViewById(R.id.divideInputButton)
    val btnCancel : Button = findViewById(R.id.cancelInputButton)

I'm trying to change the btnCancel dinamically, just for fun, because i see (i'm new also to xml so i'm wrong maybe) that in xml file i can't do something like android:layout_width="wrap_content*2" or similar dinamic stuff based on the display.我正在尝试以动态方式更改 btnCancel,只是为了好玩,因为我看到(我也是 xml 的新手,所以我可能错了)在 xml 文件中我不能做类似android:layout_width="wrap_content*2"事情android:layout_width="wrap_content*2"或基于显示器的类似动态东西。

So i was trying to do it in MainActivity.kt right after the setContentView(R.layout.activity_main)所以我试图在setContentView(R.layout.activity_main)之后立即在 MainActivity.kt 中执行此操作

Most likley do something like最有可能做类似的事情

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val btnDivide : Button = findViewById(R.id.divideInputButton)
    val btnCancel : Button = findViewById(R.id.cancelInputButton)

    var paramsCancel : LinearLayout.LayoutParams = btnCancel.layoutParams as LinearLayout.LayoutParams
    var paramsDivide : LinearLayout.LayoutParams = btnDivide.layoutParams as LinearLayout.LayoutParams
    paramsCancel.width = paramsDivide.width

is a very bad practice imo, because i'm setting the xml layout -> displaying it on the device-> do some math and operation-> change the values and display the canges; imo 是一个非常糟糕的做法,因为我正在设置 xml 布局 -> 在设备上显示它 -> 做一些数学和运算 -> 更改值并显示 canges; so if the app has a lot of todos after setContentView(R.layout.activity_main ) and before paramsCancel.width = paramsDivide.width the user will see in 2 types of UI during his use of the app.因此,如果应用在setContentView(R.layout.activity_main ) 之后和paramsCancel.width = paramsDivide.width之前有paramsCancel.width = paramsDivide.width则用户在使用应用期间将看到两种类型的 UI。

So, is there a better method to change some params (like btn.width) in programmatically way?那么,是否有更好的方法以编程方式更改某些参数(如 btn.width)? if yes, is that the right way or should i change my mind completely ?如果是,那是正确的方法还是我应该完全改变主意?

In this example i was trying to set the btnCncel width to the width of an other button, but is not working (in the image seems ok but is because i've changed the width manually using dp in the xml file after all the depression).在这个例子中,我试图将 btnCncel 宽度设置为另一个按钮的宽度,但不起作用(在图像中似乎没问题,但这是因为我在所有按下后在 xml 文件中使用 dp 手动更改了宽度) . If i set the width to paramsCancel.width = 100 works( works with Integers in general)如果我将宽度设置为paramsCancel.width = 100有效(一般适用于整数)

在此处输入图片说明

First, you need to convert your integer value to DP for your Button and with layout paramerter you can apply to your button.首先,您需要将您的整数值转换为您的按钮的 DP,并且您可以将布局参数应用于您的按钮。

First Step: Convert Integer value to DP:第一步:将整数值转换为 DP:

val dip = 14f                          <- New value
val r: Resources = resources
val px = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP,
    dip,
    r.displayMetrics
)

After that create and set updated value using layout parameter:之后使用布局参数创建和设置更新值:

button.layoutParams = LinearLayout.LayoutParams(10, MATCH_PARENT)

Your comment about why this would be bad practice:您对为什么这是不好的做法的评论:

"...the user will see in 2 types of UI during his use of the app" “...用户在使用应用程序期间将看到 2 种类型的 UI”

is incorrect.是不正确的。

The way UI layout works is that there is a main thread Looper that handles all tasks that are sent to it. UI 布局的工作方式是有一个主线程 Looper 来处理发送给它的所有任务。 Every time there is an event that affects the UI, a function call is sent to that Looper and it runs through to completion before anything is redrawn to the screen.每次有影响 UI 的事件时,都会向该 Looper 发送一个函数调用,并在将任何内容重绘到屏幕之前运行到完成。

So, for instance, if a button is pressed, the OnClickListener for that button will be called on the main thread and run through to completion before anything is redrawn on the screen.因此,例如,如果按下一个按钮,则该按钮的 OnClickListener 将在主线程上调用并在屏幕上重绘任何内容之前一直运行到完成。 It doesn't matter how many actions you take by the end of your listener's function.在侦听器函数结束时您执行了多少操作并不重要。 That's why you're not supposed to do any blocking (time-consuming) actions on the main thread like writing to a file.这就是为什么您不应该在主线程上执行任何阻塞(耗时)操作,例如写入文件。 That would freeze the UI while the file is being written.这会在写入文件时冻结 UI。

So even if you modify 100 different buttons' layout params and colors sequentially, the user will not see any changes until after the function returns.因此,即使您按顺序修改 100 个不同按钮的布局参数和颜色,用户在函数返回之前也不会看到任何更改。

The same is true for onCreate() . onCreate()也是如此。 The user will not see anything from your Activity until after onCreate() returns.onCreate()返回之前,用户不会从您的 Activity 中看到任何内容。

If your calculator does some calculation that takes so long that you're afraid it will freeze the UI noticeably, correct practice would be to first lock the buttons (disable them or set some Boolean property that all their listeners check to determine if they should work), then show some progress indicator, then launch a background thread or coroutine to do the work, and then when the calculation is done, unlock everything and show the result.如果您的计算器进行了一些需要很长时间的计算,以至于您担心它会明显冻结 UI,正确的做法是首先锁定按钮(禁用它们或设置一些所有监听器检查的布尔属性以确定它们是否应该工作),然后显示一些进度指示器,然后启动一个后台线程或协程来完成工作,然后当计算完成时,解锁所有内容并显示结果。

Realistically, you don't need to do that for a simple calculator.实际上,对于一个简单的计算器,您不需要这样做。 It's not like you're manipulating a huge data set.这不像你在操纵一个巨大的数据集。

View sizes set in Kotlin must be done in integer pixel units.在 Kotlin 中设置的视图大小必须以整数像素为单位完成。 You can search for other questions on here about how to convert dp units into pixel units.您可以在此处搜索有关如何将dp单位转换为像素单位的其他问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM