Add mavenCentral() (or jcenter()) to repository in your project's build.gradle:
allprojects {
repositories {
...
mavenCentral() // or jcenter()
}
}
Add form to dependencies in your app's build.gradle:
dependencies {
...
implementation 'com.feiyilin:form:0.3.5'
}
class MainActivity : FormActivity() {
...
override fun initForm() {
adapter?.apply {
+FormItemSection().title("Text").tag("sec_text").apply {
enableCollapse(true)
+FormItemText().title("Text").tag("text").required(true)
+FormItemText().title("Text").subTitle("here is subtitle").tag("text_subtitle")
+FormItemText().title("Text").subTitle("draggable").draggable(true)
.tag("text_draggable")
...
}
}
}
...
}
class MainActivity : FormActivity() {
...
override var onFormItemListener: FormItemCallback? = object : FormItemCallback {
override fun onValueChanged(item: FormItem) {
...
}
}
...
}
Or check FormActivity if you want to use FormRecyclerAdapter directly in the activity.
Ver 0.3 supports section. It is a breaking change. Check branch 0.2.x if prefer the old way.
Callback can be used to change the appearance and behavior of an item. It can be set
+FormItemNav().title("Nav item").tag("nav_item")
.onItemClicked {item, viewHolder ->
Toast.makeText(this@MainActivity, "Click on ${item.title}", Toast.LENGTH_SHORT).show()
}
Supported callbacks
onSetup
Called when the item is configured.
onValueChanged
Called when the value of an item changes.
onItemClicked
Called when an item is clicked.
onTitleImageClicked
Called when the title icon is clicked
onStartReorder
Called before moving/reordering an item. Return true from the callback to disable the default action.
onMoveItem
Called before finishing moving an item. Return true from the callback to disable the default action.
onSwipedAction
Called when a swipe action is triggered.
onEditorAction
"called when the enter key is pressed , or when an action supplied to the IME is selected by the user" (text item)
getMinItemHeight (FormItemCallback only)
Called when configure/bind an item. Can be used to update the minimum height for all (or a group of) items.
Use + operator to add an item or a section to adapter
adapter?.apply {
// add a section
+FormItemSection().apply {
// add item to section
+FormItemNav().title("Item 0")
}
}
Or call add
val sec = FormItemSection().title("New section").apply {
+FormItemNav().title("Item 0")
+FormItemNav().title("item 1")
}
sec.add(FormItemNav().title("Item 2"))
adapter?.add(sec)
And to remove an item or a section from adatper
// remove a section
adapter?.remove(sec)
// remove an item
adapter?.remove(item)
// or
sec.remove(item)
Tag can be used to access an item or section
val item = adapter.itemBy("item_tag") // or null if not found
val section = adapter.sectionBy("section_tag")
To collapse/expand a section (show/hide its children),
section.enableCollapse(true)
override fun onItemClicked(item: FormItem, viewHolder: RecyclerView.ViewHolder) {
if (item is FormItemSection) {
if (item.enableCollapse) {
adapter?.collapse(item, !item.collapsed)
}
}
...
}
Call adapter.hide to dynamically show/hide item/section. If it is a section, it will hide the section item and all its visible children.
For example
// hide an item
adapter.itemBy("action")?.let {
adapter.hide(it, true)
}
// hide a section
adapter.sectionBy("sec_date")?.let {
adapter.hide(it, true)
}
FormItemRadios will be considered to be in the same group (i.e., selecting one will de-select others), if
+FormItemSection().title("Radio").apply {
+FormItemRadio().group("radio0").title("item 0")
.tag("radio0_item0").isOn(true)
+FormItemRadio().group("radio0").title("item 1")
.tag("radio0_item1")
...
}
For each item, we can define the leading/left or trailing/right swipe actions (following the idea here). For example
FormItemNav().title("Swipe left with multiple actions").trailingSwipe(listOf(
FormSwipeAction().title("Delete")
.backgroundColor(ContextCompat.getColor(this, android.R.color.holo_red_light)),
FormSwipeAction().title("Archive")
.backgroundColor(ContextCompat.getColor(this, android.R.color.holo_blue_light)),
FormSwipeAction().title("Mark as unread")
.backgroundColor(ContextCompat.getColor(this, android.R.color.holo_green_light))
)),
Once an action is triggered, onSwipedAction callback will be called
override fun onSwipedAction(
item: FormItem,
action: FormSwipeAction,
viewHolder: RecyclerView.ViewHolder
) {
super.onSwipedAction(item, action, viewHolder)
Toast.makeText(this@MainActivity, "${item.title}: ${action.title}", Toast.LENGTH_SHORT).show()
}
Text | |
Text area | |
Label | |
Number | |
Switch | |
Radio | |
SeekBar | |
Stepper | |
Nav | |
Action | |
Date | |
Select | |
Picker inline | |
Color |
<?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="wrap_content" android:orientation="vertical">
<androidx.cardview.widget.CardView
android:id="@+id/profile_image_wrap"
app:cardCornerRadius="63dp"
android:layout_width="126dp"
android:layout_height="126dp"
android:layout_marginTop="9dp"
android:layout_marginBottom="9dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_gravity="center_horizontal"
app:cardBackgroundColor="#00FFFFFF">
<ImageView
android:id="@+id/formELementImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
app:srcCompat="@drawable/form_image_placeholder"
android:scaleType="fitCenter"/>
</androidx.cardview.widget.CardView>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@+id/profile_image_wrap"
android:background="#FFE0E0E0"/>
</androidx.constraintlayout.widget.ConstraintLayout>
2. Derive an item from **FormItem**,
```kotlin
open class FormItemImage : FormItem() {
var image: Int = 0
}
fun <T : FormItemImage> T.image(image: Int) = apply {
this.image = image
}
Derive a view holder class from FormViewHolder, and override bind
class FormImageViewHolder(inflater: LayoutInflater, resource: Int, parent: ViewGroup) :
FormViewHolder(inflater, resource, parent) {
private var imgView: ImageView? = null
init {
imgView = itemView.findViewById(R.id.formELementImage)
}
override fun bind(s: FormItem, listener: FormItemCallback?) {
if (s is FormItemImage) {
Picasso.get().load(s.image).fit().centerInside().into(imgView)
imgView?.setOnClickListener {
listener?.onValueChanged(s)
}
}
}
}
Register the item with registerViewHolder
class MainActivity : FormActivity() {
...
override fun initForm() {
...
adapter?.registerViewHolder(
FormItemImage::class.java,
R.layout.form_item_image,
FormImageViewHolder::class.java
)
...
}
}