How do I make a button without any XML? I tried XML but it did not work and it is "Old" I heard.
Yeah, using XML is old but it's the standard way of defining views in Android. Nowadays exist alternatives to that such as Jetpack Compose which takes a more React style when declaring the GUI where you write #Composable functions that produce a UI. Quite nice.
In any case you can create the views yourself programatically but it's much more tedious, less maintainable and imho 💩
With that said, from your activity you can create instances of any of the layouts that you would use in XML and then add more views into it:
class YourActivty: AppCompatActivity() {
override fun onCreate(...) {
val frameLayout = FrameLayout(this).apply {
// Configure the layout's properties
}
val button = AppCompatButton(this).apply {
// Configure all button's properties
}
frameLayout.addView(button)
// Indicate your activity to use the framelayout as its content
setContentView(frameLayout)
}
}
Related
I have a fragment screen where there is a form that is used to create Questions and Answers for my app. For this fragment, I use data binding, then I created many functions to validate the form, and check other stuffs.
Now, I'm creating a different fragment screen, where I'll be able to edit this Questions and Answers that were created, and for this, I want to use the same functions that were used when I created on the other fragment, for example to validate the fields that the user is editing.
I thought about implementing an Interface, and put these common functions there, so I could use it on both fragments. However, in these functions I use DataBinding, and I don't know how I can use it on the interface, so it would get the correct XML variables regarding to one fragment, or the other one.
On the screenshot bellow, it shows that I'm trying to use the binding, however I can't specify which one I'm using, otherwise the code will work only for a fragment, and not for both. Consequently, I tried to declare as DataBindingUtil but it didn't work.
Screenshot interface
If you want to go with this approach you could add the views as fields in the interface:
interface IQuestionForm {
var newQuestionTextInput: EditText
var answer1TextField: EditText
fun validateAllParametersToCreateNewQuestion(){
var allTextInputSet = true
if (newQuestionTextInput.text.isNullOrEmpty()){
newQuestionTextInput.error = "You have to enter the question"
allTextInputSet = false
}
if (answer1TextField.text.isNullOrEmpty()){
answer1TextField.error = "You have to enter an answer"
allTextInputSet = false
}
....
}
}
Then initialise those fields after creating the binding in the fragment.
I am new in Android TV development.
I use android leanback library for this. Also I I use BrowseSupportFragment and RowsSupportFragmen.
Here I want to customise the HeaderItem shown in the picture.
Specially I want to change its font. I check lots of things but not getting proper solution for this.
Thank You.
If you use BrowseSupportFragment you can use method setHeaderPresenterSelector() and register own presenter for headers. It should inherard from RowHeaderPresenter
If you want to override all header at once then you can create file
res/values/layout/lb_row_header.xml and redefine layout for default header presenter.
Try this:
override fun onBindRowViewHolder(holder: RowPresenter.ViewHolder?, item: Any?) {
super.onBindRowViewHolder(holder, item)
val textView = holder?.headerViewHolder?.view?.findViewById<RowHeaderView>(R.id.row_header)
textView?.run {
setTextColor(Color.WHITE)
setTextSize(TypedValue.COMPLEX_UNIT_SP, 12.5f)
isAllCaps = true
setFontFamily(context, R.font.hind_bold)
}
}
Here is the tutorial
https://www.youtube.com/watch?time_continue=289&v=OGfZpfn-dGI
In my android studio it doesn't recognize the button iv'e name them
android:id="#+id/top_button"
android:text="top button"
android:text="button 2"
android: android:id="#+id/button_2"
top_button.setOnClicklistner {
println(top button was clicked)
Button_2.setOnClicklistner {
println(Button)
We're missing a lot of context here that would probably help us help you.
A few things first though:
- The android:id property in your XML layout is how you name the View in question. This is most often how you will reference the View in code.
- The android:text property is the user visible text on views like TextView.
- In order for top_button to refer to your desired View in your XML layout file, it needs to be bound in code. There's a couple of normal ways of doing it findViewById() and data-binding.
I'm going to assume, for now, that the last step is what you are missing (it seems the most likely culprit at this point)... Here's a few ways to bind it:
Method 1: when using an Activity class
If you're binding top_button to your View from an Activity class, this should work:
private lateinit var top_button // replace View here with your widget's type
fun onCreate(...) {
super.onCreate(...)
setContentView(R.layout.<i>your_layout_file_name_here</i>)
top_button = findViewById(R.id.top_button)
...
}
Method 2: when using a Fragment class
If you're binding top_button to your View from a Fragment class, it's more like this:
private lateinit var top_button: View // replace View here with your widget's type
fun onCreateView(...): View {
val rootView = layoutInflater.inflate(R.layout.<i>your_layout_file_name_here</i>)
top_button = rootView.findViewById(R.id.top_button)
...
return rootView
}
Method 3: when using data-binding
I prefer this method myself, but you should Google how to setup data-binding in Android as you'll need changes in your build.gradle and all.
First, change your XML layout to be:
<layout>
<!-- your existing layout XML here -->
</layout>
Then in your Activity/Fragment, let's say your XML layout file is named activity_my_cool_screen.xml, you can do:
val binding = ActivityMyCoolScreenBinding.inflate(getLayoutInflater())
binding.topButton.setOnClickListener(...)
Notice here that the ActivityMyCoolScreenBinding class is auto-generated for you. If it turns red at first, then first verify you've accurately setup data-binding in your project, then if that's good to go, make sure to import the ActivityMyCoolScreenBinding class. If you change your XML layout's filename, then the ActivityMyCoolScreenBinding class name will change to match automatically. But, I'd recommend if you do change the name, that you use Android Studio's refactoring/renaming tools as it'll search your codebase and update it everywhere. Otherwise, you have to do it by hand (doable, but potentially tedious and error prone).
Good luck!
I'm trying to create a custom View that contains a list of CheckBoxes based on my database. This means I have to create the Views at run-time, and can't do it in XML. However, the method I'm using for this is very slow. Is there a faster method to create large amount of Views in code?
For example, with the 18 types in my database, it can take over 1 second to create all the CheckBoxes.
class FilterView : LinearLayout {
private fun init(types : List<Type>){
... setup
// Creating the CheckBoxes, this takes all the time.
checkboxes = Array(types.size, {
AppCompatCheckBox(context).apply {
text = types[it].type
CompoundButtonCompat.setButtonTintList(this, ColorStateList(states, intArrayOf(colours[it], colours[it])))
}
})
... add to view
}
What your looking for is a Recyclerview. It can all be explained here. The downvote was likely because this is assumed to be common knowledge or easily googled on your own. I was new once too. Here you go.
How to set the child view's width using data binding. The value to set is dynamic and it depends on the width of the parent layout.
item_bar.xml
<LinearLayout
android:id="#+id/barLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="#{model.usedBarWidthPercentage}"
android:layout_height="4dp"/>
</LinearLayout>
The model can give me a percentage. Ex, if the percentage is 40%, it means the width of the textview should be 40% of the parent layout.
I know the idea of using data binding adapters, but dont know how to do it with the parent layout's width.
You can create a class file, example MyBingding.class
#BindingAdapter({ "bindWidth" })
public static void bindWidth(TextView textView, double perc) {
//You can do something by java code here
textView.xxxxxxxx;
}
Then use bindWidth method in XML:
<TextView
app:bindWidth="#{model.usedBarWidthPercentage}"
android:layout_width="wrap_content"
android:layout_height="4dp"/>
Make sure the usedBarWidthPercentage's data type is same as bindWidth method's perc.
I'm afraid you will be disappointed on this one iori24. I tried for qhite a while to figure out how to accomplish this, but some variables can be done post draw and some have to be done pre draw. Binding is meant to be for post draw type of values. layout_width and layout_height are pre draw values that need to be set ahead of time.
Unfortunately there is no current way to do this. I found many articles on it and can confirm this statement. However, I managed to find ways to manipulate my UI with various match parents or weights to accomplish what I needed or adjust in code.
I would love if they brought data binding to layout_width and height, and I think they will eventually, but for now you will just have to get more creative with your design.
If you would like you could provide your full sample code for someone to modify and hand back with potential fixes, but I'm guessing you will need a code option here and not an XML option. Now namezhouyu posted a binding adapter option. This is a postdraw that will take the textview and potentially modify it's value after it has been drawn. This could work, but you may see strange behavior as the original size would be wrap_content and then each subsequent change would cause it to jump to correct size. But I do like his work around, it is a clever solution.
So if you are bound and determined to do it through binding, then I would follow namez houyu's option.
What I end up doing is follow #Raghunandan's suggestion
class ViewHolder(val binding: ItemViewBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(model: Model) {
Logger.d("START")
binding.model = model
val treeObserver = binding.viewLayout.viewTreeObserver
if (treeObserver.isAlive) {
treeObserver.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
override fun onGlobalLayout() {
binding.viewLayout.viewTreeObserver.removeOnGlobalLayoutListener(this) // need to call viewTreeObserver again
val maxValue = binding.viewLayout.width
val usePerc = binding.model.getUsedBarWidthPercentage()
Logger.d("maxValue=$maxValue, usePerc=$usePerc")
binding.view.layoutParams.width = (maxValue * usePerc).toInt()
}
})
}
}
}