{"id":13470846,"url":"https://github.com/rubengees/introduction","last_synced_at":"2025-04-06T08:13:54.191Z","repository":{"id":94425214,"uuid":"42452010","full_name":"rubengees/introduction","owner":"rubengees","description":"An Android library to show an intro to your users.","archived":false,"fork":false,"pushed_at":"2018-01-05T18:51:07.000Z","size":24526,"stargazers_count":459,"open_issues_count":0,"forks_count":55,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-03-30T06:11:08.280Z","etag":null,"topics":["android","intro","library","tour"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rubengees.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-09-14T13:59:08.000Z","updated_at":"2024-10-18T14:34:56.000Z","dependencies_parsed_at":"2023-05-17T22:30:21.984Z","dependency_job_id":null,"html_url":"https://github.com/rubengees/introduction","commit_stats":null,"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubengees%2Fintroduction","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubengees%2Fintroduction/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubengees%2Fintroduction/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubengees%2Fintroduction/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rubengees","download_url":"https://codeload.github.com/rubengees/introduction/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247451665,"owners_count":20940944,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","intro","library","tour"],"created_at":"2024-07-31T16:00:36.514Z","updated_at":"2025-04-06T08:13:54.171Z","avatar_url":"https://github.com/rubengees.png","language":"Java","funding_links":[],"categories":["Java"],"sub_categories":[],"readme":"# Introduction [![Download](https://img.shields.io/github/release/rubengees/introduction.svg?label=JitPack)](https://jitpack.io/#rubengees/introduction/) ![API](https://img.shields.io/badge/API-14%2B-blue.svg) [![CircleCI](https://circleci.com/gh/rubengees/introduction.svg?style=shield)](https://circleci.com/gh/rubengees/introduction)\r\n\r\nShow a beautiful Intro to your users with ease.\r\n\r\n![](art/screenshot_gallery.png)\r\n\r\nYou can download the latest sample app [here](https://github.com/rubengees/introduction/releases/download/2.0.0/sample-release.apk).\r\n\r\n### Table of contents\r\n\r\n- [Include in your Project](#include-in-your-project)\r\n- [Usage](#usage)\r\n  - [Options](#options)\r\n  - [Use Gifs as images](#use-gifs-as-images)\r\n  - [Runtime Permissions](#runtime-permissions)\r\n  - [Styles](#styles)\r\n  - [Custom Views](#custom-views)\r\n  - [Further reading](#further-reading)\r\n- [Upgrade Guide](#upgrade-guide)\r\n  - [1.4.0+ to 2.0.0+](#140-to-200)\r\n  - [1.3.9 to 1.4.0+](#139-to-140)\r\n  - [1.1.0 to 1.1.1+](#110-to-111)\r\n  - [1.0.x to 1.1.0+](#10x-to-110)\r\n- [Metrics](#metrics)\r\n- [Contributions and contributors](#contributions-and-contributors)\r\n- [Acknowledgments](#acknowledgments)\r\n\r\n### Include in your Project\r\n\r\nAdd this to your root `build.gradle` (usually in the root of your project):\r\n\r\n```groovy\r\nrepositories {\r\n    maven { url \"https://jitpack.io\" }\r\n}\r\n```\r\n\r\nAnd this to your module `build.gradle` (usually in the `app` directory):\r\n\r\n```groovy\r\ndependencies {\r\n    implementation 'com.github.rubengees:introduction:2.0.0'\r\n}\r\n```\r\n\r\nIf that doesn't work, look if there is a new version and the Readme was not updated yet.\r\n\r\nIf you want to use asynchronous image loading, introduced in the new version 1.1.0, you will need [Glide](https://github.com/bumptech/glide) or some other image loading library. If you want to use GIFs you will also need it.\r\n\r\n### Usage\r\n\r\nCreate an `IntroductionBuilder` like the following:\r\n\r\n```java\r\nnew IntroductionBuilder(this) // this is the Activity you want to start from.\r\n```\r\n\r\nThen add some Slides to your Introduction:\r\n\r\n```java\r\nnew IntroductionBuilder(this).withSlides(generateSlides())\r\n```\r\n\r\n```java\r\nprivate List\u003cSlide\u003e generateSlides() {\r\n    List\u003cSlide\u003e result = new ArrayList\u003c\u003e();\r\n\r\n    result.add(new Slide()\r\n            .withTitle(\"Some title\")\r\n            .withDescription(\"Some description\")\r\n            .withColorResource(R.color.green)\r\n            .withImage(R.drawable.myImage)\r\n    );\r\n\r\n    result.add(new Slide()\r\n            .withTitle(\"Another title\")\r\n            .withDescription(\"Another description\")\r\n            .withColorResource(R.color.indigo)\r\n            .withImage(R.drawable.myImage2)\r\n    );\r\n\r\n    return result;\r\n}\r\n```\r\n\r\nFinally introduce yourself!\r\n\r\n```java\r\nnew IntroductionBuilder(this).withSlides(generateSlides()).introduceMyself();\r\n```\r\n\r\nThat was easy right?\r\n\r\nYou can do many customizations, which will be covered by the following.\r\n\r\n##### Options\r\n\r\nYou can let the user make decisions, which you can use like settings.\r\nTo do that you add an Option to your slide:\r\n\r\n```java\r\nnew Slide().withTitle(\"Feature is doing something\")\r\n          .withOption(new Option(\"Enable the feature\"))\r\n          .withColorResource(R.color.orange)\r\n          .withImage(R.drawable.image));\r\n```\r\n\r\nWhen the user completes the intro, you will receive the selected Options in `onActivityResult`.\r\nTo read the result:\r\n\r\n```java\r\n@Override\r\nprotected void onActivityResult(int requestCode, int resultCode, Intent data) {\r\n     if (requestCode == IntroductionBuilder.INTRODUCTION_REQUEST_CODE \u0026\u0026 resultCode == RESULT_OK) {\r\n         String result = \"User chose: \";\r\n\r\n         for (Option option : data.\u003cOption\u003egetParcelableArrayListExtra(IntroductionActivity.OPTION_RESULT)) {\r\n            result += option.getPosition() + (option.isActivated() ? \" enabled\" : \" disabled\");\r\n        }\r\n     }\r\n}\r\n```\r\n\r\nThe constant value of the request is 32142, so don't use that yourself.\r\nIt is possible that the user cancels the intro. If that happens, the resultCode is `RESULT_CANCELLED` and no Options are passed back.\r\n\r\n##### Use Gifs as images\r\n\r\nThis library supports GIFs. You need to load them asynchronously as the loading may take a while:\r\n\r\n```java\r\nnew IntroductionBuilder(this)\r\n        .withSlides(slides)\r\n        .withOnSlideListener(new OnSlideListener() {\r\n            @Override\r\n            public void onSlideInit(int position, @Nullable TextView title, @NonNull ImageView image,\r\n                                    @Nullable TextView description) {\r\n                if (position == 1) { // Assume we want to load the GIF at Slide 2 (index 1).\r\n                    Glide.with(image.getContext())\r\n                            .load(R.drawable.image3)\r\n                            .into(image);\r\n                }\r\n            }\r\n        }).introduceMyself();\r\n```\r\n\r\nThis will add the GIF, which will be automatically played when the users navigates to the Slide.\r\n\r\n##### Runtime Permissions\r\n\r\nAndroid Marshmallow introduced Runtime Permissions, which can be requested easily with this lib.\r\nTo do that, you can add a global listener like the following:\r\n\r\n```java\r\nnew IntroductionBuilder(this)\r\n        .withSlides(slides)\r\n        .withOnSlideListener(new OnSlideListener() {\r\n            @Override\r\n            public void onSlideChanged(int from, int to) {\r\n                if (from == 0 \u0026\u0026 to == 1) {\r\n                    if (ActivityCompat.checkSelfPermission(MainActivity.this,\r\n                            Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {\r\n                        ActivityCompat.requestPermissions(MainActivity.this,\r\n                                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 12);\r\n                    }\r\n                }\r\n            }\r\n        }).introduceMyself();\r\n```\r\n\r\nYou can check if the permissions were granted like the following:\r\n\r\n```java\r\n@Override\r\npublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,\r\n                                       @NonNull int[] grantResults) {\r\n    super.onRequestPermissionsResult(requestCode, permissions, grantResults);\r\n\r\n    if (requestCode == 12) {\r\n        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {\r\n            Toast.makeText(this, \"Permission was successfully granted!\", Toast.LENGTH_LONG).show();\r\n        }\r\n    }\r\n}\r\n```\r\n\r\nYou can use that listener for different things too, of course!\r\n\r\n##### Styles\r\n\r\nThere are two available styles: `Translucent` and `Fullscreen`.\r\nTo apply one of those styles, do the following:\r\n\r\n```java\r\nnew IntroductionBuilder(this)\r\n                .withSlides(generateSlides())\r\n                .withStyle(new FullscreenStyle())\r\n                .introduceMyself();\r\n```\r\n\r\n`Translucent` is the default style.\r\n\r\n##### Custom Views\r\n\r\nYou can supply your own View to a Slide instead of just setting the title, image and description.\u003cbr\u003e\r\nThis is done like follows:\r\n\r\nCreate a class which implements CustomViewBuilder:\u003cbr\u003e\r\n\r\n```java\r\npublic class CustomViewBuilderImpl implements Slide.CustomViewBuilder {\r\n\r\n    @NonNull\r\n    @Override\r\n    public View buildView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {\r\n        return inflater.inflate(R.layout.layout_custom, parent, false);\r\n    }\r\n}\r\n```\r\n\r\nThen set it to your Slide:\r\n\r\n```java\r\nnew IntroductionBuilder(this)\r\n        .withSlides(new Slide()\r\n                .withCustomViewBuilder(new CustomViewBuilderImpl())\r\n                .withColorResource(R.color.cyan)\r\n        ).introduceMyself();\r\n```\r\n\r\nIf you set a CustomViewBuilder to your Slide, all other values aside from the color are overridden. You have to manage all on your own.\r\n\r\n##### Further reading\r\n\r\nA much more detailed explanation with all available APIs can be found in the [Wiki](https://github.com/RubenGees/Introduction/wiki).\u003cbr\u003e\r\nDetailed Javadoc can be found [here](https://jitpack.io/com/github/rubengees/introduction/2.0.0/javadoc/).\r\n\r\n### Upgrade Guide\r\n\r\n#### 1.4.0+ to 2.0.0+\r\n\r\n- This library now requires Java 8 (available in the new `Android Studio 3` [toolchain](https://developer.android.com/studio/write/java8-support.html)).\r\n- Behaviour change: Not passing a `title`, `description` or `option` hides the respective views. This way you can show fullscreen images.\r\n  - The `title` and `description` parameters of the `onSlideInit` callback are now `@Nullable`\r\n- `CustomViewBuilder` is now in a different package and has been converted into an `interface`.\r\n\r\n#### 1.3.9 to 1.4.0+\r\n\r\n- `Slide` and `Option` have been moved into a different package. Just let Android Studio re-import them.\r\n- The `OnSlideListener` is now an interface on its own. Remove `IntroductionConfig` before each and let Android Studio re-import. Furthermore `@NotNull` annotations have been added; You should add them to the signature.\r\n\r\n#### 1.1.0 to 1.1.1+\r\n\r\n- The `OnSlideInit` method in the `OnSlideListener` now comes without the `Fragment context`. If you need a `Context`, call `image.getContext()`.\r\n- There is now a class for Styles instead of an Integer. If you apply no Style, you have to do nothing, if you use one, change it to the following e.g.: `.withStyle(new FullscreenStyle())`.\r\n\r\n#### 1.0.x to 1.1.0+\r\n\r\n- The `OnSlideChangedListener` was renamed to `OnSlideListener`. Just rename it and it's working again.\r\n- Asynchronous image loading is now available (and recommended!). See the [Use GIFs as drawables](#Use-Gifs-as-images) section for more info. It applies for all types of images. GIFs won't work without asynchronous loading from now on!\r\n\r\n### Metrics\r\n\r\n\u003ca href=\"http://www.methodscount.com/?lib=com.github.rubengees%3Aintroduction%3A2.0.0\"\u003e\u003cimg src=\"https://img.shields.io/badge/Methods and size-core: 307 | deps: 16517 | 54 KB-e91e63.svg\"/\u003e\u003c/a\u003e\u003cbr\u003e\r\n\r\n### Contributions and contributors\r\n\r\nA guide for contribution can be found [here](.github/CONTRIBUTING.md).\r\n\r\n- [@Akeshihiro](https://github.com/Akeshihiro) for proper licencing and a small `Gradle` related adjustment.\r\n- [@cafedeaqua](https://github.com/cafedeaqua) for a small code improvement\r\n\r\n### Acknowledgments\r\n\r\nThe images in the samples are taken from the following webpages (I do not own any of the images, all rights are reserved to their respective owners):\r\n\r\n- [image1.jpg](https://www.flickr.com/photos/rbulmahn/6180104944/in/photolist-89W1PC-8Q713U-9BussZ-cwr9kY-9XzRzZ-83z8K5-84k3xS-adM5Y9-drdDdf-e1wXZE-6kzXBW-aq7DTw-98qbVd-83w6aa-6TYUqy-bttVPE-jPnPwv-83zc5G-9mgbHk-bmJtgf-c8f3yC-6T4zxf-83jUyV-9WRbGQ-6RrUxc-6oHoaj-7Z2YXE-oveaff-8rNmyh-f95MK4-8EFVd6-kiJrYR-9Y8USW-9qC58Z-o7ZmL9-ovdL7H-oMHywk-oMFMME-oMrEw4-oMHy8e-ovaLae-ovaL5K-ovaL2t-ovaKLZ-oMoBJr-89SKWD-89W1Bu-89SKwT-89SKwa-89W1kG)\r\n- [image2.jpg](https://www.flickr.com/photos/uncalno/8538679708/in/photolist-e1wXZE-6kzXBW-aq7DTw-98qbVd-83w6aa-6TYUqy-bttVPE-jPnPwv-83zc5G-9mgbHk-bmJtgf-c8f3yC-6T4zxf-83jUyV-9WRbGQ-6RrUxc-6oHoaj-7Z2YXE-oveaff-8rNmyh-f95MK4-8EFVd6-kiJrYR-9Y8USW-9qC58Z-o7ZmL9-ovdL7H-oMHywk-oMFMME-oMrEw4-oMHy8e-ovaLae-ovaL5K-ovaL2t-ovaKLZ-oMoBJr-89SKWD-89W1Bu-89SKwT-89SKwa-89W1kG-89W1kb-89W1jN-89W15E-89VZRs-89VZDb-9kUiFS-9957fA-ehs7zp-5yFrKB)\r\n- [image3.gif](http://www.modaco.com/forums/topic/344506-android-startshutdown-animation-for-i900/)\r\n\r\nSome images and ideas are from this Repo: [AppIntro by Paolo Rotolo](https://github.com/PaoloRotolo/AppIntro)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubengees%2Fintroduction","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frubengees%2Fintroduction","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubengees%2Fintroduction/lists"}