├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── libraries │ ├── appcompat_v7_22_2_1.xml │ ├── support_annotations_22_2_1.xml │ └── support_v4_22_2_1.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml ├── vcs.xml └── workspace.xml ├── AnimView.iml ├── LICENSE ├── MetaballLoading.iml ├── README.md ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── dodola │ │ └── animview │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── dodola │ │ └── animview │ │ ├── MainActivity.java │ │ ├── MetaballDebugView.java │ │ └── MetaballView.java │ └── res │ ├── layout │ └── activity_main.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── metaball.gif ├── metaball2.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | /*/build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | MetaballLoading -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/libraries/appcompat_v7_22_2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/libraries/support_annotations_22_2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/support_v4_22_2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 183 | 1279 | 1284 | 1581 | 1584 | 1585 | 1586 | 1596 | 1597 | 1598 | 1603 | 1604 | 1605 | 1606 | 1607 | 1608 | 1612 | 1613 | 1614 | 1615 | 1616 | 1617 | 1618 | 1619 | 1620 | 1621 | 1622 | 1623 | 1624 | 1625 | 1626 | 1627 | 1628 | 1629 | 1630 | 1631 | 1632 | 1633 | 1634 | 1635 | 1636 | 1637 | 1638 | 1639 | 1640 | 1641 | 1642 | 1643 | 1646 | 1647 | 1650 | 1651 | 1652 | 1653 | 1656 | 1657 | 1660 | 1661 | 1662 | 1663 | 1664 | 1665 | 1666 | 1667 | 1668 | 1669 | 1670 | 1671 | 1672 | 1673 | 1674 | 1675 | 1676 | 1677 | 1678 | 1679 | 1680 | 1681 | 1682 | 1683 | 1684 | 1685 | 1686 | 1687 | 1688 | 1689 | 1690 | 1691 | 1692 | 1693 | 1720 | 1721 | 1722 | 1750 | 1751 | 1752 | 1765 | 1766 | 1767 | 1768 | 1782 | 1783 | 1784 | 1785 | 1786 | 1787 | 1788 | 1789 | 1790 | 1791 | 1792 | 1799 | 1800 | 1801 | 1802 | 1820 | 1827 | 1828 | 1829 | 1856 | 1857 | 1858 | 1859 | 1860 | 1868 | 1869 | 1871 | 1872 | localhost 1873 | 5050 1874 | 1875 | 1876 | 1877 | 1878 | 1879 | 1880 | 1881 | 1882 | 1883 | 1438666338830 1884 | 1887 | 1888 | 1889 | 1890 | 1891 | 1892 | 1893 | 1894 | 1895 | 1896 | 1897 | 1898 | 1899 | 1900 | 1901 | 1902 | 1903 | 1904 | 1905 | 1906 | 1907 | 1908 | 1909 | 1910 | 1911 | 1912 | 1913 | 1914 | 1915 | 1916 | 1917 | 1918 | 1919 | 1920 | 1921 | 1922 | 1923 | 1926 | 1929 | 1930 | 1931 | 1933 | 1934 | 1935 | 1936 | 1937 | 1938 | 1939 | 1940 | 1941 | 1942 | 1943 | 1944 | 1945 | 1946 | 1947 | 1948 | 1949 | 1950 | 1951 | 1952 | 1953 | 1954 | 1955 | 1956 | 1957 | 1958 | 1959 | 1960 | 1961 | 1962 | 1963 | 1964 | 1965 | 1966 | 1967 | 1968 | 1969 | 1970 | 1971 | 1972 | 1973 | 1974 | 1975 | 1976 | 1977 | 1978 | 1979 | 1980 | 1981 | 1982 | 1983 | 1984 | 1985 | 1986 | 1987 | 1988 | 1989 | 1990 | 1991 | 1992 | 1993 | 1994 | 1995 | 1996 | 1997 | 1998 | 1999 | 2000 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 | 2027 | 2028 | 2029 | 2030 | 2031 | 2032 | 2033 | 2034 | 2035 | 2036 | 2037 | 2038 | 2039 | 2040 | 2041 | 2042 | 2043 | 2044 | 2045 | 2046 | 2047 | 2048 | 2049 | 2050 | 2051 | 2052 | 2053 | 2054 | 2055 | 2056 | 2057 | 2058 | 2059 | 2060 | 2061 | 2062 | 2063 | 2064 | 2065 | 2066 | 2067 | 2068 | 2069 | 2070 | 2071 | 2072 | 2073 | 2074 | 2075 | 2076 | 2077 | 2078 | 2079 | 2080 | 2081 | 2082 | 2083 | 2084 | 2085 | 2086 | 2087 | 2088 | 2089 | 2090 | 2091 | 2092 | 2093 | 2094 | 2095 | 2096 | 2097 | 2098 | 2099 | 2100 | 2101 | 2102 | 2103 | 2104 | 2105 | 2106 | 2107 | 2108 | 2109 | 2110 | 2111 | 2112 | 2113 | 2114 | 2115 | 2116 | 2117 | 2118 | 2119 | 2120 | 2121 | 2122 | 2123 | 2124 | 2125 | 2126 | 2127 | 2128 | 2129 | 2130 | 2131 | 2132 | 2133 | 2134 | 2135 | 2136 | 2137 | 2138 | 2139 | -------------------------------------------------------------------------------- /AnimView.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 dodola 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /MetaballLoading.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MetaballLoading 2 | A 2d metaball loading 3 | 4 | ---------- 5 | 6 | ##ScreenShot 7 | 8 | 9 | ![GIF example](metaball.gif) 10 | 11 | ##Update 12 | 13 | ###1. 增加了调试模式,可以调整参数看看对图形的影响 14 | 15 | ![GIF example](metaball2.gif) 16 | 17 | 18 | 19 | License 20 | -------- 21 | 22 | The MIT License (MIT) 23 | 24 | Copyright (c) 2015 dodola 25 | 26 | Permission is hereby granted, free of charge, to any person obtaining a copy 27 | of this software and associated documentation files (the "Software"), to deal 28 | in the Software without restriction, including without limitation the rights 29 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 30 | copies of the Software, and to permit persons to whom the Software is 31 | furnished to do so, subject to the following conditions: 32 | 33 | The above copyright notice and this permission notice shall be included in all 34 | copies or substantial portions of the Software. 35 | 36 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 37 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 38 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 39 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 40 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 41 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 42 | SOFTWARE. 43 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.dodola.animview" 9 | minSdkVersion 14 10 | targetSdkVersion 22 11 | versionCode 2 12 | versionName "1.1" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:22.2.1' 25 | } 26 | -------------------------------------------------------------------------------- /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 /Users/dodola/Library/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/dodola/animview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.dodola.animview; 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 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/dodola/animview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.dodola.animview; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.view.Menu; 6 | import android.view.MenuItem; 7 | import android.widget.ProgressBar; 8 | import android.widget.SeekBar; 9 | 10 | public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener { 11 | 12 | private MetaballView metaballView; 13 | private MetaballDebugView debugMetaballView; 14 | private SeekBar seekBar, seekBar2, seekBar3; 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main); 20 | metaballView = (MetaballView) this.findViewById(R.id.metaball); 21 | debugMetaballView = (MetaballDebugView) findViewById(R.id.debug_metaball); 22 | seekBar = (SeekBar) findViewById(R.id.seekBar); 23 | seekBar2 = (SeekBar) findViewById(R.id.seekBar2); 24 | seekBar3 = (SeekBar) findViewById(R.id.seekBar3); 25 | seekBar.setOnSeekBarChangeListener(this); 26 | seekBar2.setOnSeekBarChangeListener(this); 27 | seekBar3.setOnSeekBarChangeListener(this); 28 | 29 | } 30 | 31 | @Override 32 | public boolean onCreateOptionsMenu(Menu menu) { 33 | // Inflate the menu; this adds items to the action bar if it is present. 34 | getMenuInflater().inflate(R.menu.menu_main, menu); 35 | return true; 36 | } 37 | 38 | @Override 39 | public boolean onOptionsItemSelected(MenuItem item) { 40 | // Handle action bar item clicks here. The action bar will 41 | // automatically handle clicks on the Home/Up button, so long 42 | // as you specify a parent activity in AndroidManifest.xml. 43 | int id = item.getItemId(); 44 | 45 | //noinspection SimplifiableIfStatement 46 | if (id == R.id.action_fill) { 47 | metaballView.setPaintMode(1); 48 | debugMetaballView.setPaintMode(1); 49 | return true; 50 | } else if (id == R.id.action_strock) { 51 | metaballView.setPaintMode(0); 52 | debugMetaballView.setPaintMode(0); 53 | return true; 54 | } 55 | 56 | return super.onOptionsItemSelected(item); 57 | } 58 | 59 | @Override 60 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 61 | switch (seekBar.getId()) { 62 | case R.id.seekBar: 63 | debugMetaballView.setMaxDistance(progress); 64 | break; 65 | case R.id.seekBar2: 66 | debugMetaballView.setMv(progress / 100f); 67 | break; 68 | case R.id.seekBar3: 69 | debugMetaballView.setHandleLenRate(progress / 100f); 70 | break; 71 | } 72 | 73 | } 74 | 75 | @Override 76 | public void onStartTrackingTouch(SeekBar seekBar) { 77 | 78 | } 79 | 80 | @Override 81 | public void onStopTrackingTouch(SeekBar seekBar) { 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/dodola/animview/MetaballDebugView.java: -------------------------------------------------------------------------------- 1 | package com.dodola.animview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.Path; 7 | import android.graphics.RectF; 8 | import android.util.AttributeSet; 9 | import android.util.Log; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | import android.view.animation.AccelerateDecelerateInterpolator; 13 | import android.view.animation.Animation; 14 | import android.view.animation.Transformation; 15 | 16 | import java.util.ArrayList; 17 | import java.util.Arrays; 18 | 19 | /** 20 | * Created by dodola on 15/7/27. 21 | */ 22 | public class MetaballDebugView extends View { 23 | 24 | private Paint paint = new Paint(); 25 | 26 | 27 | private float handleLenRate = 2f; 28 | private final float radius = 60; 29 | private final float SCALE_RATE = 0.3f; 30 | private ArrayList circlePaths = new ArrayList<>(); 31 | private float mv = 0.6f; 32 | private float maxDistance = radius * 4; 33 | 34 | public MetaballDebugView(Context context) { 35 | super(context); 36 | init(); 37 | } 38 | 39 | public MetaballDebugView(Context context, AttributeSet attrs) { 40 | super(context, attrs); 41 | init(); 42 | } 43 | 44 | public MetaballDebugView(Context context, AttributeSet attrs, int defStyleAttr) { 45 | super(context, attrs, defStyleAttr); 46 | init(); 47 | 48 | } 49 | 50 | public float getMv() { 51 | return mv; 52 | } 53 | 54 | public void setMv(float mv) { 55 | this.mv = mv; 56 | invalidate(); 57 | } 58 | 59 | public float getMaxDistance() { 60 | return maxDistance; 61 | } 62 | 63 | public void setMaxDistance(float maxDistance) { 64 | this.maxDistance = maxDistance; 65 | invalidate(); 66 | } 67 | 68 | public float getHandleLenRate() { 69 | return handleLenRate; 70 | } 71 | 72 | public void setHandleLenRate(float handleLenRate) { 73 | this.handleLenRate = handleLenRate; 74 | invalidate(); 75 | } 76 | 77 | private class Circle { 78 | float[] center; 79 | float radius; 80 | } 81 | 82 | public void setPaintMode(int mode) { 83 | paint.setStyle(mode == 0 ? Paint.Style.STROKE : Paint.Style.FILL); 84 | invalidate(); 85 | } 86 | 87 | private void init() { 88 | paint.setColor(0xff4db9ff); 89 | paint.setStyle(Paint.Style.FILL); 90 | paint.setAntiAlias(true); 91 | 92 | } 93 | 94 | private void initMetaballs() { 95 | Circle circlePath = new Circle(); 96 | circlePath.center = new float[]{(radius), radius}; 97 | circlePath.radius = radius; 98 | circlePaths.add(circlePath); 99 | 100 | circlePath = new Circle(); 101 | circlePath.center = new float[]{this.getMeasuredWidth() / 2, this.getMeasuredHeight() / 3}; 102 | circlePath.radius = radius; 103 | circlePaths.add(circlePath); 104 | } 105 | 106 | private float[] getVector(float radians, float length) { 107 | float x = (float) (Math.cos(radians) * length); 108 | float y = (float) (Math.sin(radians) * length); 109 | return new float[]{ 110 | x, y 111 | }; 112 | } 113 | 114 | /** 115 | * @param canvas 画布 116 | * @param j 117 | * @param i 118 | * @param v 控制两个圆连接时候长度,间接控制连接线的粗细,该值为1的时候连接线为直线 119 | * @param handle_len_rate 120 | * @param maxDistance 121 | */ 122 | private void metaball(Canvas canvas, int j, int i, float v, float handle_len_rate, float maxDistance) { 123 | final Circle circle1 = circlePaths.get(i); 124 | final Circle circle2 = circlePaths.get(j); 125 | 126 | RectF ball1 = new RectF(); 127 | ball1.left = circle1.center[0] - circle1.radius; 128 | ball1.top = circle1.center[1] - circle1.radius; 129 | ball1.right = ball1.left + circle1.radius * 2; 130 | ball1.bottom = ball1.top + circle1.radius * 2; 131 | 132 | RectF ball2 = new RectF(); 133 | ball2.left = circle2.center[0] - circle2.radius; 134 | ball2.top = circle2.center[1] - circle2.radius; 135 | ball2.right = ball2.left + circle2.radius * 2; 136 | ball2.bottom = ball2.top + circle2.radius * 2; 137 | 138 | float[] center1 = new float[]{ 139 | ball1.centerX(), 140 | ball1.centerY() 141 | }; 142 | float[] center2 = new float[]{ 143 | ball2.centerX(), 144 | ball2.centerY() 145 | }; 146 | float d = getDistance(center1, center2); 147 | 148 | float radius1 = ball1.width() / 2; 149 | float radius2 = ball2.width() / 2; 150 | float pi2 = (float) (Math.PI / 2); 151 | float u1, u2; 152 | 153 | 154 | if (d > maxDistance) { 155 | canvas.drawCircle(ball2.centerX(), ball2.centerY(), circle2.radius, paint); 156 | } else { 157 | float scale2 = 1 + SCALE_RATE * (1 - d / maxDistance); 158 | radius2 *= scale2; 159 | canvas.drawCircle(ball2.centerX(), ball2.centerY(), radius2, paint); 160 | } 161 | 162 | Log.d("Metaball_radius", "radius1:" + radius1 + ",radius2:" + radius2); 163 | if (radius1 == 0 || radius2 == 0) { 164 | return; 165 | } 166 | 167 | if (d > maxDistance || d <= Math.abs(radius1 - radius2)) { 168 | return; 169 | } else if (d < radius1 + radius2) { 170 | u1 = (float) Math.acos((radius1 * radius1 + d * d - radius2 * radius2) / 171 | (2 * radius1 * d)); 172 | u2 = (float) Math.acos((radius2 * radius2 + d * d - radius1 * radius1) / 173 | (2 * radius2 * d)); 174 | } else { 175 | u1 = 0; 176 | u2 = 0; 177 | } 178 | Log.d("Metaball", "center2:" + Arrays.toString(center2) + ",center1:" + Arrays.toString(center1)); 179 | float[] centermin = new float[]{center2[0] - center1[0], center2[1] - center1[1]}; 180 | 181 | float angle1 = (float) Math.atan2(centermin[1], centermin[0]); 182 | float angle2 = (float) Math.acos((radius1 - radius2) / d); 183 | float angle1a = angle1 + u1 + (angle2 - u1) * v; 184 | float angle1b = angle1 - u1 - (angle2 - u1) * v; 185 | float angle2a = (float) (angle1 + Math.PI - u2 - (Math.PI - u2 - angle2) * v); 186 | float angle2b = (float) (angle1 - Math.PI + u2 + (Math.PI - u2 - angle2) * v); 187 | 188 | Log.d("Metaball", "angle1:" + angle1 + ",angle2:" + angle2 + ",angle1a:" + angle1a + ",angle1b:" + angle1b + ",angle2a:" + angle2a + ",angle2b:" + angle2b); 189 | 190 | 191 | float[] p1a1 = getVector(angle1a, radius1); 192 | float[] p1b1 = getVector(angle1b, radius1); 193 | float[] p2a1 = getVector(angle2a, radius2); 194 | float[] p2b1 = getVector(angle2b, radius2); 195 | 196 | float[] p1a = new float[]{p1a1[0] + center1[0], p1a1[1] + center1[1]}; 197 | float[] p1b = new float[]{p1b1[0] + center1[0], p1b1[1] + center1[1]}; 198 | float[] p2a = new float[]{p2a1[0] + center2[0], p2a1[1] + center2[1]}; 199 | float[] p2b = new float[]{p2b1[0] + center2[0], p2b1[1] + center2[1]}; 200 | 201 | 202 | Log.d("Metaball", "p1a:" + Arrays.toString(p1a) + ",p1b:" + Arrays.toString(p1b) + ",p2a:" + Arrays.toString(p2a) + ",p2b:" + Arrays.toString(p2b)); 203 | 204 | float[] p1_p2 = new float[]{p1a[0] - p2a[0], p1a[1] - p2a[1]}; 205 | 206 | float totalRadius = (radius1 + radius2); 207 | float d2 = Math.min(v * handle_len_rate, getLength(p1_p2) / totalRadius); 208 | d2 *= Math.min(1, d * 2 / (radius1 + radius2)); 209 | Log.d("Metaball", "d2:" + d2); 210 | radius1 *= d2; 211 | radius2 *= d2; 212 | 213 | float[] sp1 = getVector(angle1a - pi2, radius1); 214 | float[] sp2 = getVector(angle2a + pi2, radius2); 215 | float[] sp3 = getVector(angle2b - pi2, radius2); 216 | float[] sp4 = getVector(angle1b + pi2, radius1); 217 | Log.d("Metaball", "sp1:" + Arrays.toString(sp1) + ",sp2:" + Arrays.toString(sp2) + ",sp3:" + Arrays.toString(sp3) + ",sp4:" + Arrays.toString(sp4)); 218 | 219 | 220 | Path path1 = new Path(); 221 | path1.moveTo(p1a[0], p1a[1]); 222 | path1.cubicTo(p1a[0] + sp1[0], p1a[1] + sp1[1], p2a[0] + sp2[0], p2a[1] + sp2[1], p2a[0], p2a[1]); 223 | path1.lineTo(p2b[0], p2b[1]); 224 | path1.cubicTo(p2b[0] + sp3[0], p2b[1] + sp3[1], p1b[0] + sp4[0], p1b[1] + sp4[1], p1b[0], p1b[1]); 225 | path1.lineTo(p1a[0], p1a[1]); 226 | path1.close(); 227 | canvas.drawPath(path1, paint); 228 | 229 | } 230 | 231 | private float getLength(float[] b) { 232 | return (float) Math.sqrt(b[0] * b[0] + b[1] * b[1]); 233 | } 234 | 235 | private float getDistance(float[] b1, float[] b2) { 236 | float x = b1[0] - b2[0]; 237 | float y = b1[1] - b2[1]; 238 | float d = x * x + y * y; 239 | return (float) Math.sqrt(d); 240 | } 241 | 242 | 243 | //测试用 244 | @Override 245 | public boolean onTouchEvent(MotionEvent event) { 246 | Circle circle = circlePaths.get(0); 247 | circle.center[0] = event.getX(); 248 | circle.center[1] = event.getY(); 249 | invalidate(); 250 | return true; 251 | } 252 | 253 | @Override 254 | protected void onDraw(Canvas canvas) { 255 | super.onDraw(canvas); 256 | if (circlePaths.size() == 0) { 257 | initMetaballs(); 258 | } 259 | 260 | 261 | final Circle circle1 = circlePaths.get(0); 262 | RectF ball1 = new RectF(); 263 | ball1.left = circle1.center[0] - circle1.radius; 264 | ball1.top = circle1.center[1] - circle1.radius; 265 | ball1.right = ball1.left + circle1.radius * 2; 266 | ball1.bottom = ball1.top + circle1.radius * 2; 267 | canvas.drawCircle(ball1.centerX(), ball1.centerY(), circle1.radius, paint); 268 | 269 | for (int i = 1; i < circlePaths.size(); i++) { 270 | metaball(canvas, i, 0, mv, handleLenRate, maxDistance); 271 | } 272 | } 273 | 274 | } 275 | -------------------------------------------------------------------------------- /app/src/main/java/com/dodola/animview/MetaballView.java: -------------------------------------------------------------------------------- 1 | package com.dodola.animview; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.LightingColorFilter; 8 | import android.graphics.Paint; 9 | import android.graphics.Path; 10 | import android.graphics.RectF; 11 | import android.os.Build; 12 | import android.util.AttributeSet; 13 | import android.util.Log; 14 | import android.view.MotionEvent; 15 | import android.view.View; 16 | import android.view.animation.AccelerateDecelerateInterpolator; 17 | import android.view.animation.Animation; 18 | import android.view.animation.Transformation; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Arrays; 22 | import java.util.Random; 23 | 24 | /** 25 | * Created by dodola on 15/7/27. 26 | */ 27 | public class MetaballView extends View { 28 | 29 | private Paint paint = new Paint(); 30 | private float handle_len_rate = 2f; 31 | private float radius = 30; 32 | private final int ITEM_COUNT = 6; 33 | private final int ITEM_DIVIDER = 60; 34 | private final float SCALE_RATE = 0.3f; 35 | private float maxLength; 36 | private ArrayList circlePaths = new ArrayList<>(); 37 | private float mInterpolatedTime; 38 | private MoveAnimation wa; 39 | private Circle circle; 40 | 41 | public MetaballView(Context context) { 42 | super(context); 43 | init(); 44 | } 45 | 46 | public MetaballView(Context context, AttributeSet attrs) { 47 | super(context, attrs); 48 | init(); 49 | } 50 | 51 | public MetaballView(Context context, AttributeSet attrs, int defStyleAttr) { 52 | super(context, attrs, defStyleAttr); 53 | init(); 54 | 55 | } 56 | 57 | private class Circle { 58 | float[] center; 59 | float radius; 60 | } 61 | 62 | public void setPaintMode(int mode) { 63 | paint.setStyle(mode == 0 ? Paint.Style.STROKE : Paint.Style.FILL); 64 | invalidate(); 65 | } 66 | 67 | private void init() { 68 | paint.setColor(0xff4db9ff); 69 | paint.setStyle(Paint.Style.FILL); 70 | paint.setAntiAlias(true); 71 | Circle circlePath = new Circle(); 72 | circlePath.center = new float[]{(radius + ITEM_DIVIDER), radius * (1f + SCALE_RATE)}; 73 | circlePath.radius = radius / 4 * 3; 74 | circlePaths.add(circlePath); 75 | 76 | for (int i = 1; i < ITEM_COUNT; i++) { 77 | circlePath = new Circle(); 78 | circlePath.center = new float[]{(radius * 2 + ITEM_DIVIDER) * i, radius * (1f + SCALE_RATE)}; 79 | circlePath.radius = radius; 80 | circlePaths.add(circlePath); 81 | } 82 | maxLength = (radius * 2 + ITEM_DIVIDER) * ITEM_COUNT; 83 | } 84 | 85 | private float[] getVector(float radians, float length) { 86 | float x = (float) (Math.cos(radians) * length); 87 | float y = (float) (Math.sin(radians) * length); 88 | return new float[]{ 89 | x, y 90 | }; 91 | } 92 | 93 | private class MoveAnimation extends Animation { 94 | 95 | @Override 96 | protected void applyTransformation(float interpolatedTime, Transformation t) { 97 | super.applyTransformation(interpolatedTime, t); 98 | mInterpolatedTime = interpolatedTime; 99 | invalidate(); 100 | } 101 | } 102 | 103 | /** 104 | * @param canvas 画布 105 | * @param j 106 | * @param i 107 | * @param v 控制两个圆连接时候长度,间接控制连接线的粗细,该值为1的时候连接线为直线 108 | * @param handle_len_rate 109 | * @param maxDistance 110 | */ 111 | private void metaball(Canvas canvas, int j, int i, float v, float handle_len_rate, float maxDistance) { 112 | final Circle circle1 = circlePaths.get(i); 113 | final Circle circle2 = circlePaths.get(j); 114 | 115 | RectF ball1 = new RectF(); 116 | ball1.left = circle1.center[0] - circle1.radius; 117 | ball1.top = circle1.center[1] - circle1.radius; 118 | ball1.right = ball1.left + circle1.radius * 2; 119 | ball1.bottom = ball1.top + circle1.radius * 2; 120 | 121 | RectF ball2 = new RectF(); 122 | ball2.left = circle2.center[0] - circle2.radius; 123 | ball2.top = circle2.center[1] - circle2.radius; 124 | ball2.right = ball2.left + circle2.radius * 2; 125 | ball2.bottom = ball2.top + circle2.radius * 2; 126 | 127 | float[] center1 = new float[]{ 128 | ball1.centerX(), 129 | ball1.centerY() 130 | }; 131 | float[] center2 = new float[]{ 132 | ball2.centerX(), 133 | ball2.centerY() 134 | }; 135 | float d = getDistance(center1, center2); 136 | 137 | float radius1 = ball1.width() / 2; 138 | float radius2 = ball2.width() / 2; 139 | float pi2 = (float) (Math.PI / 2); 140 | float u1, u2; 141 | 142 | 143 | if (d > maxDistance) { 144 | // canvas.drawCircle(ball1.centerX(), ball1.centerY(), circle1.radius, paint); 145 | canvas.drawCircle(ball2.centerX(), ball2.centerY(), circle2.radius, paint); 146 | } else { 147 | float scale2 = 1 + SCALE_RATE * (1 - d / maxDistance); 148 | float scale1 = 1 - SCALE_RATE * (1 - d / maxDistance); 149 | radius2 *= scale2; 150 | // radius1 *= scale1; 151 | // canvas.drawCircle(ball1.centerX(), ball1.centerY(), radius1, paint); 152 | canvas.drawCircle(ball2.centerX(), ball2.centerY(), radius2, paint); 153 | 154 | } 155 | 156 | // Log.d("Metaball_radius", "radius1:" + radius1 + ",radius2:" + radius2); 157 | if (radius1 == 0 || radius2 == 0) { 158 | return; 159 | } 160 | 161 | if (d > maxDistance || d <= Math.abs(radius1 - radius2)) { 162 | return; 163 | } else if (d < radius1 + radius2) { 164 | u1 = (float) Math.acos((radius1 * radius1 + d * d - radius2 * radius2) / 165 | (2 * radius1 * d)); 166 | u2 = (float) Math.acos((radius2 * radius2 + d * d - radius1 * radius1) / 167 | (2 * radius2 * d)); 168 | } else { 169 | u1 = 0; 170 | u2 = 0; 171 | } 172 | // Log.d("Metaball", "center2:" + Arrays.toString(center2) + ",center1:" + Arrays.toString(center1)); 173 | float[] centermin = new float[]{center2[0] - center1[0], center2[1] - center1[1]}; 174 | 175 | float angle1 = (float) Math.atan2(centermin[1], centermin[0]); 176 | float angle2 = (float) Math.acos((radius1 - radius2) / d); 177 | float angle1a = angle1 + u1 + (angle2 - u1) * v; 178 | float angle1b = angle1 - u1 - (angle2 - u1) * v; 179 | float angle2a = (float) (angle1 + Math.PI - u2 - (Math.PI - u2 - angle2) * v); 180 | float angle2b = (float) (angle1 - Math.PI + u2 + (Math.PI - u2 - angle2) * v); 181 | 182 | // Log.d("Metaball", "angle1:" + angle1 + ",angle2:" + angle2 + ",angle1a:" + angle1a + ",angle1b:" + angle1b + ",angle2a:" + angle2a + ",angle2b:" + angle2b); 183 | 184 | 185 | float[] p1a1 = getVector(angle1a, radius1); 186 | float[] p1b1 = getVector(angle1b, radius1); 187 | float[] p2a1 = getVector(angle2a, radius2); 188 | float[] p2b1 = getVector(angle2b, radius2); 189 | 190 | float[] p1a = new float[]{p1a1[0] + center1[0], p1a1[1] + center1[1]}; 191 | float[] p1b = new float[]{p1b1[0] + center1[0], p1b1[1] + center1[1]}; 192 | float[] p2a = new float[]{p2a1[0] + center2[0], p2a1[1] + center2[1]}; 193 | float[] p2b = new float[]{p2b1[0] + center2[0], p2b1[1] + center2[1]}; 194 | 195 | 196 | // Log.d("Metaball", "p1a:" + Arrays.toString(p1a) + ",p1b:" + Arrays.toString(p1b) + ",p2a:" + Arrays.toString(p2a) + ",p2b:" + Arrays.toString(p2b)); 197 | 198 | float[] p1_p2 = new float[]{p1a[0] - p2a[0], p1a[1] - p2a[1]}; 199 | 200 | float totalRadius = (radius1 + radius2); 201 | float d2 = Math.min(v * handle_len_rate, getLength(p1_p2) / totalRadius); 202 | d2 *= Math.min(1, d * 2 / (radius1 + radius2)); 203 | // Log.d("Metaball", "d2:" + d2); 204 | radius1 *= d2; 205 | radius2 *= d2; 206 | 207 | float[] sp1 = getVector(angle1a - pi2, radius1); 208 | float[] sp2 = getVector(angle2a + pi2, radius2); 209 | float[] sp3 = getVector(angle2b - pi2, radius2); 210 | float[] sp4 = getVector(angle1b + pi2, radius1); 211 | // Log.d("Metaball", "sp1:" + Arrays.toString(sp1) + ",sp2:" + Arrays.toString(sp2) + ",sp3:" + Arrays.toString(sp3) + ",sp4:" + Arrays.toString(sp4)); 212 | 213 | 214 | Path path1 = new Path(); 215 | path1.moveTo(p1a[0], p1a[1]); 216 | path1.cubicTo(p1a[0] + sp1[0], p1a[1] + sp1[1], p2a[0] + sp2[0], p2a[1] + sp2[1], p2a[0], p2a[1]); 217 | path1.lineTo(p2b[0], p2b[1]); 218 | path1.cubicTo(p2b[0] + sp3[0], p2b[1] + sp3[1], p1b[0] + sp4[0], p1b[1] + sp4[1], p1b[0], p1b[1]); 219 | path1.lineTo(p1a[0], p1a[1]); 220 | path1.close(); 221 | canvas.drawPath(path1, paint); 222 | 223 | } 224 | 225 | private float getLength(float[] b) { 226 | return (float) Math.sqrt(b[0] * b[0] + b[1] * b[1]); 227 | } 228 | 229 | private float getDistance(float[] b1, float[] b2) { 230 | float x = b1[0] - b2[0]; 231 | float y = b1[1] - b2[1]; 232 | float d = x * x + y * y; 233 | return (float) Math.sqrt(d); 234 | } 235 | 236 | 237 | //测试用 238 | // @Override 239 | // public boolean onTouchEvent(MotionEvent event) { 240 | // switch (event.getAction()) { 241 | // case MotionEvent.ACTION_DOWN: 242 | // break; 243 | // case MotionEvent.ACTION_MOVE: 244 | // Circle circle = circlePaths.get(0); 245 | // circle.center[0] = event.getX(); 246 | // circle.center[1] = event.getY(); 247 | // invalidate(); 248 | // break; 249 | // case MotionEvent.ACTION_UP: 250 | // break; 251 | // } 252 | // 253 | // return true; 254 | // } 255 | 256 | @Override 257 | protected void onDraw(Canvas canvas) { 258 | super.onDraw(canvas); 259 | circle = circlePaths.get(0); 260 | circle.center[0] = maxLength * mInterpolatedTime; 261 | 262 | RectF ball1 = new RectF(); 263 | ball1.left = circle.center[0] - circle.radius; 264 | ball1.top = circle.center[1] - circle.radius; 265 | ball1.right = ball1.left + circle.radius * 2; 266 | ball1.bottom = ball1.top + circle.radius * 2; 267 | canvas.drawCircle(ball1.centerX(), ball1.centerY(), circle.radius, paint); 268 | 269 | 270 | for (int i = 1, l = circlePaths.size(); i < l; i++) { 271 | metaball(canvas, i, 0, 0.6f, handle_len_rate, radius * 4f); 272 | } 273 | } 274 | 275 | @Override 276 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 277 | setMeasuredDimension(resolveSizeAndState((int) (ITEM_COUNT * (radius * 2 + ITEM_DIVIDER)), widthMeasureSpec, 0), 278 | resolveSizeAndState((int) (2 * radius * 1.4f), heightMeasureSpec, 0)); 279 | } 280 | 281 | 282 | private void stopAnimation() { 283 | this.clearAnimation(); 284 | postInvalidate(); 285 | } 286 | 287 | private void startAnimation() { 288 | wa = new MoveAnimation(); 289 | wa.setDuration(2500); 290 | wa.setInterpolator(new AccelerateDecelerateInterpolator()); 291 | wa.setRepeatCount(Animation.INFINITE); 292 | wa.setRepeatMode(Animation.REVERSE); 293 | startAnimation(wa); 294 | } 295 | 296 | @Override 297 | protected void onVisibilityChanged(View changedView, int visibility) { 298 | super.onVisibilityChanged(changedView, visibility); 299 | 300 | if (visibility == GONE || visibility == INVISIBLE) { 301 | stopAnimation(); 302 | } else { 303 | startAnimation(); 304 | } 305 | } 306 | 307 | @Override 308 | protected void onAttachedToWindow() { 309 | super.onAttachedToWindow(); 310 | startAnimation(); 311 | } 312 | 313 | @Override 314 | protected void onDetachedFromWindow() { 315 | stopAnimation(); 316 | super.onDetachedFromWindow(); 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 18 | 19 | 27 | 28 | 37 | 38 | 44 | 45 | 50 | 51 | 57 | 58 | 63 | 64 | 69 | 70 | 75 | 76 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dodola/MetaballLoading/1a68759b22878aba87abd161dcc90b02a6f15f81/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dodola/MetaballLoading/1a68759b22878aba87abd161dcc90b02a6f15f81/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dodola/MetaballLoading/1a68759b22878aba87abd161dcc90b02a6f15f81/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dodola/MetaballLoading/1a68759b22878aba87abd161dcc90b02a6f15f81/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | AnimView 3 | 4 | Hello world! 5 | 边框模式 6 | 填充模式 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.2.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dodola/MetaballLoading/1a68759b22878aba87abd161dcc90b02a6f15f81/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jul 22 17:13:08 CST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /metaball.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dodola/MetaballLoading/1a68759b22878aba87abd161dcc90b02a6f15f81/metaball.gif -------------------------------------------------------------------------------- /metaball2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dodola/MetaballLoading/1a68759b22878aba87abd161dcc90b02a6f15f81/metaball2.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------