Core Android UI Widgets and Layout Architectures
Fundamental Android Layout Systems
Effective user interface design in Android relies heavily on managing how views are positioned. The two primary layout containers discussed here are Linear and Relative.
Managing View Arrangement
Linear Container
This container arranges child elements sequentially, either horizontally or vertically. Key configuration properties include:
| Property | Description |
|---|---|
android:id |
Unique identifier |
android:layout_width |
Horizontal dimension specification |
android:layout_height |
Vertical dimension specification |
android:orientation |
Axis direction (horizontal/vertical) |
android:gravity |
Alignment of content within the container |
android:weight |
Distributes space among children |
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<!-- Vertical Container -->
<LinearLayout
android:id="@+id/container_vertical"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#333333"
android:paddingStart="20dp"
android:paddingTop="50dp">
<View
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FF4444" />
</LinearLayout>
<!-- Horizontal Distribution -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#0044AA"
android:orientation="horizontal"
android:layout_marginTop="15dp">
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#000000" />
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:background="#FF6633" />
</LinearLayout>
</LinearLayout>
Relative Positioning
Unlike linear layouts, this system positions children relative to their parent or other siblings. Its useful for complex alignments.
Key attributes include:
android:layout_toEndOf: Positioned to the end of a target ID.android:layout_below: Positioned below a target ID.android:alignParentBottom: Anchors the view to the bottom edge.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Root Element 1 -->
<View
android:id="@+id/root_view_1"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#001122" />
<!-- Root Element 2 (Below Element 1) -->
<View
android:id="@+id/root_view_2"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_below="@id/root_view_1"
android:layout_alignStart="@id/root_view_1"
android:background="#DD2244" />
<!-- Nested Group -->
<LinearLayout
android:id="@+id/group_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/root_view_2"
android:orientation="horizontal"
android:padding="16dp"
android:background="#0088CC">
<View
android:layout_width="100dp"
android:layout_height="match_parent"
android:background="#990000"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#222222"
android:padding="8dp">
<View
android:id="@+id/sub_view_a"
android:layout_width="100dp"
android:layout_height="match_parent"
android:background="#CC9933" />
<View
android:id="@+id/sub_view_b"
android:layout_width="100dp"
android:layout_height="match_parent"
android:layout_toEndOf="@id/sub_view_a"
android:layout_marginStart="8dp"
android:background="#EEAA66" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
Text Display Controls
The TextView component allows customization of appearance, including size, color, and decorations like strikethroughs or underlines.
Implementing Text Effects
You can manipulate text painting flags programmatically to apply visual effects such as removal of anti-aliasing or adding line-through styles.
package com.example.uicore;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Paint;
import android.os.Bundle;
import android.text.Html;
import android.widget.TextView;
public class TextDisplayActivity extends AppCompatActivity {
private TextView strkLabel;
private TextView underlineLabel;
private TextView htmlLabel;
private TextView scrollLabel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text_display);
// Apply strikethrough
strkLabel = findViewById(R.id.label_strike);
int flags = strkLabel.getPaint().getFlags() | Paint.STRIKE_THRU_TEXT_FLAG;
strkLabel.getPaint().setFlags(flags);
strkLabel.setAntiAlias(true);
// Apply underline
underlineLabel = findViewById(R.id.label_underline);
flags = underlineLabel.getPaint().getFlags() | Paint.UNDERLINE_TEXT_FLAG;
underlineLabel.getPaint().setFlags(flags);
// HTML Content
htmlLabel = findViewById(R.id.label_html);
htmlLabel.setText(Html.fromHtml("<u>Rich text example</u>"));
// Marquee effect requires focus
scrollLabel = findViewById(R.id.label_scroll);
scrollLabel.setSelected(true);
}
}
Layout Example:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/text_basic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Basic Text"
android:textSize="24sp"
android:textColor="#000000" />
<TextView
android:id="@+id/text_trimmed"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:text="LongTextThatGetsTruncated"
android:textColor="#FFFFFF"
android:background="#333333"
android:layout_marginTop="10dp"/>
<TextView
android:id="@+id/text_icon_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Option A"
android:textColor="#000000"
android:textSize="20sp"
android:drawableStart="@drawable/ic_arrow_down"
android:drawablePadding="8dp" />
<TextView
android:id="@+id/label_scroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:focusable="true"
android:focusableInTouchMode="true"
android:text="Scrolling text demonstration..." />
</LinearLayout>
Interactive Elements
Buttons serve as the primary action triggers. Customization often involves background shapes and click listeners.
Button Configuration
To create dynamic backgrounds, use shape drawables defined in XML resources. Click handling can be performed via anonymous listeners or methods referenced directly in the XML.
public class ActionLauncher extends AppCompatActivity {
private final Button textActionBtn;
private final Button styledActionBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_action);
textActionBtn = findViewById(R.id.btn_launch_text);
styledActionBtn = findViewById(R.id.btn_styled_action);
textActionBtn.setOnClickListener(v -> {
navigateToNextScreen();
});
styledActionBtn.setOnClickListener(v -> { // Java Lambda equivalent if API permits
showToast("Styled button pressed");
});
}
public void handleMethodClick(View v) {
showToast("XML Method Invocation");
}
private void navigateToNextScreen() {
// Intent logic
}
private void showToast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}
Example Layout:
<Button
android:id="@+id/btn_method_trigger"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Call Method"
android:onClick="handleMethodClick"
android:textColor="#FFF"
android:background="@drawable/bg_rounded" />
Input Widgets
Input handling includes Checkboxes and Radio buttons for selection logic.
CheckBox Management
Use CompoundButton.OnCheckedChangeListener to track state changes dynamically.
public class SelectionActivity extends AppCompatActivity {
private CheckBox optCheck1;
private CheckBox optCheck2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_selection);
optCheck1 = findViewById(R.id.cb_android_dev);
optCheck2 = findViewById(R.id.cb_food_prep);
optCheck1.setOnCheckedChangeListener((buttonView, isChecked) -> {
Log.d("Selection", "Android dev checked: " + isChecked);
});
optCheck2.setOnCheckedChangeListener((buttonView, isChecked) -> {
Log.d("Selection", "Food prep checked: " + isChecked);
});
}
}
Example Selection XML:
<CheckBox
android:id="@+id/cb_custom_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Custom Option"
android:button="@drawable/custom_icon"
android:paddingStart="16dp" />
Image Handling
The ImageView displays bitmaps and vectors. Scaling behavior is controlled by scaleType.
Scaling Strategies
- fitXY: Stretches image to fill bounds (aspect ratio ignored).
- fitCenter: Centers image and scales to fit inside bounds (aspect ratio kept).
- centerCrop: Scales so image covers bounds completely (clipping allowed).
<ImageView
android:id="@+id/img_profile"
android:layout_width="100dp"
android:layout_height="100dp"
android:scaleType="centerCrop"
app:srcCompat="@drawable/ic_user" />
For network images, libraries like Glide simplify loading pipelines with caching capabilities.
Data Lists
List are essential for displaying collections of data.
ListView Implementation
While functional, modern apps prefer RecyclerView. However, understanding Adapter and ViewHolder patterns remains critical.
public class ListAdapter extends BaseAdapter {
private Context context;
public ListAdapter(Context ctx) {
this.context = ctx;
}
@Override
public int getCount() {
return 50; // Simulated data count
}
@Override
public Object getItem(int position) {
return null;
}
static class ItemBinder {
ImageView iconView;
TextView titleView;
TextView descView;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ItemBinder binder;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.list_row, parent, false);
binder = new ItemBinder();
binder.iconView = convertView.findViewById(R.id.row_img);
binder.titleView = convertView.findViewById(R.id.row_title);
binder.descView = convertView.findViewById(R.id.row_desc);
convertView.setTag(binder);
} else {
binder = (ItemBinder) convertView.getTag();
}
binder.titleView.setText("Title Item " + position);
binder.descView.setText("Description content...");
return convertView;
}
}
RecyclerView Overview
RecyclerView decouples view creation from data binding more efficiently than ListView. It supports multiple layouts including Grid, Linear, and Staggered grids.
Grid and Staggered Support
Implementing GridLayoutManager allows column definition. For masonry-style layouts, use StaggeredGridLayoutManager where item heights vary. Recycler Views allow custom Header/Footer views through extension classes like XRecyclerView.
Scrolling Containers
When vertical height exceeds screen bounds, wrap content in ScrollView. For horizontal overflow, use HorizontalScrollView.
Note: Only one direct child is permitted inside these containers. All inner views must be nested within that single child (often a LinearLayout).
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button android:text="Option A" />
<Button android:text="Option B" />
<Button android:text="Option C" />
</LinearLayout>
</ScrollView>
Web Integration
The WebView component renders HTML content, whether fetched from the web, loaded from local assets, or injected dynamically.
Navigation and Interaction
Standard navigation methods allow forward/back tracking. JavaScript bridges enable native code execution triggered by web events.
Loading Sources:
- Remote URL:
view.loadUrl("https://example.com") - Local Asset:
view.loadUrl("file:///android_asset/page.html") - Raw String:
view.loadDataWithBaseURL(null, htmlContent, "text/html", "utf-8", null)
History Management:
canGoBack()/goBack()canGoForward()/goForward()
Override onBackPressed to ensure back navigation happens within the WebView context rather than exiting the Activity immediately.