Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Core Android UI Widgets and Layout Architectures

Tech May 7 4

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.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.