How to use anko spinner? - android

I'm trying to add a spinner inside an alert using anko. My code so far looks like this:
alert(getString(R.string.alert)) {
positiveButton("Cool") { toast("Yess!!!") }
customView {
linearLayout {
textView("I'm a text")
padding = dip(16)
orientation = LinearLayout.VERTICAL
spinner(R.style.Widget_AppCompat_Spinner) {
id = R.id.spinner_todo_category
prompt = "Select a Category"
}
}
}
}.show()
but I get compilation errors because apparently that's not how to call a spinner. I've been looking at the docs (Anko GitHub Wiki) but it says nothing about spinners.
Thanks in advance

One solution :
class AddActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val items = listOf(Friend("bla","bla",50),Friend("bla","bla",50));
val adapterFriends = ArrayAdapter(this,R.layout.mon_spinner,items)
verticalLayout {
val friends = spinner { adapter = adapterFriends }
val wine = editText()
button("Say Hello") {
onClick { toast("Hello, ${wine.text}!") }
}
}
}
}
with this layout (mon_spinner.xml) :
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="14sp"
android:textColor="#color/colorPrimary"
android:spinnerMode="dialog"
android:text="XXX"
/>
It's all right !!

Try this in your AnkoComponent:
spinner {
adapter = ArrayAdapter.createFromResource(
ctx,
R.array.your_string_array,
android.R.layout.simple_spinner_dropdown_item)
}

Related

How to add a calendar header in kotlin

I am using this library, https://github.com/kizitonwose/CalendarView, to create a calendar view. I've followed the docs to add the month header.
I've add the following to res/layout/calendar_month_header_layout.xml:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/headerTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:textSize="26sp"
tools:text="October 2019" />
also added the following to the activity xml:
<com.kizitonwose.calendarview.CalendarView
android:id="#+id/month_header"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cv_dayViewResource="#layout/calendar_day_layout"
app:cv_monthHeaderResource="#layout/calendar_month_header_layout" />
I've also added the following code:
val monthHeader: com.kizitonwose.calendarview.CalendarView = findViewById(R.id.month_header)
monthHeader.monthHeaderBinder = object : MonthHeaderFooterBinder<MonthViewContainer> {
override fun create(view: View) = MonthViewContainer(view)
override fun bind(container: MonthViewContainer, month: CalendarMonth) {
println("TEST")
container.textView.text = "${month.yearMonth.month.name.toLowerCase().capitalize()} ${month.year}"
}
}
However, nothing shows up for the activity. What am I missing? Thank you.
EDIT:
I notice the println("TEST") statement doesn't even get logged
Looks like the problem was I had to have the DayBinder too. The monthHeaderBinder on it's own results in a null error. Below is the working code
val currentMonth = YearMonth.now()
val firstMonth = currentMonth.minusMonths(10)
val lastMonth = currentMonth.plusMonths(10)
val firstDayOfWeek = WeekFields.of(Locale.getDefault()).firstDayOfWeek
setContentView(R.layout.activity_calender_view)
var calendarView: com.kizitonwose.calendarview.CalendarView = findViewById(R.id.calendarView)
calendarView.dayBinder = object : DayBinder<DayViewContainer> {
// Called only when a new container is needed.
override fun create(view: View) = DayViewContainer(view)
// Called every time we need to reuse a container.
override fun bind(container: DayViewContainer, day: CalendarDay) {
container.textView.text = day.date.dayOfMonth.toString()
}
}
calendarView.setup(firstMonth, lastMonth, firstDayOfWeek)
calendarView.scrollToMonth(currentMonth)
calendarView.monthHeaderBinder = object : MonthHeaderFooterBinder<MonthViewContainer> {
override fun create(view: View) = MonthViewContainer(view)
override fun bind(container: MonthViewContainer, month: CalendarMonth) {
container.textView.text = "${month.yearMonth.month.name.toLowerCase().capitalize()} ${month.year}"
}
}
And the activity xml:
<com.kizitonwose.calendarview.CalendarView
android:id="#+id/calendarView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cv_dayViewResource="#layout/calendar_day_layout"
app:cv_monthHeaderResource="#layout/calendar_month_header_layout"/>

How to reverse View Binding from custom tab layout in Android?

I made a custom tab item for my tab layout and initialized it using view binding as follows:
val tabView = CustomTabBinding.inflate(LayoutInflater.from(mContext), null, false)
tabView.tvCustomTabTitle.text = it.title
tabView.tvCustomTabCount.visibility = View.GONE
Now when the user selects/unselects the tab I want to change the appearance of this custom view. Usually I achieved this using kotlin synthetics as follows:
fun setOnSelectView(tabLayout: TabLayout, position: Int = 0) {
val tab = tabLayout.getTabAt(position)
val selected = tab?.customView
if (selected != null)
selected.tv_custom_tab_title?.apply {
setTextColor(mContext.getColorCompat(R.color.colorAccent))
typeface = setFont(true)
}
selected?.tv_custom_tab_count?.apply {
setBackgroundResource(R.drawable.bullet_accent)
mContext.getColorCompat(android.R.color.white)
}
}
But now how do I achieve this using view binding?
I am using the method of findViewById():
fun Context.setOnSelectView(tabLayout: TabLayout, position: Int = 0) {
val tab = tabLayout.getTabAt(position)
val selected = tab?.customView
if (selected != null){
val title = selected.findViewById<TextView>(R.id.tv_custom_tab_title)
val count = selected.findViewById<TextView>(R.id.tv_custom_tab_count)
title.apply {
setTextColor(getColorCompat(R.color.colorAccent))
typeface = setFont(true)
}
count.apply {
setBackgroundResource(R.drawable.bullet_accent)
getColorCompat(android.R.color.white)
}
}
}
but I am hoping there is a better way to do this. If yes, then please do help me out.
Late reply but this is how I used view binding for custom tab layout, hope it helps
custom_tab.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tv_custom_tab_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/tv_custom_tab_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
your activity/fragment:
val tab = binding.tabLayout.getTabAt(position)
tab.setCustomView(R.layout.custom_tab)
val tabBinding = tab.customView?.let {
CustomTabBinding.bind(it)
}
tabBinding?.tvCustomTabTitle?.text = "your title here"

How to increment counter of notification badge from adapter kotlin

I am trying to build an E-commerce app having basic functionalities. I want my number of items in the cart to reflect on the action bar. Currently, my UI looks like this.
For creating the notifications this is what I have done:
cart_layout.xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="55sp"
android:paddingRight="10sp"
android:gravity="center">
<ImageView
android:id="#+id/cart_img"
android:layout_width="30sp"
android:layout_height="30sp"
android:background="#drawable/shopping"
android:foreground="?attr/selectableItemBackgroundBorderless" />
<TextView
android:id="#+id/item_count"
android:layout_width="18sp"
android:textAlignment="center"
android:layout_height="18sp"
android:textColor="#android:color/white"
android:text="0"
android:textSize="12sp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="21dp"
android:layout_marginTop="5dp"
android:background="#drawable/itemcount" />
</RelativeLayout>
</RelativeLayout>
My cart_menu.xml inside the menu directory looks like:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/select_cart"
app:showAsAction="always"
app:actionLayout="#layout/cart_layout"
android:title="Cart"/>
<item android:id="#+id/toolbar_search"
android:title="Search"
android:icon="#drawable/ic_search_black_24dp"
app:showAsAction ="always"
app:actionViewClass="android.widget.SearchView"/>
</menu>
My onCreateOptionsMenu functions inside Activity looks like this:
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.cart_menu, menu)
val count:View = menu!!.findItem(R.id.select_cart).actionView
val itemText:TextView = count.findViewById(R.id.item_count)
if(cartList.size == 0){
itemText.visibility = View.INVISIBLE
}
if(cartList.size > 0) {
itemText.visibility = View.VISIBLE
itemText.text = cartList.size.toString()
}
return true
}
Here cartList is the MutableList of items in the cart.
What I want to do is update the counter of this cart whenever the user clicks "Add to cart" button.
The click listener for this button is present inside Adapter class.
My onclicklistener inside onBindViewHolder inside ProductAdapter.kt looks like this:
holder.addToCart.setOnClickListener {
holder.count.number = 1.toString()
Log.d("Product","Clicked ${product.name}, count = ${holder.count.number}")
val cartItemObj = CartItem(product.name,product.imageUrl, product.size, product.price, holder.count.number)
val db = CartDatabase(context)
val result = db.insertData(cartItemObj)
if(result == (-1).toLong()){
Log.d("ProductAdapter","Error in Inserting values")
return#setOnClickListener
}
holder.addToCart.visibility = View.INVISIBLE
holder.count.visibility = View.VISIBLE
cartList.add(cartItemObj)
// SOME CODE HERE TO UPDATE THE NUMBER OF ITEMS IN CART
}
I don't understand how should I achieve this since I am unable to access the Textview inside the Adapter.
The link to the complete project is:
Here
Define cart count
var cartCounter: Int? = 0
//private lateinit var itemText: TextView
lateinit var itemText: TextView
Then Update it in onCreateOptionsMenu method
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.cart_menu, menu)
val count:View = menu!!.findItem(R.id.select_cart).actionView
itemText:TextView = count.findViewById(R.id.item_count)
if(cartList.size == 0){
itemText.visibility = View.INVISIBLE
}
if(cartList.size > 0) {
cartCounter = cartList.size;
itemText.visibility = View.VISIBLE
itemText.text = cartCounter.toString()
}
return true
}
Finally when user click on add to cart update it again
holder.addToCart.setOnClickListener {
holder.count.number = 1.toString()
val cartItemObj = CartItem(product.name,product.imageUrl, product.size, product.price, holder.count.number)
val db = CartDatabase(context)
val result = db.insertData(cartItemObj)
if(result == (-1).toLong()){
Log.d("ProductAdapter","Error in Inserting values")
return#setOnClickListener
}
holder.addToCart.visibility = View.INVISIBLE
holder.count.visibility = View.VISIBLE
cartList.add(cartItemObj)
cartCounter = cartCounter + 1;
// or cartCounter = cartCounter + quantity_of_item;
itemText.text = cartCounter.toString()
}
I am unable to access the Textview inside the Adapter
Your adapter should not know anything about the menu and its items. But it can expose some observable field which can be monitored by an entity owning the menu - I guess it is either your Fragment or Activity. The easiest way to achieve this nowadays is by using LiveData. Create a new instance of it somewhere in your adapter:
class YourAdapter ... {
val cartSize = MutableLiveData<Int>()
}
and update it from your click listener. Now you can observe this livedata from your fragment like this
override fun onViewCreated(...) {
adapter.cartSize.observe(viewLifecycleOwner, Observer {
cartSize -> updateMenuCounter(cartSize)
}
}
The last step here is to implement the updateMenuCounter which can access the previously created MenuItem and update its TextView.

How to change drawableEnd property of TextView

I have a Textview which I set the property drawableRight from my xml file, now I will like to change the drawable programatically.
I want when clicked, drawable icon/image should change from let say btn_up to btn_down.
Below is what I tried so far:
Class:
requireText.SetOnClickListener {
requireText.drawableRight = resources.getDrawable(R.drawable.btn_up)
}
xml:
<TextView
android:id="#+id/requireText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:background="#null"
android:clickable="true"
android:drawableRight="#drawable/btn_down"/>
How do I solve this? Thanks in advance.
There is no .drawableRight or Left, not yet for now, you can try below code:
class SampleActivity : AppCompatActivity() {
var up = true
var drawable: Drawable ?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_signup)
userName.setOnClickListener {
if(up){
up = false
drawable = resources.getDrawable(com.exolve.eros.R.drawable.sampleDownDrawable)
}else{
up = true
drawable = resources.getDrawable(com.exolve.eros.R.drawable.sampleUpDrawable)
}
drawable!!.setBounds(0, 0, 10, 10)
userName.setCompoundDrawables(drawable, null, null, null)
}
}
}
An update to the fact that you want to switch the drawable on click.
Try
var isClicked = false // declare this at top
requireText.setOnClickListener{
requireText.setCompoundDrawablesWithIntrinsicBounds(0, 0,
if(!isClicked) R.drawable.btn_up else R.drawable.btn_down, 0)
isClicked = !isClicked
}
try this code to set drawable right in kotlin class
val my_text_view = findViewById(R.id.my_text_view)
my_text_view.setOnClickListener(View.OnClickListener { my_text_view.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_arrow_upward_black_24dp, 0) })

ternary operator for drawable in layout expression

This is my fragment_setting.xml.
<ToggleButton
android:layout_width="47dp"
android:layout_height="27dp"
android:background="#{settingVm.isNotiOn ? #drawable/btn_on_mid : #drawable/btn_off_mid}"
android:onClick="#{()->settingVm.changeBtnStatus()}"
android:text="#string/on"
android:textOff="on"
android:textOn="on"
android:textSize="11sp"
android:textStyle="bold" />
<ToggleButton
android:layout_width="47dp"
android:layout_height="27dp"
android:background="#{settingVm.isNotiOn ? #drawable/btn_off_mid : #drawable/btn_on_mid}"
android:onClick="#{()-> settingVm.changeBtnStatus()}"
android:text="#string/off"
android:textOff="off"
android:textOn="off"
android:textSize="11sp"
android:textStyle="bold" />
This is my SettingViewModel
class SettingViewModel(handler: SettingHandler) : ViewModel() {
var handler = handler
var isNotiOn: Boolean? = true
var visibility = View.VISIBLE
init {
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
Timber.d("start")
}
}
fun onBackBtnPressed() {
Timber.d("onBackBtnPressed()")
handler.onBackBtnPressed()
}
fun showLogoutDialogue() {
Timber.d("showLogoutDialogue()")
handler.showLogoutDialogue()
}
fun changeBtnStatus(){
Timber.d("changeBtnStatus()")
handler.changeBtnStatus()
}
}
And this is my SettingFragment
...
val spUtil = SharedPreferenceUtil(activity!!)
when (spUtil.isNotificationOn) {
false -> {
binding!!.settingVm!!.isNotiOn = false
}
else -> {
binding!!.settingVm!!.isNotiOn = true
}
}
...
override fun changeBtnStatus() {
// TODO: Set real notification setting.
val spUtil = SharedPreferenceUtil(activity!!)
when (binding!!.settingVm!!.isNotiOn) {
true -> {
binding!!.settingVm!!.isNotiOn = false
spUtil.isNotificationOn = false
}
else -> {
binding!!.settingVm!!.isNotiOn = true
spUtil.isNotificationOn = true
}
}
}
What's the problem??? I am not using two way binding and the ternary operator like #={}. But I reckon I should use two way binding because it is not a constant value. And I have two images correctly.
Someone says I should not use is prefix because it might generate getter and setter. So, I even tried removing it and define has prefix or just NotiOn but didn't work.
Please try this code once ## Your XML should be in the code is look like this
<ToggleButton
android:layout_width="match_parent"
android:layout_height="match_parent"
android:button="#{settingVm.isNotiOn ? #drawable/btn_on_mid : #drawable/btn_off_mid}"/>
and the following java code you can reduce and get the result in proper form. please use this code on fragment class.
val spUtil = SharedPreferenceUtil(activity!!) tbutton.setOnCheckedChangeListener { buttonView, isChecked -> spUtil.isNotificationOn = isChecked binding!!.settingVm!!.isNotiOn = isChecked }
========================================================================
You can use a MutableLiveData in order to change the status and observe that inside the fragment to get live update and you can change the drawable values according to this LiveData
ViewModel.kt
class GuestViewModel #Inject constructor(val repo: GuestRepository) : ViewModel() {
val guest = MutableLiveData<Guest>()
val guestLoading = MutableLiveData<Boolean>()
}
Fragment.kt
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final TestViewModel viewModel = ViewModelProviders.of(getActivity()).get(TestViewModel.class);
viewModel.guestLoading.observe(this, it -> {
//Do something
});
}

Categories

Resources