hikage-core
This is the core dependency of Hikage, and you need to introduce this module to use the basic features of Hikage.
Configure Dependency
You can add this module to your project using the following method.
SweetDependency (Recommended)
Add dependency in your project's SweetDependency
configuration file.
libraries:
com.highcapable.hikage:
hikage-core:
version: +
Configure dependency in your project build.gradle.kts
.
implementation(com.highcapable.hikage.hikage.core)
Traditional Method
Configure dependency in your project build.gradle.kts
.
implementation("com.highcapable.hikage:hikage-core:<version>")
Please change <version>
to the version displayed at the top of this document.
Function Introduction
You can view the KDoc click here.
Basic Usage
Use the code below to create your first Hikage layout.
First, use Hikageable
to create a Hikage.Delegate
object.
The following example
val myLayout = Hikageable {
LinearLayout {
TextView {
text = "Hello, World!"
}
}
}
Then, set it to the parent or root layout you want to display.
The following example
// Assume that's your Activity.
val activity: Activity
// Instantiate the Hikage object.
val hikage = myLayout.create(activity)
// Get the root layout.
val root = hikage.root
// Content view set to Activity.
activity.setContentView(root)
In this way, we complete a simple layout creation and setting.
Layout Agreement
The basic layout elements of Hikage are based on the Android native View
component.
All layout elements can be created directly using the Android native View
component.
The creation process of all layouts will be limited to the specified scope Hikage.Performer
, which is called the "player" of the layout, that is, the role object that plays the layout.
This object can be created and maintained in the following ways.
Hikageable
As shown in Basic Usage, Hikageable
can directly create a Hikage.Delegate
or Hikage
object.
In DSL, you can get the Hikage.Performer
object to create the layout content.
The first solution is created anywhere.
The following example
// myLayout is a Hikage.Delegate object.
val myLayout = Hikageable {
// ...
}
// Assume that's your Context.
val context: Context
// Instantiate the Hikage object where the Context is needed.
val hikage = myLayout.create(context)
The second solution is created directly where Context
exists.
The following example
// Assume that's your Context.
val context: Context
// Create a layout, myLayout is a Hikage object.
val myLayout = Hikageable(context) {
// ...
}
HikageBuilder
In addition to the above methods, you can also maintain a HikageBuilder
object to pre-create the layout.
First, we need to create a HikageBuilder
object and define it as a singleton.
The following example
object MyLayout : HikageBuilder {
override fun build() = Hikageable {
// ...
}
}
Then, use it where needed, there are two options as follows.
The first solution is to create a Hikage.Delegate
object directly using build
.
The following example
// myLayout is a Hikage.Delegate object.
val myLayout = MyLayout.build()
// Assume that's your Context.
val context: Context
// Instantiate the Hikage object where the Context is needed.
val hikage = myLayout.create(context)
The second solution is to create the Hikage
delegate object using Context.lazyHikage
.
For example, we can use it like ViewBinding
in Activity
.
The following example
class MyActivity: AppCompatActivity() {
private val myLayout by lazyHikage(MyLayout)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Get the root layout.
val root = myLayout.root
// Content view set to Activity.
setContentView(root)
}
}
Basic Layout Components
Hikage uses a functional component creation scheme consistent with Jetpack Compose.
Its layout is done using two basic components, the View
and ViewGroup
functions. They correspond to Android native components based on View
and ViewGroup
, respectively.
View
The basic parameters of the View
function are the following three, and the View
object type created using generic definitions.
If the generic type is not declared, the default is to use android.view.View
as the object type created.
Parameter Name | Description |
---|---|
lparams | Layout parameter, i.e. ViewGroup.LayoutParams , created using LayoutParams |
id | Used to find the ID of the created object, defined using a string |
init | The initialization method body of View , passed as the last DSL parameter |
The following example
View<TextView>(
lparams = LayoutParams(),
id = "my_text_view"
) {
text = "Hello, World!"
textSize = 16f
gravity = Gravity.CENTER
}
ViewGroup
The basic parameters of the ViewGroup
function are four, and compared with the View
function, there is one more performer
parameter.
It must declare a generic type because ViewGroup
is an abstract class and requires a concrete implementation class.
ViewGroup
provides an additional generic parameter based on ViewGroup.LayoutParams
to provide layout parameters for sub-layouts.
ViewGroup.LayoutParams
is used by default when not declared.
Parameter Name | Description |
---|---|
lparams | Layout parameter, i.e. ViewGroup.LayoutParams , created using LayoutParams |
id | Used to find the ID of the created object, defined using a string |
init | The initialization method body of ViewGroup , passed in as DSL parameter |
performer | Hikage.Performer object, passed as the last DSL parameter |
The function of the performer
parameter is to pass a new Hikage.Performer
object downward as the creator of the sub-layout.
The following example
ViewGroup<LinearLayout, LinearLayout.LayoutParams>(
lparams = LayoutParams(),
id = "my_linear_layout",
// Initialization method body will be reflected here using `init`.
init = {
orientation = LinearLayout.VERTICAL
gravity = Gravity.CENTER
}
) {
// You can continue to create sub-layouts here.
View()
}
LayoutParams
Layouts in Hikage can be set using the LayoutParams
function, you can create it using the following parameters.
Parameter Name | Description |
---|---|
width | Manually specify layout width |
height | Manually specify layout height |
matchParent | Whether to use MATCH_PARENT as layout width and height |
wrapContent | Whether to use WRAP_CONTENT as layout width and height |
widthMatchParent | Set width to MATCH_PARENT only |
heightMatchParent | Set the height to MATCH_PARENT only |
body | The initialization method body of the layout parameter, passed into as the last DSL parameter |
When you do not set the LayoutParams
object or specify width
and height
, Hikage will automatically use WRAP_CONTENT
as layout parameters.
The type of the body
method body comes from the second generic parameter provided by the upper layer ViewGroup.
The following example
View(
// Assume that the layout parameter type provided by the upper layer is LinearLayout.LayoutParams.
lparams = LayoutParams(width = 100.dp) {
topMargin = 20.dp
}
)
If you only need a horizontally filled layout, you can use widthMatchParent = true
directly.
The following example
View(
lparams = LayoutParams(widthMatchParent = true)
)
Layout
Hikage supports references to third-party layouts, you can pass in XML layout resource IDs, other Hikage objects, and View
objects, and even ViewBinding
.
The following example
ViewGroup<...> {
// Quote XML layout resource ID.
Layout(R.layout.my_layout)
// Quote ViewBinding.
Layout<MyLayoutBinding>()
// Reference another Hikage or Hikage.Delegate object.
Layout(myLayout)
}
Positioning Layout Components
Hikage supports locating components using id
. In the example above, we used the id
parameter to set the component's ID.
After setting the ID, you can use the Hikage.get
method to get them.
The following example
val myLayout = Hikageable {
View<TextView>(id = "my_text_view") {
text = "Hello, World!"
}
}
// Assume that's your Context.
val context: Context
// Instantiate the Hikage object where the Context is needed.
val hikage = myLayout.create(context)
// Get the specified component and return the View type.
val textView = hikage["my_text_view"]
// Get the specified component and declare the component type.
val textView = hikage.get<TextView>("my_text_view")
// If you are not sure whether the ID exists, you can use the `getOrNull` method.
val textView = hikage.getOrNull<TextView>("my_text_view")
Custom Layout Components
Hikage provides functions corresponding to component class names for Android basic layout components.
You can directly use these functions to create components without using generics to declare them. If you need components provided by Jetpack or Material, the hikage-widget-androidx or hikage-widget-material modules can be introduced.
The following example
LinearLayout(
lparams = LayoutParams(),
id = "my_linear_layout",
init = {
orientation = LinearLayout.VERTICAL
gravity = Gravity.CENTER
}
) {
TextView(
lparams = LayoutParams(),
id = "my_text_view"
) {
text = "Hello, World!"
textSize = 16f
gravity = Gravity.CENTER
}
}
The initialized View
or ViewGroup
objects return instances of their own object type, which you can use in the following layout.
The following example
val textView = TextView {
text = "Hello, World!"
textSize = 16f
gravity = Gravity.CENTER
}
Button {
text = "Click Me!"
setOnClickListener {
// Use the textView object directly.
textView.text = "Clicked!"
}
}
If the provided components do not meet your needs, you can create your own components manually.
The following example
// Suppose you have defined your custom components.
class MyCustomView(context: Context, attrs: AttributeSet? = null) : View(context, attrs) {
// ...
}
// Below, create the function corresponding to the component.
// Custom components must declare this annotation.
// Declaring the annotation of the component is contagious,
// and this annotation is required in every scope used to build the layout.
@Hikageable
// The naming of functions can be done at will, but it is recommended to use a big camel name.
// The signature part of the function needs to be fixedly
// declared as `inline fun <reified LP : ViewGroup.LayoutParams> Hikage.Performer<LP>`.
inline fun <reified LP : ViewGroup.LayoutParams> Hikage.Performer<LP>.MyCustomView(
lparams: Hikage.LayoutParams? = null,
id: String? = null,
init: HikageView<MyCustomView> = {},
// If this component is a container, you can declare a `performer` parameter.
// performer: HikagePerformer<LP> = {}
) = View<MyCustomView>(lparams, id, init)
It would seem tedious to implement such complex functions manually every time. If you want to be able to automatically generate component functions, you can introduce and refer to the hikage-compiler module.
Combination and Disassembly Layout
When building a UI, we usually use reusable layouts as components.
If you don't want each part to be customized separately using a native custom View
, you can split the layout logic parts directly.
Hikage supports splitting layouts into multiple parts and combining them, you can use the Hikageable
function anywhere to create a new Hikage.Delegate
object.
The following example
// Assume this is your main layout.
val mainLayout = Hikageable {
LinearLayout(
lparams = LayoutParams(matchParent = true),
init = {
orientation = LinearLayout.VERTICAL
}
) {
TextView {
text = "Hello, World!"
}
// Combination sublayout.
Layout(subLayout)
}
}
// Assume this is your layout submodule.
// Since the upper layout uses LinearLayout,
// you can declare LinearLayout.LayoutParams for the sublayout.
val subLayout = Hikageable<LinearLayout.LayoutParams> {
TextView(
lparams = LayoutParams {
topMargin = 16.dp
}
) {
text = "Hello, Sub World!"
}
}
Custom Layout Factory
Hikage supports custom layout factories and is compatible with LayoutInflater.Factory2
. You can customize events and listening during the Hikage layout inflating process in the following ways.
The following example
val factory = HikageFactory { parent, base, context, params ->
// You can customize the behavior of the layout factory here.
// For example, create a new View object in your own way.
// `parent` is the ViewGroup object to which the current component is to be added,
// and if not, it is `null`.
// `base` is the View object created for the previous HikageFactory, if not, it is `null`.
// `params` object contains the component ID, AttributeSet and Class objects of View.
val view = MyLayoutFactory.createView(context, params)
// You can also initialize and set the created View object here.
view.setBackgroundColor(Color.RED)
// Return the created View object.
// Return `null` will use the default component inflating method.
view
}
You can also pass in the LayoutInflater
object directly to automatically inflate and use the LayoutInflater.Factory2
in it.
The following example
// Assume that this is your LayoutInflater object.
val layoutInflater: LayoutInflater
// Create HikageFactory object through LayoutInflater.
val factory = HikageFactory(layoutInflater)
Then set it to the Hikage layout you need to inflate.
The following example
// Assume that's your Context.
val context: Context
// Create Hikage object.
val hikage = Hikageable(
context = context,
factory = {
// Add a custom HikageFactory object.
add(factory)
// Add directly.
add { parent, base, context, params ->
// ...
null
}
// Add multiple consecutively.
addAll(factories)
}
) {
LinearLayout {
TextView {
text = "Hello, World!"
}
}
}
Tips
Hikage will inflate the layout according to the LayoutInflater.Factory2
of the Context
object, if you are using AppCompatActivity
, Components in the layout will be automatically replaced with the corresponding Compat component or Material component, which is consistent with the characteristics of the XML layout.
If you do not need this feature to be effective by default, you can turn it off globally using the following method.
The following example
Hikage.isAutoProcessWithFactory2 = false
Preview Layout
Hikage supports previewing layouts in Android Studio.
With the help of the custom View
preview plugin that comes with Android Studio, you can preview the layout using the following methods.
You just need to define a custom View
for the preview layout and inherit from HikagePreview
.
The following example
class MyLayoutPreview(context: Context, attrs: AttributeSet?) : HikagePreview(context, attrs) {
override fun build() = Hikageable {
LinearLayout {
TextView {
text = "Hello, World!"
}
}
}
}
Then the preview pane should appear on the right side of your current window. After opening, click "Build & Refresh". The preview will be automatically displayed after the compilation is completed.
Tips
HikagePreview
implements the HikageBuilder
interface, you can return any Hikage layout in the build
method for preview.
Pay Attention
HikagePreview
supports previewing layouts in Android Studio only, do not use it at runtime or add it to any XML layout.