hackware1993/MagicIndicator
A powerful, customizable and extensible ViewPager indicator framework. As the best alternative of ViewPagerIndicator, TabLayout and PagerSlidingTabStrip —— 强大、可定制、易扩展的 ViewPager 指示器框架。是ViewPagerIndicator、TabLayout、PagerSlidingTabStrip的最佳替代品。支持角标,更支持在非ViewPager场景下使用(使用hide()、show()切换Fragment或使用setVisibility切换FrameLayout里的View等),http://www.jianshu.com/p/f3022211821c
Looks unmaintained — solo project with stale commits
weakest axisno license — legally unclear; last commit was 1y ago…
no license — can't legally use code; no CI workflows detected
Documented and popular — useful reference codebase to read through.
no license — can't legally use code; last commit was 1y ago…
- ✓Tests present
- ⚠Stale — last commit 1y ago
- ⚠Solo or near-solo (1 contributor active in recent commits)
Show all 5 evidence items →Show less
- ⚠No license — legally unclear to depend on
- ⚠No CI workflows detected
What would change the summary?
- →Use as dependency Concerns → Mixed if: publish a permissive license (MIT, Apache-2.0, etc.)
- →Fork & modify Concerns → Mixed if: add a LICENSE file
- →Deploy as-is Concerns → Mixed if: add a LICENSE file
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Great to learn from" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/hackware1993/magicindicator)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/hackware1993/magicindicator on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: hackware1993/MagicIndicator
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/hackware1993/MagicIndicator shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
AVOID — Looks unmaintained — solo project with stale commits
- Tests present
- ⚠ Stale — last commit 1y ago
- ⚠ Solo or near-solo (1 contributor active in recent commits)
- ⚠ No license — legally unclear to depend on
- ⚠ No CI workflows detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live hackware1993/MagicIndicator
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/hackware1993/MagicIndicator.
What it runs against: a local clone of hackware1993/MagicIndicator — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in hackware1993/MagicIndicator | Confirms the artifact applies here, not a fork |
| 2 | Default branch main exists | Catches branch renames |
| 3 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 4 | Last commit ≤ 547 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of hackware1993/MagicIndicator. If you don't
# have one yet, run these first:
#
# git clone https://github.com/hackware1993/MagicIndicator.git
# cd MagicIndicator
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of hackware1993/MagicIndicator and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "hackware1993/MagicIndicator(\\.git)?\\b" \\
&& ok "origin remote is hackware1993/MagicIndicator" \\
|| miss "origin remote is not hackware1993/MagicIndicator (artifact may be from a fork)"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "magicindicator/src/main/java/net/lucode/hackware/magicindicator/MagicIndicator.java" \\
&& ok "magicindicator/src/main/java/net/lucode/hackware/magicindicator/MagicIndicator.java" \\
|| miss "missing critical file: magicindicator/src/main/java/net/lucode/hackware/magicindicator/MagicIndicator.java"
test -f "magicindicator/src/main/java/net/lucode/hackware/magicindicator/abs/IPagerNavigator.java" \\
&& ok "magicindicator/src/main/java/net/lucode/hackware/magicindicator/abs/IPagerNavigator.java" \\
|| miss "missing critical file: magicindicator/src/main/java/net/lucode/hackware/magicindicator/abs/IPagerNavigator.java"
test -f "magicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/CommonNavigator.java" \\
&& ok "magicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/CommonNavigator.java" \\
|| miss "missing critical file: magicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/CommonNavigator.java"
test -f "magicindicator/src/main/java/net/lucode/hackware/magicindicator/ViewPagerHelper.java" \\
&& ok "magicindicator/src/main/java/net/lucode/hackware/magicindicator/ViewPagerHelper.java" \\
|| miss "missing critical file: magicindicator/src/main/java/net/lucode/hackware/magicindicator/ViewPagerHelper.java"
test -f "magicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/abs/CommonNavigatorAdapter.java" \\
&& ok "magicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/abs/CommonNavigatorAdapter.java" \\
|| miss "missing critical file: magicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/abs/CommonNavigatorAdapter.java"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 547 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~517d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/hackware1993/MagicIndicator"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
MagicIndicator is a customizable Android ViewPager indicator framework that replaces ViewPagerIndicator, TabLayout, and PagerSlidingTabStrip. It provides a highly extensible system for rendering page tabs, badges, and indicators with support for complex animations and non-ViewPager scenarios (Fragment hide/show, FrameLayout visibility toggling). Single Android library module structure: magicindicator/ contains core components (MagicIndicator view, CommonNavigator, adapter interfaces), while app/ is a feature-rich demo project with examples in app/src/main/java/net/lucode/hackware/magicindicatordemo/example/ showing FixedTab, ScrollableTab, DynamicTab, BadgeTab, and Fragment-based scenarios. Custom implementations (ColorFlipPagerTitleView, ScaleCircleNavigator) demonstrate the extension pattern.
👥Who it's for
Android developers building tabbed interfaces who need fine-grained control over indicator appearance, animations, and behavior beyond what Material Design's TabLayout offers. Specifically useful for apps requiring custom badge styles, dynamic tab management, or indicator-only displays without tabs.
🌱Maturity & risk
Production-ready. The project is well-documented with comprehensive examples in app/src/main/java/net/lucode/hackware/magicindicatordemo/example/, released on jitpack.io with versioning (1.6.0 for support lib, 1.7.0 for androidx), and actively maintained with androidx support. However, the last commit timestamp is not visible in the provided data.
Low risk for active projects. Single-maintainer repo (hackware1993) with no visible CI/CD pipeline in the provided files, but the codebase is pure Java with minimal external dependencies (only androidx/support-lib). Risk increases if upstream AndroidX updates introduce breaking changes without prompt response.
Active areas of work
No recent activity metadata is provided in the file list, but the repo structure indicates stable maintenance with androidx support (version 1.7.0) and comprehensive example coverage across BadgeTabExampleActivity, FragmentContainerExampleActivity, DynamicTabExampleActivity, and LoadCustomLayoutExampleActivity, suggesting ongoing polish rather than major feature development.
🚀Get running
Clone and import the Android module:
git clone https://github.com/hackware1993/MagicIndicator.git
cd MagicIndicator
./gradlew app:assembleDebug
Then open in Android Studio (build.gradle specifies compileSdkVersion 28, minSdkVersion 14) and run the app module on an emulator or device.
Daily commands: Android Studio: File → Open, select cloned directory. Build → Make Project. Then Run → Run 'app' targeting an emulator or connected device. Or via gradle:
./gradlew app:installDebug
./gradlew app:connectedAndroidTest # if tests exist
🗺️Map of the codebase
magicindicator/src/main/java/net/lucode/hackware/magicindicator/MagicIndicator.java— Core container View that manages all indicator behavior, lifecycle, and integration with adapters—entry point for all usage patternsmagicindicator/src/main/java/net/lucode/hackware/magicindicator/abs/IPagerNavigator.java— Primary abstraction defining the contract all navigator implementations must follow; foundational interface for extensibilitymagicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/CommonNavigator.java— Most versatile built-in navigator combining title views and indicators; handles composition and positioning logicmagicindicator/src/main/java/net/lucode/hackware/magicindicator/ViewPagerHelper.java— Adapter between Android's ViewPager and MagicIndicator; handles scroll state synchronization and page change eventsmagicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/abs/CommonNavigatorAdapter.java— Required adapter for CommonNavigator defining how many items exist and how title/indicator views are created for each positionmagicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/abs/IPagerIndicator.java— Abstract interface for all indicator implementations (line, bezier, triangle); defines animation and position update contractmagicindicator/src/main/java/net/lucode/hackware/magicindicator/FragmentContainerHelper.java— Enables indicator to work with Fragment switching patterns beyond ViewPager, supporting hide()/show() and setVisibility() approaches
🛠️How to make changes
Create a Custom Indicator Renderer
- Create a new class implementing IPagerIndicator interface from magicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/abs/IPagerIndicator.java (
magicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/indicators/[YourIndicator].java) - Implement onDraw(Canvas canvas) to render your custom shape based on current position/scroll state (see LinePagerIndicator.java for reference) (
magicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/indicators/[YourIndicator].java) - Implement onPageScrolled(int position, float positionOffset) to update internal state as user scrolls (
magicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/indicators/[YourIndicator].java) - Add your indicator to CommonNavigator in your Activity by calling commonNavigator.setPageIndicator(new YourIndicator()) (
app/src/main/java/net/lucode/hackware/magicindicatordemo/example/[YourExampleActivity].java)
Create a Custom Title View with Animation
- Create a class implementing IMeasurablePagerTitleView (extends IPagerTitleView) from magicindicator/src/main/java/net/lucode/hackware/magicindicator/buildins/commonnavigator/abs/IMeasurablePagerTitleView.java (
app/src/main/java/net/lucode/hackware/magicindicatordemo/ext/titles/[YourTitleView].java) - Implement onSelected(int index, boolean animate) to apply visual changes when tab becomes active (
app/src/main/java/net/lucode/hackware/magicindicatordemo/ext/titles/[YourTitleView].java) - Implement onDeselected(int index) to revert visual changes when tab loses focus (
app/src/main/java/net/lucode/hackware/magicindicatordemo/ext/titles/[YourTitleView].java) - Create a CommonNavigatorAdapter in your Activity that instantiates your title view in getTitleView() method (
app/src/main/java/net/lucode/hackware/magicindicatordemo/example/[YourExampleActivity].java) - Attach adapter to CommonNavigator via setAdapter() and set navigator on MagicIndicator via setNavigator() (
app/src/main/java/net/lucode/hackware/magicindicatordemo/example/[YourExampleActivity].java)
🪤Traps & gotchas
- The library targets API 14 (minSdkVersion 14) but demo app uses androidx; ensure you're using the correct version branch (1.6.0 for support-lib, 1.7.0+ for androidx) to avoid inflation errors.
- Custom PagerTitleView and PagerIndicator implementations must override onPageScrolled(int position, float positionOffset, int positionOffsetPixels) to animate correctly; forgetting this produces static, non-animated indicators.
- Badge layouts in app/src/main/res/layout/ (simple_count_badge_layout.xml) are inflated dynamically; ensure drawables (simple_red_dot.xml, simple_count_badge_bg.xml) exist or inflation will fail silently.
- When using non-ViewPager scenarios (Fragment switching), manual setIndicator(position) calls are required; the framework cannot auto-detect Fragment visibility changes.
💡Concepts to learn
- Adapter Pattern (CommonNavigatorAdapter) — MagicIndicator uses adapter pattern to decouple the indicator rendering from data; all custom tab/indicator implementations are injected via CommonNavigatorAdapter.getTitleView() and getIndicator(), making the framework extensible without modifying core code
- ViewPager Scroll State Machine (onPageScrolled, onPageSelected, onPageScrollStateChanged) — Custom indicators must react to three ViewPager lifecycle events (scroll offset, final selection, state change); mastering this state machine is essential for smooth animations in PagerTitleView and PagerIndicator subclasses
- LayoutInflater Factory Pattern (badge attachment) — Badges are dynamically inflated from XML layouts (simple_count_badge_layout.xml) at runtime and attached to title views; understanding Android's layout inflation is critical for customizing badge rendering
- Custom View Measurement & Layout (onMeasure, onLayout) — MagicIndicator and custom navigators must handle flexible sizing (match_parent, wrap_content, dp values); poor measurement logic causes layout glitches in scrollable tabs or dynamic tab counts
- Fragment Lifecycle & View Visibility Toggle Pattern — Non-ViewPager examples (FragmentContainerExampleActivity) use hide()/show() or setVisibility() instead of ViewPager; understanding Fragment lifecycle prevents memory leaks and state loss when manually switching views
- TypeEvaluator & ObjectAnimator (smooth indicator animation) — Title views and indicators animate during scroll (scale, color, position transitions); custom implementations like ColorFlipPagerTitleView use evaluators to interpolate between states smoothly
- Canvas Drawing & Path Rendering (custom indicators) — PagerIndicator subclasses override onDraw(Canvas) to render shapes (dots, bars, circles); understanding Canvas API and Path operations is necessary for creating novel indicator styles
🔗Related repos
google/material-components-android— Official Material Design TabLayout is the closest built-in alternative; MagicIndicator's selling point is superior customization vs. TabLayout's limited APIJakeWharton/ViewPagerIndicator— Historical predecessor (Jake Wharton's library); MagicIndicator is explicitly positioned as its modern replacement with better extensibilityastuetz/PagerSlidingTabStrip— Another widely-used indicator library that MagicIndicator competes with; comparison helps justify migrationhackware1993/Flutter_ConstraintLayout— Author's other major open-source project; demonstrates same engineering philosophy of powerful, extensible UI frameworksandroidx/androidx— MagicIndicator depends on androidx.appcompat and androidx.viewpager; understanding androidx versioning prevents compatibility issues
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive unit tests for core indicator framework classes
The repo lacks unit tests for the core MagicIndicator framework. By examining the example activities (BadgeTabExampleActivity, DynamicTabExampleActivity, etc.), we can see various use cases that need test coverage. Adding tests for ViewPager synchronization, indicator positioning, and badge updates would catch regressions early and make the library more maintainable for contributors.
- [ ] Create app/src/test/java/net/lucode/hackware/magicindicator directory structure
- [ ] Add unit tests for ViewPager page change callbacks and indicator position updates (test synchronization between indicator and ViewPager state)
- [ ] Add unit tests for dynamic tab addition/removal based on DynamicTabExampleActivity logic
- [ ] Add unit tests for badge display/update behavior as shown in BadgeTabExampleActivity
Add instrumented Android tests for UI rendering and animations
Since MagicIndicator is a visual framework with custom drawing and animations, instrumented tests are critical. The example activities demonstrate scroll animations, title transitions (ColorFlipPagerTitleView, ScaleTransitionPagerTitleView), and custom navigator scaling. These need UI tests to verify correct rendering across different Android versions and screen sizes.
- [ ] Create app/src/androidTest/java/net/lucode/hackware/magicindicatordemo directory for instrumented tests
- [ ] Add UI tests for indicator animation correctness using Espresso, verifying smooth transitions between pages
- [ ] Add tests for title view animations (ColorFlipPagerTitleView, ScaleTransitionPagerTitleView) to verify visual effects render correctly
- [ ] Add tests for FragmentContainerExampleActivity behavior without ViewPager (hide/show Fragment transitions)
Create GitHub Actions CI workflow for automated testing and APK building
The repo has no visible CI/CD pipeline (no .github/workflows directory visible in the structure). Adding automated testing on every PR would improve code quality. Given the compileSdkVersion 28 and minSdkVersion 14 range, a workflow should test across API levels and generate demo APK artifacts automatically.
- [ ] Create .github/workflows/android-ci.yml with Gradle build and test steps
- [ ] Configure the workflow to run on pull_request and push events to main/master branch
- [ ] Add steps to run unit tests (./gradlew test) and instrumented tests (./gradlew connectedAndroidTest) with emulator
- [ ] Add artifact upload step to attach built demo.apk to workflow results for easy testing
🌿Good first issues
- Add unit tests for CommonNavigatorAdapter contract (verify getCount(), getTitleView(), and getIndicator() are called in correct order) in a new test/ directory alongside examples.
- Document the exact lifecycle of PagerIndicator.onPageScrolled() with a sequence diagram and annotated example in README.md, since three example implementations (DotPagerIndicator, CommonPagerIndicator, custom ones) all override it differently.
- Create a new example activity LoadDynamicBadgesExampleActivity.java showing how to update badge counts at runtime (call updateIndicator() or setAdapter() on CommonNavigator) without rebuilding the entire MagicIndicator, with comments on performance implications.
📝Recent commits
Click to expand
Recent commits
🔒Security observations
The MagicIndicator codebase shows a low-to-medium security risk profile typical of older Android libraries. Primary concerns are outdated build tools and dependencies (SDK 28, AndroidX 1.2.0 from 2020), lack of code obfuscation in releases, and an extremely low minSdkVersion targeting. The library itself is a UI indicator framework with minimal data handling, reducing injection and credential exposure risks. Immediate recommendations: update compileSdkVersion to 33+, enable minification for release builds, update AndroidX to latest, and increase minSdkVersion to 21+. These changes will significantly improve security posture and align with current Android security best practices.
- Medium · Outdated Android Build Tools and SDK —
app/build.gradle. The project uses compileSdkVersion 28 and buildToolsVersion 28.0.3, which are significantly outdated (released in 2018-2019). This may miss critical security patches and bug fixes available in newer Android versions. Modern standards recommend compileSdkVersion 33+ and latest build tools. Fix: Update compileSdkVersion to 33 or higher and buildToolsVersion to the latest available version. Review and update targetSdkVersion to match or exceed compileSdkVersion. - Medium · Outdated AndroidX Dependency —
app/build.gradle. The androidx.appcompat dependency is pinned to version 1.2.0 (released in 2020). This version is outdated and may contain known security vulnerabilities that have been patched in newer releases. Fix: Update androidx.appcompat to the latest stable version (currently 1.6.x). Regularly update all dependencies to their latest versions and monitor security advisories. - Medium · Minify Disabled in Release Build —
app/build.gradle. The release build type has minifyEnabled set to false. This means the APK is not obfuscated, making it easier for attackers to reverse-engineer the application code and identify potential vulnerabilities or business logic. Fix: Enable minification by setting minifyEnabled true and configure an appropriate ProGuard/R8 rules file to obfuscate code while preserving necessary functionality. - Low · Low Minimum SDK Version —
app/build.gradle. The application targets minSdkVersion 14 (Android 4.0, released in 2011). This is extremely old and may support devices with known security vulnerabilities. Modern apps should target minSdkVersion 21 or higher. Fix: Increase minSdkVersion to at least 21 (Android 5.0 or later). This allows use of modern security APIs and reduces attack surface from legacy OS vulnerabilities. - Low · Missing Security-Related Gradle Properties —
app/build.gradle and magicindicator/build.gradle. No explicit security configurations are visible in the build.gradle files, such as security provider updates or network security configuration references. While not a critical issue for this UI library, it's a best practice. Fix: Consider adding gradle security plugins (e.g., dependency-check plugin) to scan for known vulnerabilities in dependencies. Ensure AndroidManifest.xml includes a network security configuration.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.