# How the JapaneseKeyboard Project Implements Keyboard View Architecture Using GridLayout and Custom View Controllers

> Explore the Japanese Keyboard project's view architecture. Learn how GridLayout and custom view controllers manage layouts, gestures, and themes for flick, ten-key, and tablet variants.

- Repository: [Kazu/japanesekeyboard](https://github.com/kazumaproject/japanesekeyboard)
- Tags: architecture
- Published: 2026-03-05

---

**The JapaneseKeyboard app employs a modular architecture where GridLayout containers position key views, specialized controller classes isolate gesture handling, and a dynamic theme engine applies consistent styling across flick, ten-key, and tablet keyboard variants.**

The kazumaproject/japanesekeyboard repository demonstrates a sophisticated Android input method that supports diverse keyboard families through a unified design pattern. This article examines the keyboard view architecture using GridLayout and custom view controllers that enables deterministic cell placement, reusable gesture logic, and runtime theme adaptation across Flick, Ten-key, and Tablet implementations.

## Architectural Layers of the Keyboard System

The implementation separates concerns into four distinct layers: layout containers, key views, behavior controllers, and the theme engine.

### Layout Containers and Grid Implementation

Three container strategies manage the spatial arrangement of keys depending on the keyboard variant.

**FlickKeyboardView** extends Android's native `GridLayout` to create a static, non-scrolling grid for the primary flick keyboard. In [`FlickKeyboardView.kt`](https://github.com/kazumaproject/japanesekeyboard/blob/main/FlickKeyboardView.kt), the `setKeyboard()` method receives a `KeyboardLayout` object and iterates over `layout.keys` to populate the grid deterministically.

**CustomSymbolKeyboardView** and the QWERTY/Number keyboards utilize a `RecyclerView` with `GridLayoutManager` for dynamic grid generation. This approach enables efficient view recycling when displaying large symbol sets without sacrificing the grid metaphor.

**TabletKeyboardView** wraps a `ConstraintLayout` that inflates [`keyboard_layout.xml`](https://github.com/kazumaproject/japanesekeyboard/blob/main/keyboard_layout.xml) (located in `tenkey/src/main/res/layout/`). This static XML approach supports complex positioning for large-screen devices while maintaining compatibility with the controller attachment system.

### Key View Implementation

Individual keys instantiate as either `AutoSizeButton` (extending `Button`) for text labels or `AppCompatImageButton` for icon-based keys. The `createKeyView()` function in `FlickKeyboardView` constructs these views based on `KeyData` properties, applying `rowSpec` and `columnSpec` parameters defined in `GridLayout.LayoutParams` to position each cell within the grid.

### Custom View Controllers for Gesture Handling

Gesture logic is isolated from UI code through specialized controller classes attached via `attachKeyBehavior()`. The architecture implements several controller types:

- **CustomAngleFlickController**: Manages circular flick pop-up gestures
- **CrossFlickInputController**: Handles cross-shaped four-directional flicks  
- **StandardFlickInputController**: Processes standard five-direction flicks for alphanumeric keys
- **GridFlickInputController**: Powers the petal-style flick interface used by the Symbol keyboard

Each controller receives the key view instance and configures touch listeners in `controller.attach()`, forwarding high-level events such as `onFlick`, `onKey`, and `onAction` to the registered `OnKeyboardActionListener` supplied by the host IME.

### Theme Engine and Dynamic Updates

The `applyKeyboardTheme()` method in base view classes manages visual styling across Neumorphism, Material-You, and custom color modes. Runtime state changes propagate through `dynamicKeyMap`, which stores references to keys requiring visual updates. When `updateDynamicKey()` triggers, the system rebuilds the specific key view and reattaches the appropriate controller while preserving its grid position.

## Keyboard Construction Workflow

The assembly process follows a strict initialization sequence when `setKeyboard()` executes.

1. **Grid Initialization**: The view calls `removeAllViews()` and configures `columnCount` and `rowCount` from the `KeyboardLayout` metadata.

2. **View Instantiation**: For each `KeyData` entry, `createKeyView()` determines whether to instantiate an `AutoSizeButton` or `AppCompatImageButton` based on `keyData.isSpecialKey` and `keyData.drawableResId`.

3. **Controller Attachment**: `attachKeyBehavior()` inspects `keyData.keyType` (values include `CIRCULAR_FLICK`, `STANDARD_FLICK`, `CROSS_FLICK`, `PETAL_FLICK`, or `NORMAL`) to instantiate the matching controller from `custom_keyboard/src/main/java/com/kazumaproject/custom_keyboard/controller/`. The controller configures flick range, color themes, and listener interfaces before attaching to the view.

4. **Event Propagation**: Touch events route through the controller's gesture recognition logic, which translates physical movements into semantic actions forwarded to the IME service via the `OnKeyboardActionListener` interface.

## Design Rationale

### Why GridLayout?

The architecture leverages GridLayout for the Flick keyboard because it provides deterministic cell placement matching the physical Japanese keyboard matrix. Unlike RecyclerView, GridLayout requires no adapter overhead, minimizing touch latency for gesture-intensive input. The direct ownership of `LayoutParams` by the grid simplifies background drawable application and margin adjustments during theme changes.

### Why Custom Controllers?

Isolating gesture logic into controller classes enables the same `StandardFlickInputController` to function across QWERTY, Ten-key, and Symbol keyboards without code duplication. This separation of concerns keeps view classes focused on layout and rendering while making gesture patterns testable and extensible. Adding a new flick pattern requires only a new controller subclass, leaving the grid container untouched.

## Implementation Examples

The following Kotlin examples demonstrate typical usage patterns:

```kotlin
// Initialize a flick keyboard in an IME service
val flickView = FlickKeyboardView(context)
flickView.setOnKeyboardActionListener(object : 
    FlickKeyboardView.OnKeyboardActionListener {
    
    override fun onKey(text: String, isFlick: Boolean) {
        inputConnection.commitText(text, 1)
    }
    
    override fun onAction(action: KeyAction, view: View, isFlick: Boolean) {
        // Handle space, delete, enter actions
    }
})

// Load layout and display
flickView.setKeyboard(myJapaneseLayout)

```

Applying custom themes through the architecture:

```kotlin
flickView.applyKeyboardTheme(
    themeMode = "custom",
    currentNightMode = resources.configuration.uiMode,
    isDynamicColorEnabled = false,
    customBgColor = Color.parseColor("#FAFAFA"),
    customKeyColor = Color.parseColor("#EEEEEE"),
    customSpecialKeyColor = Color.parseColor("#DDDDDD"),
    customKeyTextColor = Color.BLACK,
    customSpecialKeyTextColor = Color.DKGRAY,
    liquidGlassEnable = false,
    customBorderEnable = true,
    customBorderColor = Color.GRAY,
    liquidGlassKeyAlphaEnable = 230,
    borderWidth = 2
)

```

Ten-key implementation using RecyclerView with GridLayoutManager:

```kotlin
val tenKeyRecycler = RecyclerView(context).apply {
    layoutManager = GridLayoutManager(
        context, 
        3, 
        RecyclerView.HORIZONTAL, 
        false
    )
    adapter = TenKeyAdapter(myTenKeyLayout)
}

```

## Summary

- **GridLayout containers** in `FlickKeyboardView` provide zero-overhead view hierarchies for latency-sensitive flick gestures, while `RecyclerView` with `GridLayoutManager` handles larger datasets in the Symbol and Ten-key variants located in `symbol_keyboard/` and `tenkey/` modules.

- **Custom view controllers** encapsulate gesture recognition into reusable classes like `StandardFlickInputController` and `CustomAngleFlickController`, enabling consistent behavior across different keyboard modes without modifying view code.

- **Key views** instantiate as `AutoSizeButton` or `AppCompatImageButton` based on `KeyData` specifications, with layout parameters managed by the parent grid container via `rowSpec` and `columnSpec`.

- **Dynamic theming** applies through `applyKeyboardTheme()` and `updateDynamicKey()`, allowing runtime visual updates without reconstructing the entire view hierarchy.

- **Tablet optimization** uses `TabletKeyboardView` with a static XML grid defined in [`keyboard_layout.xml`](https://github.com/kazumaproject/japanesekeyboard/blob/main/keyboard_layout.xml), demonstrating how the controller system adapts to different layout containers while maintaining gesture consistency.

## Frequently Asked Questions

### What is the difference between FlickKeyboardView and CustomSymbolKeyboardView?

`FlickKeyboardView` extends `GridLayout` directly for static, non-scrolling keyboards optimized for flick gestures, while `CustomSymbolKeyboardView` uses a `RecyclerView` with `GridLayoutManager` to efficiently handle larger symbol sets that require view recycling. Both utilize the same controller classes for gesture handling but differ in their container implementations to suit their specific content needs and performance characteristics.

### How does the architecture handle different flick gesture patterns?

The system implements specialized controllers—`StandardFlickInputController` for five-direction flicks, `CrossFlickInputController` for cross-shaped inputs, and `GridFlickInputController` for petal-style arrangements—that attach to key views via `attachKeyBehavior()` in `FlickKeyboardView`. Each controller interprets touch events independently and forwards high-level actions to the `OnKeyboardActionListener`, allowing the grid container to remain agnostic of gesture specifics.

### Can the keyboard appearance change dynamically without rebuilding the entire layout?

Yes, the `dynamicKeyMap` in `FlickKeyboardView` maintains references to keys that require runtime updates. When `updateDynamicKey(keyId, stateIndex)` triggers, the system rebuilds only the affected key view and reattaches its controller, preserving the grid structure and maintaining the existing layout parameters defined during initial `setKeyboard()` execution.

### Where are the gesture controllers defined in the source code?

Controller classes reside in `custom_keyboard/src/main/java/com/kazumaproject/custom_keyboard/controller/`, including [`CustomAngleFlickController.kt`](https://github.com/kazumaproject/japanesekeyboard/blob/main/CustomAngleFlickController.kt), [`StandardFlickInputController.kt`](https://github.com/kazumaproject/japanesekeyboard/blob/main/StandardFlickInputController.kt), and [`CrossFlickInputController.kt`](https://github.com/kazumaproject/japanesekeyboard/blob/main/CrossFlickInputController.kt). These classes implement the touch recognition logic that attaches to views created in [`FlickKeyboardView.kt`](https://github.com/kazumaproject/japanesekeyboard/blob/main/FlickKeyboardView.kt) through the `attachKeyBehavior()` method, ensuring separation between visual layout and input behavior.