├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── github │ │ └── iojjj │ │ └── likeslayout │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── iojjj │ │ │ └── likeslayout │ │ │ └── app │ │ │ ├── BaseFragment.java │ │ │ ├── ChooseFragment.java │ │ │ ├── CustomDrawableAnimatorFactory.java │ │ │ ├── CustomPositionAnimatorFactory.java │ │ │ ├── CustomPositionAnimatorFactory2.java │ │ │ ├── FromCodeFragment.java │ │ │ ├── FromXmlFragment.java │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable-anydpi │ │ ├── ic_favorite_normal.xml │ │ ├── ic_favorite_pressed.xml │ │ ├── ic_grade_normal.xml │ │ ├── ic_grade_pressed.xml │ │ ├── ic_stars_colored.xml │ │ ├── ic_stars_normal.xml │ │ └── ic_stars_pressed.xml │ │ ├── drawable │ │ ├── ic_favorite.xml │ │ ├── ic_grade.xml │ │ └── ic_stars.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_code.xml │ │ └── fragment_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── github │ └── iojjj │ └── likeslayout │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── images └── demo.gif ├── library ├── .gitignore ├── build.gradle ├── gradle-mvn-push.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── github │ │ └── iojjj │ │ └── likeslayout │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── iojjj │ │ │ └── likeslayout │ │ │ ├── DrawableAnimator.java │ │ │ ├── LikesAttributes.java │ │ │ ├── LikesAttributesImpl.java │ │ │ ├── LikesDrawer.java │ │ │ ├── LikesFrameLayout.java │ │ │ ├── LikesLayout.java │ │ │ ├── LikesLayoutInternal.java │ │ │ ├── LikesLayoutParams.java │ │ │ ├── LikesLinearLayout.java │ │ │ ├── LikesProducer.java │ │ │ ├── LikesRelativeLayout.java │ │ │ ├── OnChildTouchListener.java │ │ │ ├── PositionAnimator.java │ │ │ └── Utilities.java │ └── res │ │ └── values │ │ ├── integers.xml │ │ ├── likes_attrs.xml │ │ ├── public.xml │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── github │ └── iojjj │ └── likeslayout │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | ### Android template 2 | # Built application files 3 | *.apk 4 | *.ap_ 5 | 6 | # Files for the Dalvik VM 7 | *.dex 8 | 9 | # Java class files 10 | *.class 11 | 12 | # Generated files 13 | bin/ 14 | gen/ 15 | out/ 16 | 17 | # Gradle files 18 | .gradle/ 19 | build/ 20 | 21 | # Local configuration file (sdk path, etc) 22 | local.properties 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Log Files 28 | *.log 29 | 30 | # Android Studio Navigation editor temp files 31 | .navigation/ 32 | 33 | # Android Studio captures folder 34 | captures/ 35 | 36 | # Intellij 37 | 38 | # Keystore files 39 | *.jks 40 | *.iml 41 | .gradle 42 | /local.properties 43 | /.idea/workspace.xml 44 | /.idea/libraries 45 | .DS_Store 46 | /build 47 | /captures 48 | gradle 49 | .idea 50 | gradlew 51 | gradlew.bat -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Likes Layout 2 | 3 | LikesLayout is an implementation of layout that can draw likes similar to [Periscope app](https://play.google.com/store/apps/details?id=tv.periscope.android). 4 | 5 | ![Likes Layout Demo](/images/demo.gif) 6 | 7 | 8 | ## Setup and usage 9 | 10 | To include this library to your project add dependency in **build.gradle** file: 11 | 12 | ```groovy 13 | dependencies { 14 | compile 'com.github.iojjj:likeslayout:1.0.0' 15 | } 16 | ``` 17 | 18 | There are three implementations of `LikesLayout` interface: **LikesFrameLayout**, **LikesLinearLayout**, **LikesRelativeLayout**. You can add them to your view via XML or in Java code. 19 | 20 | ```XML 21 | 34 | 35 | 48 | 49 | 50 | ``` 51 | 52 | or 53 | 54 | ```JAVA 55 | // create new LikesLayout 56 | LikesLinearLayout likesLinearLayout = new LikesLinearLayout(getContext()); 57 | likesLinearLayout.setId(R.id.likes_layout); 58 | // set layout height 59 | final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 60 | (int) (getResources().getDisplayMetrics().density * 250)); 61 | likesLinearLayout.setLayoutParams(params); 62 | likesLinearLayout.setOrientation(LinearLayout.HORIZONTAL); 63 | // make sure your buttons located at the bottom of LikesLayout 64 | likesLinearLayout.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL); 65 | likesLinearLayout.setPadding(0, 0, 0, (int) (getResources().getDisplayMetrics().density * 16)); 66 | // get attributes object that will store default values 67 | likesLinearLayout.getAttributes().setAnimationDuration(1200); 68 | likesLinearLayout.getAttributes().setTintMode(LikesAttributes.TINT_MODE_ON_SUCCESSIVELY); 69 | likesLinearLayout.getAttributes().setTintColors(colors); 70 | 71 | // it's time to add a button 72 | ImageButton button = new ImageButton(getContext(), null, R.style.LikeButton_Grade); 73 | button.setId(R.id.btn_grade); 74 | button.setImageResource(R.drawable.ic_grade); 75 | DrawableCompat.setTint(button.getDrawable(), ContextCompat.getColor(getContext(), R.color.colorAccent)); 76 | // you can create layout params for your button using LikesLayout.newLayoutParamsBuilder() method 77 | // then using a builder you can set all necessary attributes values 78 | final ViewGroup.LayoutParams params = likesLinearLayout 79 | .newLayoutParamsBuilder(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) 80 | .setDrawable(ContextCompat.getDrawable(getContext(), R.drawable.ic_grade_normal)) 81 | .setAnimationDuration(3000) 82 | .setProduceInterval(500) 83 | .setPositionAnimatorFactory(new CustomPositionAnimatorFactory2()) 84 | // don't forget to enable likes mode :) 85 | .setLikesMode(LikesAttributes.LIKES_MODE_ENABLED) 86 | .build(); 87 | // set parameters and add button to LikesLayout 88 | button.setLayoutParams(params); 89 | likesLinearLayout.addView(button); 90 | ``` 91 | 92 | There is the list of available attributes: 93 | 94 | | Attribute name | ATLL | CBOBC | Description | Default value | 95 | | --- | --- | --- | --- | --- | 96 | | likes_animationDuration | yes | yes | Animation duration in milliseconds. | 1200 | 97 | | likes_drawable | yes | yes | Drawable that will be drawn when user presses view. | null | 98 | | likes_drawableAnimator | yes | yes | Drawable animator factory. | @string/likes_drawable_animator_factory | 99 | | likes_drawableHeight | yes | yes | Custom drawable height. | 0 | 100 | | likes_drawablePositionAnimator | yes | yes | Drawable's position animator factory. | @string/likes_position_animator_factory | 101 | | likes_drawableWidth | yes | yes | Custom drawable width. | 0 | 102 | | likes_mode | no | yes | Switch that allows to enable/disable drawing likes on touching child view. If `likes_drawable` is null, `likes_mode` will be considered as `disabled`. | disabled | 103 | | likes_produceInterval | yes | yes | Rate at which new likes drawables are produced in milliseconds. | 300 | 104 | | likes_tintMode | yes | yes | Switch that allows to enable/disable tinting drawables. | not_set | 105 | | likes_tintColors | yes | yes | Array of colors used for tinting drawables. If array is empty, `likes_tintMode` will be considered as `off`.| null | 106 | 107 | Where: 108 | 109 | * **ATLL** - Available to LikesLayout 110 | * **CBOBC** - Can be overridden by child? 111 | 112 | ## Produce likes programmatically 113 | For this case you can use `LikesLayout.produceLikes(...)` methods, for example: 114 | 115 | ```JAVA 116 | mLikesLayout.produceLikes(mBtnFavorite, 3, TimeUnit.SECONDS); 117 | ``` 118 | 119 | Make sure that child passed as an argument (`mBtnFavorite`) was added to this `mLikesLayout` (via XML or Java code). Otherwise you will get `IllegalArgumentException`. 120 | 121 | ## Custom Animations 122 | You can provide your own animations. There are two types of animators available: `DrawableAnimator` and `PositionAnimator`. First one used for animating drawable itself (size, alpha, etc). Second one used for animating drawable's position. Note that `PositionAnimator` animates center of drawable. 123 | To use your custom animations you need to create `DrawableAnimator.Factory` or `PositionAnimator.Factory` implementations. Then you can set them via XML or in Java code. 124 | 125 | ## Restrictions 126 | * If you will not set `likes_mode` or set it to `disabled`, this view will not draw any likes. 127 | * All attributes applicable to LikesLayout will be used as default values for child with `likes_mode` set to `enabled`. 128 | * Custom drawable width and height will set exact size ignoring aspect ratio. 129 | * Likes floating from bottom to top. 130 | 131 |
132 | ## Changelog 133 | 134 | | Version | Changes | 135 | | --- | --- | 136 | | v.1.0.0 | First public release | 137 | 138 |
139 | ## Support 140 | 141 | You can support this library by creating a pull request with bug fixes and/or new features on `develop` branch. Any pull requests on `master` branch will be removed. 142 | 143 |
144 | ## License 145 | * * * 146 | The MIT License (MIT) 147 | 148 | Permission is hereby granted, free of charge, to any person obtaining a copy 149 | of this software and associated documentation files (the "Software"), to deal 150 | in the Software without restriction, including without limitation the rights 151 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 152 | copies of the Software, and to permit persons to whom the Software is 153 | furnished to do so, subject to the following conditions: 154 | 155 | The above copyright notice and this permission notice shall be included in all 156 | copies or substantial portions of the Software. 157 | 158 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 159 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 160 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 161 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 162 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 163 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 164 | SOFTWARE. -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | dependencies { 6 | classpath 'me.tatarka:gradle-retrolambda:3.2.5' 7 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' 8 | } 9 | } 10 | 11 | apply plugin: 'com.android.application' 12 | apply plugin: 'com.neenbedankt.android-apt' 13 | apply plugin: 'me.tatarka.retrolambda' 14 | 15 | android { 16 | compileSdkVersion 23 17 | buildToolsVersion "24.0.0-rc3" 18 | 19 | defaultConfig { 20 | applicationId "com.github.iojjj.likeslayout.app" 21 | minSdkVersion 14 22 | targetSdkVersion 23 23 | versionCode 1 24 | versionName "1.0" 25 | } 26 | buildTypes { 27 | release { 28 | minifyEnabled false 29 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 30 | } 31 | } 32 | 33 | compileOptions { 34 | sourceCompatibility JavaVersion.VERSION_1_8 35 | targetCompatibility JavaVersion.VERSION_1_8 36 | } 37 | 38 | productFlavors { 39 | defaultConfig { 40 | minSdkVersion 14 41 | targetSdkVersion 23 42 | } 43 | instantRun { 44 | minSdkVersion 21 45 | targetSdkVersion 23 46 | } 47 | } 48 | } 49 | 50 | dependencies { 51 | compile fileTree(dir: 'libs', include: ['*.jar']) 52 | testCompile 'junit:junit:4.12' 53 | compile 'com.android.support:appcompat-v7:23.4.0' 54 | compile 'com.jakewharton:butterknife:8.0.1' 55 | apt 'com.jakewharton:butterknife-compiler:8.0.1' 56 | compile project(':library') 57 | } 58 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in E:\Documents\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/github/iojjj/likeslayout/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.iojjj.likeslayout; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/iojjj/likeslayout/app/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.iojjj.likeslayout.app; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.View; 7 | import android.widget.TextView; 8 | 9 | import com.github.iojjj.likeslayout.LikesLinearLayout; 10 | import com.github.iojjj.likeslayout.OnChildTouchListener; 11 | 12 | import java.util.Locale; 13 | 14 | import butterknife.BindView; 15 | import butterknife.ButterKnife; 16 | import butterknife.Unbinder; 17 | 18 | /** 19 | * Base fragment implementation. 20 | */ 21 | public class BaseFragment extends Fragment implements OnChildTouchListener { 22 | 23 | @BindView(R.id.status) 24 | TextView mStatus; 25 | 26 | @BindView(R.id.likes_layout) 27 | LikesLinearLayout mLikesLayout; 28 | 29 | private int mFavoriteCounter; 30 | private int mGradeCounter; 31 | private int mStarsCounter; 32 | private Unbinder mUnbinder; 33 | 34 | @Override 35 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 36 | super.onViewCreated(view, savedInstanceState); 37 | mUnbinder = ButterKnife.bind(this, view); 38 | mLikesLayout.setOnChildTouchListener(this); 39 | updateStatus(); 40 | } 41 | 42 | @Override 43 | public void onDestroyView() { 44 | mUnbinder.unbind(); 45 | super.onDestroyView(); 46 | } 47 | 48 | @Override 49 | public void onChildTouched(View child) { 50 | 51 | } 52 | 53 | @Override 54 | public void onLikeProduced(View child) { 55 | // do something here 56 | switch (child.getId()) { 57 | case R.id.btn_favorite: { 58 | mFavoriteCounter++; 59 | break; 60 | } 61 | case R.id.btn_grade: { 62 | mGradeCounter++; 63 | break; 64 | } 65 | case R.id.btn_stars: { 66 | mStarsCounter++; 67 | break; 68 | } 69 | } 70 | updateStatus(); 71 | } 72 | 73 | @Override 74 | public void onChildReleased(View child, boolean isCanceled) { 75 | 76 | } 77 | 78 | private void updateStatus() { 79 | mStatus.setText(String.format(Locale.US, "Counter. favorites: %1$d, grades: %2$d, stars: %3$d", 80 | mFavoriteCounter, mGradeCounter, mStarsCounter)); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/iojjj/likeslayout/app/ChooseFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.iojjj.likeslayout.app; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.ListFragment; 6 | import android.view.View; 7 | import android.widget.AdapterView; 8 | import android.widget.ArrayAdapter; 9 | 10 | /** 11 | * Fragment that allows to choose what demo to show. 12 | */ 13 | public class ChooseFragment extends ListFragment implements AdapterView.OnItemClickListener { 14 | 15 | public static ChooseFragment newInstance() { 16 | Bundle args = new Bundle(); 17 | ChooseFragment fragment = new ChooseFragment(); 18 | fragment.setArguments(args); 19 | return fragment; 20 | } 21 | 22 | @Override 23 | public void onViewCreated(View view, Bundle savedInstanceState) { 24 | super.onViewCreated(view, savedInstanceState); 25 | String[] items = getResources().getStringArray(R.array.choices); 26 | setListAdapter(new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, items)); 27 | getListView().setOnItemClickListener(this); 28 | } 29 | 30 | @Override 31 | public void onItemClick(AdapterView parent, View view, int position, long id) { 32 | Fragment fragment; 33 | if (position == 0) { 34 | fragment = FromXmlFragment.newInstance(); 35 | } else { 36 | fragment = FromCodeFragment.newInstance(); 37 | } 38 | getActivity().getSupportFragmentManager().beginTransaction() 39 | .replace(R.id.container, fragment) 40 | .addToBackStack(null) 41 | .commit(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/iojjj/likeslayout/app/CustomDrawableAnimatorFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.iojjj.likeslayout.app; 2 | 3 | import com.github.iojjj.likeslayout.DrawableAnimator; 4 | 5 | /** 6 | * Custom drawable animator factory. 7 | */ 8 | public class CustomDrawableAnimatorFactory implements DrawableAnimator.Factory { 9 | @Override 10 | public DrawableAnimator newInstance() { 11 | return new DrawableAnimator.AlphaDrawableAnimator(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/iojjj/likeslayout/app/CustomPositionAnimatorFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.iojjj.likeslayout.app; 2 | 3 | import com.github.iojjj.likeslayout.PositionAnimator; 4 | 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | /** 8 | * Custom position animator factory. 9 | */ 10 | public class CustomPositionAnimatorFactory implements PositionAnimator.Factory { 11 | 12 | private final AtomicInteger pathGenerator = new AtomicInteger(); 13 | 14 | @Override 15 | public PositionAnimator newInstance() { 16 | return new PositionAnimator.LinearSuccessiveRoutePositionAnimator(pathGenerator); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/iojjj/likeslayout/app/CustomPositionAnimatorFactory2.java: -------------------------------------------------------------------------------- 1 | package com.github.iojjj.likeslayout.app; 2 | 3 | import com.github.iojjj.likeslayout.PositionAnimator; 4 | 5 | /** 6 | * Custom position animator factory. 7 | */ 8 | public class CustomPositionAnimatorFactory2 implements PositionAnimator.Factory { 9 | 10 | @Override 11 | public PositionAnimator newInstance() { 12 | return new PositionAnimator.LinearRandomRoutePositionAnimator(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/iojjj/likeslayout/app/FromCodeFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.iojjj.likeslayout.app; 2 | 3 | import android.content.res.TypedArray; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.content.ContextCompat; 8 | import android.support.v4.graphics.drawable.DrawableCompat; 9 | import android.support.v4.widget.Space; 10 | import android.view.Gravity; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.widget.ImageButton; 15 | import android.widget.LinearLayout; 16 | import android.widget.RelativeLayout; 17 | 18 | import com.github.iojjj.likeslayout.LikesAttributes; 19 | import com.github.iojjj.likeslayout.LikesLinearLayout; 20 | 21 | /** 22 | * Fragment that constructs LikesLayout from code. 23 | */ 24 | public class FromCodeFragment extends BaseFragment { 25 | 26 | public static FromCodeFragment newInstance() { 27 | Bundle args = new Bundle(); 28 | FromCodeFragment fragment = new FromCodeFragment(); 29 | fragment.setArguments(args); 30 | return fragment; 31 | } 32 | 33 | @Nullable 34 | @Override 35 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 36 | ViewGroup view = (ViewGroup) inflater.inflate(R.layout.fragment_code, container, false); 37 | LikesLinearLayout likesLinearLayout = new LikesLinearLayout(getContext()); 38 | likesLinearLayout.setId(R.id.likes_layout); 39 | final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 40 | (int) (getResources().getDisplayMetrics().density * 250)); 41 | params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); 42 | likesLinearLayout.setLayoutParams(params); 43 | likesLinearLayout.setOrientation(LinearLayout.HORIZONTAL); 44 | likesLinearLayout.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL); 45 | likesLinearLayout.setPadding(0, 0, 0, (int) (getResources().getDisplayMetrics().density * 16)); 46 | likesLinearLayout.getAttributes().setAnimationDuration(1200); 47 | likesLinearLayout.getAttributes().setTintMode(LikesAttributes.TINT_MODE_ON_SUCCESSIVELY); 48 | TypedArray colorsArray = getResources().obtainTypedArray(R.array.drawable_colors); 49 | int[] colors = new int[colorsArray.length()]; 50 | for (int i = 0; i < colors.length; i++) { 51 | colors[i] = colorsArray.getColor(i, Color.TRANSPARENT); 52 | } 53 | likesLinearLayout.getAttributes().setTintColors(colors); 54 | colorsArray.recycle(); 55 | addFavoriteButton(likesLinearLayout); 56 | addSpace(likesLinearLayout); 57 | addGradeButton(likesLinearLayout); 58 | addSpace(likesLinearLayout); 59 | addStarsButton(likesLinearLayout); 60 | view.addView(likesLinearLayout); 61 | return view; 62 | } 63 | 64 | private void addSpace(LikesLinearLayout likesLinearLayout) { 65 | Space space = new Space(getContext()); 66 | ViewGroup.LayoutParams params = new ViewGroup.LayoutParams((int) (getResources().getDisplayMetrics().density * 24), 67 | ViewGroup.LayoutParams.MATCH_PARENT); 68 | space.setLayoutParams(params); 69 | likesLinearLayout.addView(space); 70 | } 71 | 72 | private void addFavoriteButton(LikesLinearLayout likesLinearLayout) { 73 | ImageButton button = new ImageButton(getContext(), null, R.style.LikeButton_Favorite); 74 | button.setId(R.id.btn_favorite); 75 | button.setImageResource(R.drawable.ic_favorite); 76 | DrawableCompat.setTint(button.getDrawable(), ContextCompat.getColor(getContext(), R.color.colorAccent)); 77 | final ViewGroup.LayoutParams params = likesLinearLayout 78 | .newLayoutParamsBuilder(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) 79 | .setDrawable(ContextCompat.getDrawable(getContext(), R.drawable.ic_favorite_normal)) 80 | .setAnimationDuration(1000) 81 | .setProduceInterval(500) 82 | .setDrawableAnimatorFactory(new CustomDrawableAnimatorFactory()) 83 | .setLikesMode(LikesAttributes.LIKES_MODE_ENABLED) 84 | .build(); 85 | button.setLayoutParams(params); 86 | likesLinearLayout.addView(button); 87 | } 88 | 89 | private void addGradeButton(LikesLinearLayout likesLinearLayout) { 90 | ImageButton button = new ImageButton(getContext(), null, R.style.LikeButton_Grade); 91 | button.setId(R.id.btn_grade); 92 | button.setImageResource(R.drawable.ic_grade); 93 | DrawableCompat.setTint(button.getDrawable(), ContextCompat.getColor(getContext(), R.color.colorAccent)); 94 | final ViewGroup.LayoutParams params = likesLinearLayout 95 | .newLayoutParamsBuilder(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) 96 | .setDrawable(ContextCompat.getDrawable(getContext(), R.drawable.ic_grade_normal)) 97 | .setAnimationDuration(3000) 98 | .setProduceInterval(500) 99 | .setPositionAnimatorFactory(new CustomPositionAnimatorFactory2()) 100 | .setLikesMode(LikesAttributes.LIKES_MODE_ENABLED) 101 | .build(); 102 | button.setLayoutParams(params); 103 | likesLinearLayout.addView(button); 104 | } 105 | 106 | private void addStarsButton(LikesLinearLayout likesLinearLayout) { 107 | ImageButton button = new ImageButton(getContext(), null, R.style.LikeButton_Stars); 108 | button.setId(R.id.btn_stars); 109 | button.setImageResource(R.drawable.ic_stars); 110 | DrawableCompat.setTint(button.getDrawable(), ContextCompat.getColor(getContext(), R.color.colorAccent)); 111 | final ViewGroup.LayoutParams params = likesLinearLayout 112 | .newLayoutParamsBuilder(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) 113 | .setDrawable(ContextCompat.getDrawable(getContext(), R.drawable.ic_stars_colored)) 114 | .setAnimationDuration(1600) 115 | .setProduceInterval(200) 116 | .setPositionAnimatorFactory(new CustomPositionAnimatorFactory()) 117 | .setTintMode(LikesAttributes.TINT_MODE_OFF) 118 | .setDrawableWidth(getResources().getDisplayMetrics().density * 32) 119 | .setDrawableHeight(getResources().getDisplayMetrics().density * 32) 120 | .setLikesMode(LikesAttributes.LIKES_MODE_ENABLED) 121 | .build(); 122 | button.setLayoutParams(params); 123 | likesLinearLayout.addView(button); 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/iojjj/likeslayout/app/FromXmlFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.iojjj.likeslayout.app; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageButton; 9 | 10 | import java.util.concurrent.TimeUnit; 11 | 12 | import butterknife.BindView; 13 | import butterknife.OnClick; 14 | 15 | /** 16 | * Fragment that inflates LikesLayout from XML. 17 | */ 18 | public class FromXmlFragment extends BaseFragment { 19 | 20 | @BindView(R.id.btn_favorite) 21 | ImageButton mBtnFavorite; 22 | 23 | @BindView(R.id.btn_grade) 24 | ImageButton mBtnGrade; 25 | 26 | @BindView(R.id.btn_stars) 27 | ImageButton mBtnStars; 28 | 29 | public static FromXmlFragment newInstance() { 30 | Bundle args = new Bundle(); 31 | FromXmlFragment fragment = new FromXmlFragment(); 32 | fragment.setArguments(args); 33 | return fragment; 34 | } 35 | 36 | @Nullable 37 | @Override 38 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 39 | return inflater.inflate(R.layout.fragment_main, container, false); 40 | } 41 | 42 | @OnClick(R.id.btn_produce) 43 | void onProduceLikesClicked() { 44 | mLikesLayout.produceLikes(mBtnFavorite, 3, TimeUnit.SECONDS); 45 | mLikesLayout.produceLikes(mBtnGrade, 3, TimeUnit.SECONDS); 46 | mLikesLayout.produceLikes(mBtnStars, 3, TimeUnit.SECONDS); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/iojjj/likeslayout/app/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.iojjj.likeslayout.app; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | 7 | public class MainActivity extends AppCompatActivity { 8 | 9 | @Override 10 | protected void onCreate(@Nullable Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | setContentView(R.layout.activity_main); 13 | if (savedInstanceState == null) { 14 | getSupportFragmentManager().beginTransaction() 15 | .add(R.id.container, ChooseFragment.newInstance()) 16 | .commit(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_favorite_normal.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_favorite_pressed.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_grade_normal.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_grade_pressed.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_stars_colored.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_stars_normal.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_stars_pressed.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_favorite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_grade.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_stars.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_code.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 |