I want to dynamically create input views, which each contain an AutoCompleteTextView. Each AutoCompleteTextView shows a Dropdown list.
I have defined an item view (item_new_product.xml), which gets inflated and added to the viewContainer (activity_main.xml).
Each AutoCompleteTextView has defined a dropDownAnchor in xml, which is the view ID of its parent TextInputLayout. This is where the dropdown list should show up.
For the first item the Dropdown appears in the right place (see Screenshot 1). But each additional Dropdown is associated to the first AutoCompleteTextView's TextInputLayout, because they all have the same dropDownAnchor id(see Screenshot 2).
Is there a clean way to show the Dropdown lists at the right place having multiple dynamically created AutoCompleteTextViews? I have not found anything related to this specific issue.
activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.card.MaterialCardView
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:backgroundTint="#android:color/holo_blue_dark"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.button.MaterialButton
android:id="#+id/addButton"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_gravity="start"
android:background="#color/holo_blue_bright"
android:elevation="5dp"
android:text="+" />
<com.google.android.material.button.MaterialButton
android:id="#+id/removeButton"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_gravity="end"
android:background="#color/holo_blue_bright"
android:elevation="5dp"
android:text="-" />
</com.google.android.material.card.MaterialCardView>
<LinearLayout
android:id="#+id/viewContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="16dp"
android:animateLayoutChanges="true"
android:background="#color/holo_blue_dark"
android:orientation="vertical"
android:padding="8dp"
app:layout_constraintTop_toBottomOf="#id/cardView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
item_new_product.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintGuide_percent=".5" />
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/productText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:hint="Product"
app:hintTextColor="#color/holo_blue_dark"
app:helperText=" "
app:boxBackgroundColor="#color/holo_blue_bright"
app:boxStrokeColor="#color/holo_blue_dark"
app:layout_constraintEnd_toStartOf="#+id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/productEditText"
android:layout_width="match_parent"
android:layout_height="52dp"
android:textSize="12sp"
android:imeOptions="actionNext"
android:inputType="textPersonName"
android:textCursorDrawable="#null" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/productTypeLayout"
style="#style/DropdownLayoutStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:hint="Type"
app:helperText=" "
android:inputType="none"
app:boxBackgroundColor="#color/holo_blue_bright"
app:boxStrokeColor="#color/holo_blue_dark"
app:endIconTint="#color/holo_blue_dark"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="#id/guideline"
app:layout_constraintEnd_toEndOf="parent">
<AutoCompleteTextView
android:id="#+id/productTypeAutoCompleteTv"
android:layout_width="match_parent"
android:layout_height="52dp"
android:dropDownAnchor="#id/productTypeLayout"
android:dropDownHeight="120dp"
android:inputType="none"
android:maxLines="1"
android:textSize="12sp"
android:singleLine="true"
android:paddingStart="16dp"
android:paddingEnd="16dp"/>
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var IDs = mutableListOf<Int>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
binding.addButton.setOnClickListener {
Timber.d("add clicked")
addView()
}
binding.removeButton.setOnClickListener {
Timber.d("remove clicked")
removeView()
}
setContentView(binding.root)
}
private fun addView() {
Timber.d("addView")
val rootView = binding.viewContainer
val inflater = LayoutInflater.from(this)
val child: View = inflater.inflate(R.layout.item_new_product, rootView, false)
// generate new view id and remember it for later removal
val childId = View.generateViewId()
child.id = childId
IDs.add(childId)
val items: List<String> = listOf("Beverages", "Cocktails", "Pasta", "Pizza", "Salads")
val adapter = ArrayAdapter(this, R.layout.item_product_dropdown, items)
val productAutoComplete =
child.findViewById(R.id.productTypeAutoCompleteTv) as AutoCompleteTextView
productAutoComplete.setAdapter(adapter)
rootView.addView(child)
}
private fun removeView() {
if (IDs.size == 0) {
return
}
val view: View? = findViewById<View>(IDs.last())
IDs.removeLast()
if (view != null) {
(view.parent as ViewGroup).removeView(view)
}
}
styles.xml
<resources>
<style name="DropdownLayoutStyle" parent="Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu">
<item name="endIconTint">#color/holo_blue_dark</item>
<item name="hintTextColor">#color/holo_blue_dark</item>
</style>
</resources>
item_product_dropdown.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="#color/holo_blue_bright"
android:maxLines="1"
android:padding="16dp"
android:textColor="#color/white" />
Related
I am Trying to Achieve the Exposed Drop-Down Menu in Android I have tried this one but can't identify where I went wrong.
DropDown_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textview.MaterialTextView
android:id="#+id/textViewFeelings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp"
android:text="TextView"
android:textColor="#color/black"
android:textSize="18sp"
android:textStyle="bold" />
</androidx.appcompat.widget.LinearLayoutCompat>
BottomSheetDialogConnectWifiFragment.kt
class BottomSheetDialogConnectWifiFragment : BottomSheetDialogFragment() {
private lateinit var _binding: FragmentBottomSheetDialogConnectWifiBinding
private val items = listOf("Material", "Design", "Components", "Android")
private lateinit var ActivityContext: Context
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onAttach(context: Context) {
ActivityContext = context
super.onAttach(context)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentBottomSheetDialogConnectWifiBinding.inflate(inflater, container, false)
return _binding.root
//
// val arrayAdapter = ArrayAdapter(_binding.root.context, R.layout.dropdown_item, items)
// _binding.autoCompleteTextFieldSsidType.setAdapter(arrayAdapter)
_binding.autoCompleteTextFieldSsidType.apply {
setAdapter(
ArrayAdapter(
ActivityContext,
R.layout.dropdown_item,
items
)
)
}
}
companion object {
const val TAG = "CustomBottomSheetDialogFragment"
}
}
fragment_bottom_sheet_dialog_connect_wifi
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView 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:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
tools:context=".Fragments.BottomSheetDialogConnectWifiFragment">
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<androidx.cardview.widget.CardView
android:layout_width="100dp"
android:layout_height="2dp"
android:layout_centerHorizontal="true"
android:elevation="10dp"
android:foregroundGravity="center_vertical"
app:cardBackgroundColor="#color/black"
app:cardCornerRadius="100dp">
<!--YOUR CONTENT-->
</androidx.cardview.widget.CardView>
<com.google.android.material.textview.MaterialTextView
android:id="#+id/idTVCourseTracks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Add Network"
android:textAlignment="center"
android:textColor="#color/black"
android:textSize="15sp" />
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/tilSsid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/idTVCourseTracks"
android:keyboardNavigationCluster="true">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter The SSID" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/textFieldSsidType"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/tilSsid"
android:layout_marginTop="12dp">
<AutoCompleteTextView
android:id="#+id/autoCompleteTextFieldSsidType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Enter The SSID"
android:inputType="none" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/textFieldPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/textFieldSsidType"
android:layout_marginTop="12dp">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="#+id/idBtnDismiss"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/textFieldPassword"
android:layout_marginTop="12dp"
android:text="Connect"
android:textAllCaps="false"
android:theme="#style/ShapeAppearanceOverlay.Material3.Button" />
</RelativeLayout>
</ScrollView>
</com.google.android.material.card.MaterialCardView>
I Created An bottomSheet in Android/kotlin and trying to solve this cant understood where i missing some thing to
i have try with .Apply{}Method And also with the normally but both of them not worked for me
Using com.google.android.material:material:1.6.1, when setting hint enabled to true and then to false, the outline gets broken. Here is the example code.
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val someHintButton = findViewById<MaterialButton>(R.id.someHintButton)
val noHintButton = findViewById<MaterialButton>(R.id.noHintButton)
val textInput = findViewById<TextInputEditText>(R.id.textInput)
val textLayout = findViewById<TextInputLayout>(R.id.textLayout)
someHintButton.setOnClickListener {
textInput.setText("Some text")
textLayout.setHintEnabled(true)
textLayout.setHint("Entered text:")
}
noHintButton.setOnClickListener {
textLayout.setHint(null)
textLayout.setHintEnabled(false)
textInput.setText("Some text will be entered here")
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.textfield.TextInputLayout
android:layout_marginTop="5dp"
android:layout_marginHorizontal="5dp"
android:id="#+id/textLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
>
<com.google.android.material.textfield.TextInputEditText
android:focusable="false"
android:editable="false"
android:id="#+id/textInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Here some text"
android:textAlignment="center"
android:inputType="none"
/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="#+id/someHintButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="bottom"
android:text="some hint"
android:textColor="#color/black"
android:textColorLink="#FFFFFF"
app:backgroundTint="#FFFFFF"
app:cornerRadius="8dp"
android:layout_marginBottom="16dp"
android:layout_marginStart="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
<com.google.android.material.button.MaterialButton
android:id="#+id/noHintButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No hint"
android:textColor="#color/black"
android:textColorLink="#FFFFFF"
app:backgroundTint="#FFFFFF"
app:cornerRadius="8dp"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
Screen after launch:
Screen after 'Some hint' pressed:
Screen after 'No hint' pressed:
setHint(null) or setHint("") don't do any difference. Why doesn't outline get reconnected? Please advise.
I have recyclerview to show my order items but it has design issue and after 3 days changing it I have no other solution for it!
screenshot
Issues
Recyclerview is not covering page full height
Items have space same as recyclerview height (it shows 1 item per page!)
Code
fragment_order.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/orderItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.OrdersFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/orders_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
order_items.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:id="#+id/cardView2"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginBottom="5dp"
app:cardElevation="2dp"
android:layout_margin="5dp">
<FrameLayout
android:background="#color/orders"
android:layout_width="4dp"
android:layout_height="match_parent"/>
<TextView
android:id="#+id/order_Iid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:gravity="start|top"
android:text="#string/order_ID"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="#+id/order_status_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
android:layout_marginStart="10dp"
android:layout_marginTop="35dp"
android:text="#string/order_status"
android:textColor="#5CDCBD"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="#+id/order_price_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_marginEnd="10dp"
android:text="#string/price"
android:textSize="12sp"
android:textStyle="bold" />
</androidx.cardview.widget.CardView>
</LinearLayout>
OrdersFragment.kt
class OrdersFragment : Fragment() {
lateinit var sesssion: SessionManager
lateinit var laundriesRecycler: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val root = inflater.inflate(R.layout.fragment_orders, container, false)
sesssion = SessionManager(context)
laundriesRecycler = root.findViewById(R.id.orders_list)
getOrders()
return root
}
private fun getOrders() {
var session = SessionManager(context)
session.checkLogin()
var user = session.getUserDetails()
var token: String? = user.get(SessionManager.KEY_ACCESS_TOKEN)
val tokenFull = "Bearer $token"
val queue = Volley.newRequestQueue(context)
val url = "https://example.com/api/orders"
val stringReq : StringRequest =
object : StringRequest(
Method.GET, url,
Response.Listener { response ->
val list = Gson().fromJson(response, OrderArr::class.java)
laundriesRecycler.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
laundriesRecycler.adapter = OrdersAdapter(context, list)
},
Response.ErrorListener {
Toast.makeText(context, R.string.errorMessage, Toast.LENGTH_LONG)
.show()
}
){
override fun getHeaders(): Map<String, String> {
val headers = HashMap<String, String>()
headers["Content-Type"] = "application/json"
headers["Authorization"] = tokenFull
return headers
}
}
queue.add(stringReq)
}
}
Any idea?
Update
OrdersAdapter.kt
class OrdersAdapter(
val context: Context?,
private var orderList: OrderArr
) : RecyclerView.Adapter<OrdersAdapter.OrderViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrdersAdapter.OrderViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(
R.layout.orders_items,
parent,
false
)
//fixing width issue
val outMetrics = DisplayMetrics()
val display = parent.display
display?.getRealMetrics(outMetrics)
itemView.layoutParams = RecyclerView.LayoutParams(outMetrics.widthPixels, RecyclerView.LayoutParams.MATCH_PARENT)
return OrdersAdapter.OrderViewHolder(itemView)
}
override fun onBindViewHolder(holder: OrdersAdapter.OrderViewHolder, position: Int) {
val currentItem = orderList.data[position]
holder.orderId.text = "ID: " + currentItem.id
holder.price.text = if(currentItem.amount!= null){"Rp. " + currentItem.amount + " /KG"}else{"Not provided"}
holder.status.text = if(currentItem.lastProgress!= null) {currentItem.lastProgress.progress.name} else{"Unknown"}
holder.itemView.setOnClickListener {
val i: Intent = Intent(context, OrdersActivity::class.java)
i.putExtra("orderIDArgument", currentItem.id.toString())
it.context.startActivity(i);
}
}
override fun getItemCount() = orderList.data.size
class OrderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val orderId: TextView = itemView.findViewById(R.id.order_Iid)
val status: TextView = itemView.findViewById(R.id.order_status_text)
val price: TextView = itemView.findViewById(R.id.order_price_text)
}
}
Update 2
Activity_main.xml
Every fragment will replace each other inside this activity
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="56dp">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragmentFragmentId"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/main_graphs"
tools:context=".MainActivity" />
</ScrollView>
<!--bottom navigation bar with items-->
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#color/colorPrimaryNewTheme"
android:backgroundTint="#color/colorPrimaryNewTheme"
app:backgroundTint="#android:color/white"
app:fabAlignmentMode="end"
app:fabCradleMargin="10dp"
app:fabCradleRoundedCornerRadius="20dp"
app:fabCradleVerticalOffset="14dp"
app:hideOnScroll="true"
app:menu="#menu/bottom_menu"
tools:ignore="BottomAppBar,MissingConstraints" />
<!--Floating action button which is anchored to the bottom navigation button-->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="#color/colorPrimaryNewTheme"
android:contentDescription="#string/app_name"
android:src="#drawable/order"
app:backgroundTint="#color/colorPrimaryNewTheme"
app:layout_anchor="#id/bottomAppBar"
app:layout_dodgeInsetEdges="bottom"
tools:ignore="MissingConstraints" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Update 3
fragment_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.MainFragment">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/header_imageP"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="#string/himage"
android:scaleType="centerCrop"
android:src="#drawable/main_header"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="42dp"
android:layout_marginTop="31dp"
android:textColor="#FFFFFF"
android:text="#string/nameHint" />
<TextView
android:id="#+id/useremail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/username"
android:layout_alignParentStart="true"
android:layout_marginStart="42dp"
android:layout_marginTop="8dp"
android:textColor="#FFFFFF"
android:text="#string/emailHint" />
<ImageView
android:id="#+id/logo"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_below="#+id/useremail"
android:layout_alignParentStart="true"
android:layout_marginStart="41dp"
android:layout_marginTop="13dp"
android:contentDescription="#string/himage"
android:src="#drawable/logo" />
<TextView
android:id="#+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginStart="21dp"
android:layout_marginTop="118dp"
android:layout_toEndOf="#+id/logo"
android:text="#string/app_name"
android:textColor="#FFFFFF"
android:textSize="18sp"
android:textStyle="bold" />
<RelativeLayout
android:id="#+id/t1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_below="#+id/header_imageP"
android:layout_marginTop="4dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="6dp"
android:text="HIIII" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/t2"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_below="#+id/t1"
android:layout_marginTop="4dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="6dp"
android:text="BYEEEE" />
</RelativeLayout>
</RelativeLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
First remove code for customizing width and height of recycler item view inside Adapter.
Like:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrdersAdapter.OrderViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(
R.layout.order_item,
parent,
false
)
//fixing width issue
/*val outMetrics = DisplayMetrics()
val display = parent.display
display?.getRealMetrics(outMetrics)
itemView.layoutParams = RecyclerView.LayoutParams(outMetrics.widthPixels, RecyclerView.LayoutParams.MATCH_PARENT)*/
return OrdersAdapter.OrderViewHolder(itemView)
}
Second, you are not putting any constraint to FragmentContainerView thats why it goes to (0,0) position by default and you have set it's height to wrap_content, so your recycler view looks like the posted image. And it is not recommended to use recycler view inside scroll view. Try with customizing Activity_main.xml as below:
<androidx.constraintlayout.widget.ConstraintLayout
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/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:fabAlignmentMode="end"
app:fabCradleMargin="10dp"
app:fabCradleRoundedCornerRadius="20dp"
app:fabCradleVerticalOffset="14dp"
app:hideOnScroll="true"
app:menu="#menu/bottom_menu"
tools:ignore="BottomAppBar,MissingConstraints"
app:layout_constraintBottom_toBottomOf="parent"/>
<fragment
android:id="#+id/nav_view"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="#+id/bottomAppBar"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/main_graphs" />
<!-- put FAB here -->
</androidx.constraintlayout.widget.ConstraintLayout>
How can I make a custom view to take only 33% of the screen and make it show proportionately on every device?
This should be handled either on the xml files below, or in the custom view kotlin class, since it's part of a library and I don't have access to the view that will host my custom class.
buff_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="#+id/mainLinearLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="#layout/buff_sender"/>
<include layout="#layout/buff_question"/>
<LinearLayout
android:id="#+id/answersContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
</LinearLayout>
buff_sender.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/light_bg"
android:orientation="horizontal"
tools:ignore="RtlHardcoded">
<ImageView
android:id="#+id/sender_image"
android:layout_width="27dp"
android:layout_height="27dp"
android:layout_gravity="center_vertical"
android:padding="4dp" />
<TextView
android:id="#+id/sender_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="4dp"
tools:text="Praveen"
android:textColor="#color/test_color_dark"
android:textStyle="bold" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageButton
android:id="#+id/buff_close"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_alignParentEnd="true"
android:background="#drawable/ic_btn_close" />
</RelativeLayout>
buff_question.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/dark_bg"
android:orientation="horizontal">
<TextView
android:id="#+id/question_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:padding="18dp"
android:textColor="#color/test_color_light"
android:textStyle="bold"
tools:text="Where do you think Jorge will put this penalty? I'd go left here! Hehehehehehehehehehe super long text" />
<FrameLayout
android:layout_width="32dp"
android:layout_height="32dp">
<ProgressBar
android:id="#+id/question_time_progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:indeterminate="false"
android:indeterminateDuration="1"
android:max="100"
android:progress="0" />
<TextView
android:id="#+id/question_time"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#color/test_color_light"
android:textStyle="bold"
tools:text="14" />
</FrameLayout>
</LinearLayout>
buff_answer.xml (which will be injected in the answersContainer from buff_view.xml dynamically depending on the number of answers available for that question)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="#drawable/light_bg"
android:orientation="horizontal"
tools:ignore="RtlHardcoded">
<ImageView
android:id="#+id/answer_image"
android:layout_width="27dp"
android:layout_height="27dp"
android:layout_gravity="center_vertical"
android:src="#drawable/ic_generic_answer"
android:padding="4dp" />
<TextView
android:id="#+id/answer_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="4dp"
android:textColor="#color/test_color_dark"
tools:text="The keeper's right"
android:textStyle="bold" />
</LinearLayout>
BuffView.kt
class BuffView #JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
: LinearLayout(context, attrs) {
private val apiErrorHandler = ApiErrorHandler()
private val getBuffUseCase = GetBuffUseCase(apiErrorHandler)
private val intervalsHandler = Handler()
private val buffView: LinearLayout = inflate(context, R.layout.buff_view, this) as LinearLayout
private var errorListener: ErrorListener? = null
private var countDownTimer: CountDownTimer? = null
private var buffIdCount = 1
private var getBuffs = false
fun init() {
getBuffs = true
getBuff()
}
private fun getBuff() {
if (!getBuffs) return
getBuffUseCase.invoke(Params(buffIdCount.toLong()), object : UseCaseResponse<Buff> {
override fun onSuccess(result: Buff) {
displayBuff(result)
}
override fun onError(errorModel: ErrorModel?) {
errorListener?.onError( errorModel?.message?: "An error has occurred")
hideBuff()
}
})
if (buffIdCount < TOTAL_BUFFS ) {
intervalsHandler.postDelayed({
buffIdCount++
getBuff()
stopCountDownTimer()
}, REQUEST_BUFF_INTERVAL_TIME)
}
}
private fun displayBuff(buff: Buff) {
setQuestion(buff.question.title)
setAuthor(buff.author)
setAnswer(buff.answers)
setProgressBar(buff.timeToShow)
setCloseButton()
invalidate()
showBuff()
}
private fun setQuestion(questionText: String) {
question_text.text = questionText
}
private fun setAuthor(author: Buff.Author) {
val firstName = author.firstName
val lastName = author.lastName
sender_name.text = "$firstName $lastName"
Glide.with(buffView)
.load(author.image)
.into(sender_image)
}
private fun setAnswer(answers: List<Buff.Answer>) {
val answersContainer = findViewById<LinearLayout>(R.id.answersContainer)
answersContainer.removeAllViews()
for(answer in answers) {
val answerView: View = LayoutInflater.from(answersContainer.context).inflate(
R.layout.buff_answer,
answersContainer,
false
)
answer.answerImage?.x0?.url?.let {
Glide.with(buffView)
.load(it)
.into(answerView.answer_image)
}
answerView.setOnClickListener {
answerView.background = ContextCompat.getDrawable(context, R.drawable.answer_selected_bg)
answerView.answer_text.setTextColor(ContextCompat.getColor(context, android.R.color.white))
//freeze timer
stopCountDownTimer()
//hideView() after 2 seconds
it.postDelayed(Runnable {
hideBuff()
}, HIDE_BUFF_AFTER_SELECTED_ANSWER_DURATION)
}
answerView.answer_text?.text = answer.title
answersContainer.addView(answerView)
}
}
...
}
You'll have to include your buff_view.xml as a child of a layout where you can set the layout_weight property like this.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="bottom">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<include layout="#layout/buff_view">
</LinearLayout>
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" />
</LinearLayout>
Also change the width and height constraints for the buff view top LinearLayout like this
<LinearLayout
android:id="#+id/mainLinearLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/buff_sender"/>
<include layout="#layout/buff_question"/>
<LinearLayout
android:id="#+id/answersContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
</LinearLayout>
EDIT: Progress bar not visible problem
I think it is a problem with the TextView question_text
Change it like this
<TextView
android:id="#+id/question_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical|start"
android:padding="18dp"
android:textColor="#color/test_color_light"
android:textStyle="bold" />
Also change the main Layout in buff_question.xml and set its layout_width to match_parent like this
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/dark_bg"
android:orientation="horizontal">
This is easily done using ConstraintLayout and width/height percentages.
Be sure to set the actual width dimensions to 0dp (where using a percentage value) and to make sure the views are constrained appropriately.
The below produces this output
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:background="#color/salmon1"
android:id="#+id/view1"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent=".33"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:background="#color/orange1"
android:id="#+id/view2"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/view1" />
</androidx.constraintlayout.widget.ConstraintLayout>
I'm trying to create a Two-Way Data binding connection with a LiveData object of a modal class. But when I tries to read the values of user it turns out to be null. Here is my code -
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val viewModal: MainActivityViewModal = ViewModelProvider(
this,
MainActivityViewModalFactory()
).get(MainActivityViewModal::class.java)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(
this,
R.layout.activity_main
).apply {
this.lifecycleOwner = this#MainActivity
this.viewModal = viewModal
}
}}
Here is the Layout file -
<data>
<variable
name="viewModal"
type="com.weaponx.databindingexample.MainActivityViewModal" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="#+id/ivLogo"
android:layout_width="100dp"
android:layout_height="100dp"
android:contentDescription="#string/logo"
android:tint="#000000"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#android:drawable/ic_menu_myplaces" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/clBody"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/ivLogo">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.10" />
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/tilUserName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#drawable/edit_text_bg"
android:hint="#string/user_name"
android:padding="5dp"
app:layout_constraintEnd_toStartOf="#id/guideline2"
app:layout_constraintStart_toEndOf="#id/guideline1"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/tietUserName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#null"
android:inputType="text"
android:text="#={viewModal.user.userName}" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/tilPassword"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:background="#drawable/edit_text_bg"
android:hint="#string/password"
android:padding="5dp"
app:layout_constraintEnd_toStartOf="#id/guideline2"
app:layout_constraintStart_toEndOf="#id/guideline1"
app:layout_constraintTop_toBottomOf="#id/tilUserName">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/tietPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#null"
android:inputType="textPassword"
android:text="#={viewModal.user.password}" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:background="#drawable/button_bg"
android:text="#string/login"
android:onClick="#{() -> viewModal.login()}"
android:textAllCaps="false"
android:textColor="#android:color/white"
android:textSize="18sp"
app:layout_constraintEnd_toStartOf="#id/guideline2"
app:layout_constraintStart_toEndOf="#id/guideline1"
app:layout_constraintTop_toBottomOf="#id/tilPassword" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.90" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Here is the ViewModal
class MainActivityViewModal : ViewModel() {
var user = MutableLiveData<User>()
fun login() {
println("Login Success ${user.value}")
}}
And here is the Modal Class
class User() {
var userName: String = ""
var password: String = ""
override fun toString(): String {
return "User(userName='$userName', password='$password')"
}}
Please tell me any solution or a good way around to this problem
In the MainActivityViewModal define user as just User type rather as MutableLiveData.