├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── markdown-navigator.xml ├── markdown-navigator │ └── profiles_settings.xml ├── misc.xml └── vcs.xml ├── README.md ├── animation_button.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── allen │ │ └── androidcustomview │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── allen │ │ │ └── androidcustomview │ │ │ ├── activity │ │ │ ├── AliPayHomeActivity.java │ │ │ ├── AnimationBtnActivity.java │ │ │ ├── AnimationViewActivity.java │ │ │ ├── BannerActivity.java │ │ │ ├── BubbleViewActivity.java │ │ │ ├── ClearScreenActivity.kt │ │ │ ├── DragBallActivity.java │ │ │ ├── FingerprintActivity.java │ │ │ ├── HoverItemActivity.java │ │ │ ├── MainActivity.kt │ │ │ ├── PathActivity.kt │ │ │ ├── PayPsdViewActivity.java │ │ │ ├── ProgressBarActivity.java │ │ │ ├── RadarActivity.java │ │ │ ├── RecyclerViewItemAnimActivity.kt │ │ │ ├── RevealAnimationActivity.java │ │ │ ├── SinaVoteActivity.kt │ │ │ ├── WaveByBezierActivity.java │ │ │ └── WaveBySinCosActivity.java │ │ │ ├── adapter │ │ │ ├── HoverAdapter.java │ │ │ ├── ItemAnimAdapter.kt │ │ │ └── MainAdapter.java │ │ │ ├── anim │ │ │ ├── BaseItemAnimation.java │ │ │ ├── RotateXItemAnimation.kt │ │ │ ├── RotateYItemAnimation.kt │ │ │ ├── ScaleItemAnimation.kt │ │ │ ├── SlideItemAnimation.kt │ │ │ └── SuperItemAnimation.kt │ │ │ ├── bean │ │ │ ├── CircleBean.java │ │ │ ├── TypeBean.java │ │ │ ├── UserBean.java │ │ │ ├── VoteBean.kt │ │ │ └── WaveBean.java │ │ │ ├── data │ │ │ └── VoteData.kt │ │ │ ├── helper │ │ │ └── DragViewHelper.kt │ │ │ ├── listener │ │ │ └── OnDragTouchListener.kt │ │ │ ├── tagview │ │ │ ├── TagActivity.java │ │ │ ├── TagAdapter.java │ │ │ ├── TagBean.java │ │ │ └── recyclerview.md │ │ │ ├── utils │ │ │ ├── BezierUtil.java │ │ │ ├── CharacterParser.java │ │ │ ├── DisplayUtils.java │ │ │ ├── FingerprintUtil.java │ │ │ └── PinyinComparator.java │ │ │ └── widget │ │ │ ├── AnimationButton.java │ │ │ ├── ArcView.kt │ │ │ ├── BaseView.java │ │ │ ├── BubbleView.java │ │ │ ├── CarMoveView.kt │ │ │ ├── CircleProgressBarView.java │ │ │ ├── ClearScreenView.kt │ │ │ ├── DividerItemDecoration.java │ │ │ ├── DragBallView.java │ │ │ ├── FadeInTextView.java │ │ │ ├── HorizontalProgressBar.java │ │ │ ├── HoverItemDecoration.java │ │ │ ├── IndexView.java │ │ │ ├── IndicatorView.java │ │ │ ├── LoadingButton.java │ │ │ ├── LoadingLineView.java │ │ │ ├── LoadingView.java │ │ │ ├── PayPsdInputView.java │ │ │ ├── ProductProgressBar.java │ │ │ ├── RadarWaveView.java │ │ │ ├── StudyPlanProgressView.kt │ │ │ ├── SuperDividerItemDecoration.java │ │ │ ├── WaveViewByBezier.java │ │ │ ├── WaveViewBySinCos.java │ │ │ ├── banner │ │ │ ├── BannerView.java │ │ │ ├── PagerOptions.java │ │ │ ├── adapter │ │ │ │ └── BannerViewPagerAdapter.java │ │ │ ├── holder │ │ │ │ ├── BannerViewHolder.java │ │ │ │ └── BannerViewHolderCreator.java │ │ │ └── listener │ │ │ │ ├── OnPageChangeListener.java │ │ │ │ └── OnPageClickListener.java │ │ │ ├── status │ │ │ ├── StatusBuilder.kt │ │ │ ├── StatusLayout.kt │ │ │ └── StatusManager.kt │ │ │ └── vote │ │ │ ├── VoteContainerView.kt │ │ │ ├── VoteLayoutAdapter.kt │ │ │ └── VoteView.kt │ └── res │ │ ├── drawable │ │ ├── background_gradual_assarts.xml │ │ ├── shape_bg_clickable.xml │ │ ├── shape_bg_un_clickable.xml │ │ ├── shape_circle_bg.xml │ │ ├── shape_item_bg.xml │ │ ├── shape_search.xml │ │ ├── shape_vote_item_bg.xml │ │ ├── tag_bg_selector.xml │ │ ├── tag_checked_bg.xml │ │ ├── tag_normal_bg.xml │ │ └── tag_text_selector.xml │ │ ├── layout │ │ ├── activity_alipay_home.xml │ │ ├── activity_animation_btn.xml │ │ ├── activity_animation_view.xml │ │ ├── activity_banner.xml │ │ ├── activity_bubble_view.xml │ │ ├── activity_clear_screen.xml │ │ ├── activity_drag_ball.xml │ │ ├── activity_finger_print.xml │ │ ├── activity_hover_item.xml │ │ ├── activity_main.xml │ │ ├── activity_path.xml │ │ ├── activity_pay_psd_view.xml │ │ ├── activity_pregress_bar.xml │ │ ├── activity_radar.xml │ │ ├── activity_recycler_view_item_anim.xml │ │ ├── activity_reveal_animation.xml │ │ ├── activity_sina_vote.xml │ │ ├── activity_tag.xml │ │ ├── activity_wave_by_bezier.xml │ │ ├── activity_wave_by_sin_cos.xml │ │ ├── activity_webview.xml │ │ ├── adapter_item_hover_user.xml │ │ ├── adapter_item_main.xml │ │ ├── banner_item.xml │ │ ├── banner_view_layout.xml │ │ ├── include_default_layout.xml │ │ ├── include_toolbar_close.xml │ │ ├── include_toolbar_open.xml │ │ ├── item_danmu_layout.xml │ │ ├── tag_layout.xml │ │ └── widget_vote_layout.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── icon_study_progress_completed.png │ │ └── icon_study_progress_not_check.png │ │ ├── mipmap-xhdpi │ │ ├── beijing2x.jpg │ │ ├── ic_launcher.png │ │ └── start_logo_group.png │ │ ├── mipmap-xxhdpi │ │ ├── alipay_home_bg.jpg │ │ ├── app_download.png │ │ ├── banner_point_disabled.png │ │ ├── banner_point_enabled.png │ │ ├── car.png │ │ ├── ic_add.png │ │ ├── ic_camera_3x.png │ │ ├── ic_card.png │ │ ├── ic_contact.png │ │ ├── ic_launcher.png │ │ ├── ic_payment.png │ │ ├── ic_scan.png │ │ ├── ic_search.png │ │ ├── ic_transfer.png │ │ ├── icon_img1.png │ │ ├── icon_img2.jpg │ │ ├── icon_vote_check.png │ │ ├── icon_vote_unchecked.png │ │ ├── live_bg.jpeg │ │ └── progress_tip_icon.png │ │ ├── mipmap-xxxhdpi │ │ ├── beijing.jpg │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── allen │ └── androidcustomview │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── pay_psd_input_view.md ├── progress.md └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | .idea 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 34 | 35 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 扫码下载最新demo第一时间体验新功能 2 | ## 如有问题可以加群讨论 3 | STV&RxHttp交流群 4 | 5 | 或者手动加QQ群:688433795 6 | 7 | ## Demo示例下载 8 | [点击下载demo体验](http://d.firim.top/whez) 9 | 10 | # [**炫酷的提交按钮**](https://github.com/lygttpod/AndroidCustomView/blob/master/animation_button.md) 11 | ![99.gif](http://upload-images.jianshu.io/upload_images/2057501-0d1119721429bf71.gif?imageMogr2/auto-orient/strip) 12 | 13 | 14 | # [**仿微信支付宝等风格的支付密码输入框的实现**](https://github.com/lygttpod/AndroidCustomView/blob/master/pay_psd_input_view.md) 15 | ![两种样式供你选择](http://upload-images.jianshu.io/upload_images/2057501-3ca764c315dcdea2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/320) 16 | 17 | # [**炫酷的进度条**](https://github.com/lygttpod/AndroidCustomView/blob/master/progress.md) 18 | ![progress.gif](http://upload-images.jianshu.io/upload_images/2057501-615ad5fe97faf782.gif?imageMogr2/auto-orient/strip) 19 | 20 | # [**TextView实现打印机逐个显示的效果**](http://www.jianshu.com/p/4d987769785c) 21 | ![FadeInTextView.gif](http://upload-images.jianshu.io/upload_images/2057501-a7a751b456b25494.gif?imageMogr2/auto-orient/strip) 22 | 23 | # [**水波动画效果多种实现方式详解**](http://www.jianshu.com/p/0cd1c1d47f4a) 24 | ![wave.gif](http://upload-images.jianshu.io/upload_images/2057501-43358432099e1e71.gif?imageMogr2/auto-orient/strip) 25 | 26 | # [**仿QQ未读消息拖拽效果详解**](http://www.jianshu.com/p/ed2721286778) 27 | ![拖拽粘性小球.gif](http://upload-images.jianshu.io/upload_images/2057501-7df462b80a11f7e2.gif?imageMogr2/auto-orient/strip) 28 | 29 | # [**炫酷的欢迎页**] 30 | ![欢迎页.gif](http://osnoex6vf.bkt.clouddn.com/welcome.gif) 31 | 32 | # [**进度条**] 33 | ![进度条.gif](http://osnoex6vf.bkt.clouddn.com/loading.gif) 34 | 35 | # [**一行代码实现吸顶悬停效果**] 36 | ![吸顶悬停.gif](http://osnoex6vf.bkt.clouddn.com/hover_view.gif) 37 | 38 | 39 | # [**支付宝首页效果**] 40 | ![支付宝首页效果.gif](http://osnoex6vf.bkt.clouddn.com/alipay_home.gif) 41 | 42 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | 4 | apply plugin: 'kotlin-android-extensions' 5 | 6 | android { 7 | compileSdkVersion 27 8 | defaultConfig { 9 | applicationId "com.allen.androidcustomview" 10 | targetSdkVersion 27 11 | minSdkVersion 17 12 | versionCode 1 13 | versionName "1.0" 14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | productFlavors { 23 | } 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(include: ['*.jar'], dir: 'libs') 28 | androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { 29 | exclude group: 'com.android.support', module: 'support-annotations' 30 | }) 31 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 32 | implementation 'com.android.support:appcompat-v7:27.1.1' 33 | implementation 'com.android.support:design:27.1.1' 34 | implementation 'com.android.support:recyclerview-v7:27.1.1' 35 | testImplementation 'junit:junit:4.12' 36 | implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.40' 37 | } 38 | -------------------------------------------------------------------------------- /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 D:\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/allen/androidcustomview/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.allen.androidcustomview", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/AliPayHomeActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.design.widget.AppBarLayout; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.View; 9 | 10 | import com.allen.androidcustomview.R; 11 | 12 | /** 13 | *
14 |  *      @author : Allen
15 |  *      date    : 2018/09/30
16 |  *      desc    : 支付宝首页 来源 https://mp.weixin.qq.com/s/GegMt7GDBCFVoUgFQWG3Sw
17 |  *      version : 1.0
18 |  * 
19 | */ 20 | public class AliPayHomeActivity extends AppCompatActivity implements AppBarLayout.OnOffsetChangedListener { 21 | 22 | 23 | private AppBarLayout mAppBarLayout; 24 | private View mToolbarOpenBgView; 25 | private View mToolbarCloseBgView; 26 | private View mToolbarOpenLayout; 27 | private View mToolbarCloseLayout; 28 | private View contentBgView; 29 | @Override 30 | protected void onCreate(@Nullable Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | 33 | setContentView(R.layout.activity_alipay_home); 34 | initView(); 35 | mAppBarLayout.addOnOffsetChangedListener(this); 36 | } 37 | 38 | private void initView() { 39 | 40 | mToolbarOpenBgView = findViewById(R.id.toolbar_open_bg_view); 41 | mToolbarOpenLayout = findViewById(R.id.include_toolbar_open); 42 | 43 | mToolbarCloseBgView = findViewById(R.id.bg_toolbar_close); 44 | mToolbarCloseLayout = findViewById(R.id.include_toolbar_close); 45 | contentBgView = findViewById(R.id.content_bg_view); 46 | 47 | mAppBarLayout = findViewById(R.id.app_bar_layout); 48 | } 49 | 50 | @Override 51 | public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { 52 | 53 | //垂直方向偏移量 54 | int offset = Math.abs(verticalOffset); 55 | //最大偏移距离 56 | int scrollRange = appBarLayout.getTotalScrollRange(); 57 | if (offset <= scrollRange / 2) {//当滑动没超过一半,展开状态下toolbar显示内容,根据收缩位置,改变透明值 58 | mToolbarOpenLayout.setVisibility(View.VISIBLE); 59 | mToolbarCloseLayout.setVisibility(View.GONE); 60 | //根据偏移百分比 计算透明值 61 | float scale2 = (float) offset / (scrollRange / 2); 62 | int alpha2 = (int) (255 * scale2); 63 | mToolbarOpenBgView.setBackgroundColor(Color.argb(alpha2, 25, 131, 209)); 64 | } else {//当滑动超过一半,收缩状态下toolbar显示内容,根据收缩位置,改变透明值 65 | mToolbarOpenLayout.setVisibility(View.GONE); 66 | mToolbarCloseLayout.setVisibility(View.VISIBLE); 67 | float scale3 = (float) (scrollRange - offset) / (scrollRange / 2); 68 | int alpha3 = (int) (255 * scale3); 69 | mToolbarCloseBgView.setBackgroundColor(Color.argb(alpha3, 25, 131, 209)); 70 | } 71 | //根据偏移百分比计算扫一扫布局的透明度值 72 | float scale = (float) offset / scrollRange; 73 | int alpha = (int) (255 * scale); 74 | contentBgView.setBackgroundColor(Color.argb(alpha, 25, 131, 209)); 75 | } 76 | 77 | @Override 78 | protected void onDestroy() { 79 | super.onDestroy(); 80 | mAppBarLayout.removeOnOffsetChangedListener(this); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/AnimationBtnActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.widget.Toast; 6 | 7 | import com.allen.androidcustomview.R; 8 | import com.allen.androidcustomview.widget.AnimationButton; 9 | 10 | public class AnimationBtnActivity extends AppCompatActivity { 11 | 12 | private AnimationButton animationButton; 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_animation_btn); 18 | animationButton = (AnimationButton) findViewById(R.id.animation_btn); 19 | animationButton.setAnimationButtonListener(new AnimationButton.AnimationButtonListener() { 20 | @Override 21 | public void onClickListener() { 22 | animationButton.start(); 23 | } 24 | 25 | @Override 26 | public void animationFinish() { 27 | Toast.makeText(AnimationBtnActivity.this,"动画执行完毕",Toast.LENGTH_SHORT).show(); 28 | // finish(); 29 | animationButton.reset(); 30 | } 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/AnimationViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.Toast; 7 | 8 | import com.allen.androidcustomview.R; 9 | import com.allen.androidcustomview.widget.FadeInTextView; 10 | import com.allen.androidcustomview.widget.LoadingButton; 11 | 12 | public class AnimationViewActivity extends AppCompatActivity { 13 | 14 | private FadeInTextView fadeInTextView; 15 | private LoadingButton loadingButton; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_animation_view); 21 | 22 | fadeInTextView = (FadeInTextView) findViewById(R.id.fade_in_tv); 23 | loadingButton = (LoadingButton) findViewById(R.id.loading_btn); 24 | 25 | fadeInTextView 26 | .setTextString("自定义view实现字符串逐字显示,后边的文字是为了测试换行是否正常显示!") 27 | .setTextAnimationListener(new FadeInTextView.TextAnimationListener() { 28 | @Override 29 | public void animationFinish() { 30 | loadingButton.stopLoading(); 31 | } 32 | }); 33 | 34 | loadingButton.setOnClickListener(new View.OnClickListener() { 35 | @Override 36 | public void onClick(View v) { 37 | loadingButton.startLoading(); 38 | fadeInTextView.startFadeInAnimation(); 39 | } 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/BannerActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.view.ViewPager; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.widget.ImageView; 12 | import android.widget.Toast; 13 | 14 | import com.allen.androidcustomview.R; 15 | import com.allen.androidcustomview.widget.banner.BannerView; 16 | import com.allen.androidcustomview.widget.banner.listener.OnPageChangeListener; 17 | import com.allen.androidcustomview.widget.banner.listener.OnPageClickListener; 18 | import com.allen.androidcustomview.widget.banner.PagerOptions; 19 | import com.allen.androidcustomview.widget.banner.holder.BannerViewHolder; 20 | import com.allen.androidcustomview.widget.banner.holder.BannerViewHolderCreator; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | /** 26 | *
27 |  *      @author : xiaoyao
28 |  *      e-mail  : xiaoyao@51vest.com
29 |  *      date    : 2018/03/09
30 |  *      desc    :
31 |  *      version : 1.0
32 |  * 
33 | */ 34 | 35 | public class BannerActivity extends AppCompatActivity { 36 | 37 | private BannerView bannerView; 38 | private List datas = new ArrayList<>(); 39 | @Override 40 | protected void onCreate(@Nullable Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.activity_banner); 43 | 44 | datas.add("http://7xi8d6.com1.z0.glb.clouddn.com/20180109085038_4A7atU_rakukoo_9_1_2018_8_50_25_276.jpeg"); 45 | datas.add("http://7xi8d6.com1.z0.glb.clouddn.com/20180102083655_3t4ytm_Screenshot.jpeg"); 46 | datas.add("http://7xi8d6.com1.z0.glb.clouddn.com/20171228085004_5yEHju_Screenshot.jpeg"); 47 | 48 | bannerView = (BannerView) findViewById(R.id.banner_view); 49 | 50 | PagerOptions options = new PagerOptions 51 | .Builder(this) 52 | .setPageMargin(20) 53 | .setPrePagerWidth(50) 54 | .setIndicatorDrawable(R.mipmap.banner_point_disabled,R.mipmap.banner_point_enabled) 55 | // .setIndicatorColor(Color.YELLOW,Color.RED) 56 | .setOnPageClickListener(new OnPageClickListener() { 57 | @Override 58 | public void onPageClick(View view, int position) { 59 | Toast.makeText(BannerActivity.this,"Click"+position,Toast.LENGTH_SHORT).show(); 60 | } 61 | }) 62 | .build(); 63 | 64 | 65 | bannerView.setPagerOptions(options) 66 | .setPages(datas, new BannerViewHolderCreator() { 67 | @Override 68 | public MyBanner createViewHolder() { 69 | return new MyBanner(); 70 | } 71 | }); 72 | 73 | } 74 | 75 | public class MyBanner implements BannerViewHolder{ 76 | 77 | private ImageView imageView; 78 | @Override 79 | public View createView(Context context) { 80 | View view = LayoutInflater.from(context).inflate(R.layout.banner_item,null); 81 | return view; 82 | } 83 | 84 | @Override 85 | public void onBind(Context context, int position, String data) { 86 | 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/ClearScreenActivity.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import android.widget.Toast 6 | import com.allen.androidcustomview.R 7 | import com.allen.androidcustomview.widget.ClearScreenMode 8 | import com.allen.androidcustomview.widget.ClearScreenView 9 | import kotlinx.android.synthetic.main.activity_clear_screen.* 10 | 11 | /** 12 | *
13 |  *      author  : Allen
14 |  *      date    : 2021/1/28
15 |  *      desc    :
16 |  * 
17 | */ 18 | class ClearScreenActivity : AppCompatActivity(), ClearScreenView.OnClearScreenListener { 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | setContentView(R.layout.activity_clear_screen) 23 | 24 | clear_screen_container.addClearView(iv_clear_content) 25 | 26 | clear_screen_container.setOnClearScreenListener(this) 27 | 28 | btn_quick_clear.setOnClickListener { clear_screen_container.clearScreenMode = ClearScreenMode.QUICK_SCROLL } 29 | btn_slow_clear.setOnClickListener { clear_screen_container.clearScreenMode = ClearScreenMode.SLOW_SCROLL } 30 | } 31 | 32 | override fun onCleared() { 33 | Toast.makeText(this, "清屏了", Toast.LENGTH_SHORT).show() 34 | } 35 | 36 | override fun onRestored() { 37 | Toast.makeText(this, "恢复了", Toast.LENGTH_SHORT).show() 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/DragBallActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.text.TextUtils; 7 | import android.view.View; 8 | import android.widget.Button; 9 | import android.widget.EditText; 10 | import android.widget.Toast; 11 | 12 | import com.allen.androidcustomview.R; 13 | import com.allen.androidcustomview.widget.DragBallView; 14 | 15 | 16 | public class DragBallActivity extends AppCompatActivity { 17 | 18 | 19 | private Button resetBtn, msgCountBtn; 20 | private DragBallView dragBallView; 21 | private EditText msgCountEt; 22 | 23 | @Override 24 | protected void onCreate(@Nullable Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_drag_ball); 27 | resetBtn = (Button) findViewById(R.id.reset_btn); 28 | msgCountBtn = (Button) findViewById(R.id.msg_count_btn); 29 | dragBallView = (DragBallView) findViewById(R.id.drag_ball_view); 30 | 31 | msgCountEt = (EditText) findViewById(R.id.msg_count_et); 32 | 33 | resetBtn.setOnClickListener(new View.OnClickListener() { 34 | @Override 35 | public void onClick(View v) { 36 | dragBallView.reset(); 37 | } 38 | }); 39 | 40 | msgCountBtn.setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | if (!TextUtils.isEmpty(msgCountEt.getText().toString().trim())) { 44 | int count = Integer.valueOf(msgCountEt.getText().toString().trim()); 45 | dragBallView.setMsgCount(count); 46 | } 47 | } 48 | }); 49 | 50 | dragBallView.setOnDragBallListener(new DragBallView.OnDragBallListener() { 51 | @Override 52 | public void onDisappear() { 53 | Toast.makeText(DragBallActivity.this, "消失了", Toast.LENGTH_SHORT).show(); 54 | } 55 | }); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/FingerprintActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.hardware.fingerprint.FingerprintManagerCompat; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.TextView; 10 | import android.widget.Toast; 11 | 12 | import com.allen.androidcustomview.R; 13 | import com.allen.androidcustomview.utils.FingerprintUtil; 14 | 15 | /** 16 | * Created by xiaoyao on 2017/9/14. 17 | */ 18 | 19 | public class FingerprintActivity extends AppCompatActivity { 20 | 21 | private static final String TAG = "allen"; 22 | 23 | 24 | TextView resultTv; 25 | @Override 26 | protected void onCreate(@Nullable Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | 29 | setContentView(R.layout.activity_finger_print); 30 | 31 | resultTv = (TextView) findViewById(R.id.result_tv); 32 | findViewById(R.id.open_finger_btn).setOnClickListener(new View.OnClickListener() { 33 | @Override 34 | public void onClick(View v) { 35 | openFinger(); 36 | } 37 | }); 38 | 39 | 40 | findViewById(R.id.cancel_finger_btn).setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | FingerprintUtil.cancel(); 44 | } 45 | }); 46 | 47 | 48 | } 49 | 50 | private void openFinger() { 51 | 52 | FingerprintUtil.callFingerPrint(this, new FingerprintUtil.OnCallBackListener() { 53 | @Override 54 | public void onSupportFailed() { 55 | Toast.makeText(FingerprintActivity.this, "当前设备不支持指纹", Toast.LENGTH_LONG).show(); 56 | Log.e(TAG, "当前设备不支持指纹"); 57 | } 58 | 59 | @Override 60 | public void onInsecurity() { 61 | Toast.makeText(FingerprintActivity.this, "当前设备未处于安全保护中", Toast.LENGTH_LONG).show(); 62 | Log.e(TAG, "当前设备未处于安全保护中"); 63 | } 64 | 65 | @Override 66 | public void onEnrollFailed() { 67 | Toast.makeText(FingerprintActivity.this, "请到设置中设置指纹", Toast.LENGTH_LONG).show(); 68 | Log.e(TAG, "请到设置中设置指纹"); 69 | } 70 | 71 | @Override 72 | public void onAuthenticationStart() { 73 | Toast.makeText(FingerprintActivity.this, "验证开始", Toast.LENGTH_LONG).show(); 74 | 75 | Log.e(TAG, "onAuthenticationStart: "); 76 | } 77 | 78 | @Override 79 | public void onAuthenticationError(int errMsgId, CharSequence errString) { 80 | Toast.makeText(FingerprintActivity.this, errString, Toast.LENGTH_LONG).show(); 81 | Log.e(TAG, "onAuthenticationError: "); 82 | } 83 | 84 | @Override 85 | public void onAuthenticationFailed() { 86 | Toast.makeText(FingerprintActivity.this, "解锁失败", Toast.LENGTH_LONG).show(); 87 | 88 | Log.e(TAG, "解锁失败"); 89 | } 90 | 91 | @Override 92 | public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { 93 | Toast.makeText(FingerprintActivity.this, helpString, Toast.LENGTH_LONG).show(); 94 | 95 | Log.e(TAG, "onAuthenticationHelp: "); 96 | } 97 | 98 | @Override 99 | public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) { 100 | Toast.makeText(FingerprintActivity.this, "解锁成功", Toast.LENGTH_LONG).show(); 101 | Log.e(TAG, "解锁成功"); 102 | resultTv.setText(result.getClass().getName()); 103 | } 104 | }); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/HoverItemActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.widget.TextView; 9 | 10 | import com.allen.androidcustomview.R; 11 | import com.allen.androidcustomview.adapter.HoverAdapter; 12 | import com.allen.androidcustomview.bean.UserBean; 13 | import com.allen.androidcustomview.utils.CharacterParser; 14 | import com.allen.androidcustomview.utils.PinyinComparator; 15 | import com.allen.androidcustomview.widget.HoverItemDecoration; 16 | import com.allen.androidcustomview.widget.IndexView; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.List; 21 | 22 | /** 23 | *
 24 |  *      @author : xiaoyao
 25 |  *      e-mail  : xiaoyao@51vest.com
 26 |  *      date    : 2018/04/16
 27 |  *      desc    :
 28 |  *      version : 1.0
 29 |  * 
30 | */ 31 | 32 | public class HoverItemActivity extends AppCompatActivity { 33 | private RecyclerView recyclerView; 34 | private IndexView indexView; 35 | private TextView showTextDialog; 36 | 37 | private HoverAdapter adapter; 38 | 39 | private List userBeans = new ArrayList<>(); 40 | 41 | private String[] names = new String[]{"阿妹", "打黑牛", "张三", "李四", "王五", "田鸡", "孙五"}; 42 | 43 | /** 44 | * 汉字转换成拼音的类 45 | */ 46 | private CharacterParser characterParser; 47 | /** 48 | * 根据拼音来排列ListView里面的数据类 49 | */ 50 | private PinyinComparator pinyinComparator; 51 | 52 | private LinearLayoutManager layoutManager; 53 | 54 | @Override 55 | protected void onCreate(@Nullable Bundle savedInstanceState) { 56 | super.onCreate(savedInstanceState); 57 | setContentView(R.layout.activity_hover_item); 58 | 59 | characterParser = CharacterParser.getInstance(); 60 | pinyinComparator = new PinyinComparator(); 61 | 62 | 63 | userBeans = filledData(getData()); 64 | 65 | recyclerView = (RecyclerView) findViewById(R.id.recycler_view); 66 | indexView = (IndexView) findViewById(R.id.index_view); 67 | showTextDialog = (TextView) findViewById(R.id.show_text_dialog); 68 | 69 | layoutManager = new LinearLayoutManager(this); 70 | recyclerView.setLayoutManager(layoutManager); 71 | //一行代码实现吸顶悬浮的效果 72 | recyclerView.addItemDecoration(new HoverItemDecoration(this, new HoverItemDecoration.BindItemTextCallback() { 73 | @Override 74 | public String getItemText(int position) { 75 | //悬浮的信息 76 | return userBeans.get(position).getSortLetters(); 77 | } 78 | })); 79 | 80 | adapter = new HoverAdapter(userBeans); 81 | 82 | recyclerView.setAdapter(adapter); 83 | 84 | initIndexView(); 85 | } 86 | 87 | /** 88 | * 初始化右边字幕索引view 89 | */ 90 | private void initIndexView() { 91 | indexView.setShowTextDialog(showTextDialog); 92 | indexView.setOnTouchingLetterChangedListener(new IndexView.OnTouchingLetterChangedListener() { 93 | @Override 94 | public void onTouchingLetterChanged(String letter) { 95 | // 该字母首次出现的位置 96 | int position = getPositionForSection(letter); 97 | if (position != -1) { 98 | layoutManager.scrollToPositionWithOffset(position, 0); 99 | layoutManager.setStackFromEnd(false); 100 | } 101 | } 102 | }); 103 | } 104 | 105 | public int getPositionForSection(String section) { 106 | for (int i = 0; i < userBeans.size(); i++) { 107 | String sortStr = userBeans.get(i).getSortLetters(); 108 | if (sortStr.equals(section)) { 109 | return i; 110 | } 111 | } 112 | return -1; 113 | } 114 | 115 | private List getData() { 116 | List userBeans = new ArrayList<>(); 117 | for (int i = 0; i < 50; i++) { 118 | UserBean userBean = new UserBean(); 119 | userBean.setUserName(names[i % 7]); 120 | userBeans.add(userBean); 121 | } 122 | 123 | return userBeans; 124 | } 125 | 126 | private List filledData(List sortList) { 127 | 128 | for (int i = 0; i < sortList.size(); i++) { 129 | 130 | if ("".equals(sortList.get(i).getUserName())) { 131 | sortList.get(i).setSortLetters("#"); 132 | } else { 133 | // 汉字转换成拼音 134 | String pinyin = characterParser.getSelling(sortList.get(i).getUserName()); 135 | String sortString = pinyin.substring(0, 1).toUpperCase(); 136 | 137 | // 正则表达式,判断首字母是否是英文字母 138 | if (sortString.matches("[A-Z]")) { 139 | sortList.get(i).setSortLetters(sortString.toUpperCase()); 140 | } else { 141 | sortList.get(i).setSortLetters("#"); 142 | } 143 | } 144 | 145 | } 146 | 147 | // 根据a-z进行排序源数据 148 | Collections.sort(sortList, pinyinComparator); 149 | 150 | return sortList; 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | import android.support.v7.widget.LinearLayoutManager 7 | import android.view.View 8 | import android.widget.Toast 9 | import com.allen.androidcustomview.R 10 | import com.allen.androidcustomview.adapter.MainAdapter 11 | import com.allen.androidcustomview.bean.TypeBean 12 | import com.allen.androidcustomview.helper.DragViewHelper 13 | import com.allen.androidcustomview.tagview.TagActivity 14 | import com.allen.androidcustomview.widget.SuperDividerItemDecoration 15 | import com.chad.library.adapter.base.BaseQuickAdapter 16 | import kotlinx.android.synthetic.main.activity_main.* 17 | import java.util.* 18 | 19 | 20 | class MainActivity : AppCompatActivity(), BaseQuickAdapter.OnItemClickListener { 21 | 22 | private var adapter: MainAdapter? = null 23 | 24 | private val typeBeans = ArrayList() 25 | 26 | private val data: List 27 | get() { 28 | typeBeans.add(TypeBean("气泡漂浮动画", 0)) 29 | typeBeans.add(TypeBean("波浪动画--贝塞尔曲线实现", 1)) 30 | typeBeans.add(TypeBean("波浪动画--正余弦函数实现", 2)) 31 | typeBeans.add(TypeBean("水波(雷达)扩散效果", 3)) 32 | typeBeans.add(TypeBean("RecyclerView实现另类的Tag标签", 4)) 33 | typeBeans.add(TypeBean("按钮自定义动画", 5)) 34 | typeBeans.add(TypeBean("自定义支付密码输入框", 6)) 35 | typeBeans.add(TypeBean("自定义进度条", 7)) 36 | typeBeans.add(TypeBean("使用的带动画的view", 8)) 37 | typeBeans.add(TypeBean("粘性小球", 9)) 38 | typeBeans.add(TypeBean("banner", 10)) 39 | typeBeans.add(TypeBean("吸顶效果--一行代码实现", 11)) 40 | typeBeans.add(TypeBean("揭露动画", 12)) 41 | typeBeans.add(TypeBean("支付宝首页效果", 13)) 42 | typeBeans.add(TypeBean("RecyclerView的item动画", 14)) 43 | typeBeans.add(TypeBean("路径path动画", 15)) 44 | typeBeans.add(TypeBean("仿新浪投票控件", 16)) 45 | typeBeans.add(TypeBean("直播侧滑清屏效果", 17)) 46 | return typeBeans 47 | } 48 | 49 | override fun onCreate(savedInstanceState: Bundle?) { 50 | super.onCreate(savedInstanceState) 51 | setContentView(R.layout.activity_main) 52 | 53 | adapter = MainAdapter(data) 54 | adapter!!.onItemClickListener = this 55 | recycler_view.layoutManager = LinearLayoutManager(this) 56 | recycler_view.addItemDecoration(SuperDividerItemDecoration.Builder(this) 57 | .build()) 58 | recycler_view.adapter = adapter 59 | 60 | DragViewHelper.addDragView(this, 61 | root_view, 62 | "网络图片地址", 63 | defaultImgResId = R.mipmap.ic_camera_3x, 64 | onClick = { 65 | Toast.makeText(this, "点击事件", Toast.LENGTH_SHORT).show() 66 | }) 67 | } 68 | 69 | override fun onItemClick(adapter: BaseQuickAdapter<*, *>, view: View, position: Int) { 70 | when (typeBeans[position].type) { 71 | 0 -> startActivity(Intent(this@MainActivity, BubbleViewActivity::class.java)) 72 | 1 -> startActivity(Intent(this@MainActivity, WaveByBezierActivity::class.java)) 73 | 2 -> startActivity(Intent(this@MainActivity, WaveBySinCosActivity::class.java)) 74 | 3 -> startActivity(Intent(this@MainActivity, RadarActivity::class.java)) 75 | 4 -> startActivity(Intent(this@MainActivity, TagActivity::class.java)) 76 | 5 -> startActivity(Intent(this@MainActivity, AnimationBtnActivity::class.java)) 77 | 6 -> startActivity(Intent(this@MainActivity, PayPsdViewActivity::class.java)) 78 | 7 -> startActivity(Intent(this@MainActivity, ProgressBarActivity::class.java)) 79 | 8 -> startActivity(Intent(this@MainActivity, AnimationViewActivity::class.java)) 80 | 9 -> startActivity(Intent(this@MainActivity, DragBallActivity::class.java)) 81 | 10 -> startActivity(Intent(this@MainActivity, BannerActivity::class.java)) 82 | 11 -> startActivity(Intent(this@MainActivity, HoverItemActivity::class.java)) 83 | 12 -> startActivity(Intent(this@MainActivity, RevealAnimationActivity::class.java)) 84 | 13 -> startActivity(Intent(this@MainActivity, AliPayHomeActivity::class.java)) 85 | 14 -> startActivity(Intent(this@MainActivity, RecyclerViewItemAnimActivity::class.java)) 86 | 15 -> startActivity(Intent(this@MainActivity, PathActivity::class.java)) 87 | 16 -> startActivity(Intent(this@MainActivity, SinaVoteActivity::class.java)) 88 | 17 -> startActivity(Intent(this@MainActivity, ClearScreenActivity::class.java)) 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/PathActivity.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import com.allen.androidcustomview.R 6 | import kotlinx.android.synthetic.main.activity_path.* 7 | 8 | /** 9 | *
10 |  *      @author : Allen
11 |  *      date    : 2019/07/23
12 |  *      desc    :
13 |  * 
14 | */ 15 | class PathActivity : AppCompatActivity() { 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | setContentView(R.layout.activity_path) 20 | start_btn.setOnClickListener { 21 | car_anim_view.startAnim() 22 | } 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/PayPsdViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.widget.Toast; 6 | 7 | import com.allen.androidcustomview.R; 8 | import com.allen.androidcustomview.widget.PayPsdInputView; 9 | 10 | public class PayPsdViewActivity extends AppCompatActivity { 11 | private PayPsdInputView passwordInputView; 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_pay_psd_view); 17 | 18 | passwordInputView = (PayPsdInputView) findViewById(R.id.password); 19 | 20 | passwordInputView.setComparePassword( new PayPsdInputView.onPasswordListener() { 21 | 22 | @Override 23 | public void onDifference(String oldPsd, String newPsd) { 24 | // TODO: 2018/1/22 和上次输入的密码不一致 做相应的业务逻辑处理 25 | Toast.makeText(PayPsdViewActivity.this, "两次密码输入不同" + oldPsd + "!=" + newPsd, Toast.LENGTH_SHORT).show(); 26 | passwordInputView.cleanPsd(); 27 | } 28 | 29 | @Override 30 | public void onEqual(String psd) { 31 | // TODO: 2017/5/7 两次输入密码相同,那就去进行支付楼 32 | Toast.makeText(PayPsdViewActivity.this, "密码相同" + psd, Toast.LENGTH_SHORT).show(); 33 | passwordInputView.setComparePassword(""); 34 | passwordInputView.cleanPsd(); 35 | } 36 | 37 | @Override 38 | public void inputFinished(String inputPsd) { 39 | // TODO: 2018/1/3 输完逻辑 40 | Toast.makeText(PayPsdViewActivity.this, "输入完毕:" + inputPsd, Toast.LENGTH_SHORT).show(); 41 | passwordInputView.setComparePassword(inputPsd); 42 | } 43 | }); 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/ProgressBarActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.Button; 8 | import android.widget.TextView; 9 | 10 | import com.allen.androidcustomview.R; 11 | import com.allen.androidcustomview.widget.CircleProgressBarView; 12 | import com.allen.androidcustomview.widget.HorizontalProgressBar; 13 | import com.allen.androidcustomview.widget.LoadingLineView; 14 | import com.allen.androidcustomview.widget.LoadingView; 15 | import com.allen.androidcustomview.widget.ProductProgressBar; 16 | import com.allen.androidcustomview.widget.StudyPlanProgressView; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | public class ProgressBarActivity extends AppCompatActivity { 22 | 23 | CircleProgressBarView circleProgressBarView; 24 | HorizontalProgressBar horizontalProgressBar; 25 | ProductProgressBar productProgressBar; 26 | LoadingView loadingView; 27 | TextView textView; 28 | LoadingLineView loadingLineView; 29 | 30 | Button button; 31 | StudyPlanProgressView studyPlanProgressView; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_pregress_bar); 37 | 38 | circleProgressBarView = (CircleProgressBarView) findViewById(R.id.circle_progress_view); 39 | 40 | horizontalProgressBar = (HorizontalProgressBar) findViewById(R.id.horizontal_progress_view); 41 | productProgressBar = (ProductProgressBar) findViewById(R.id.product_progress_view); 42 | loadingView = (LoadingView) findViewById(R.id.loading_view); 43 | loadingLineView = (LoadingLineView) findViewById(R.id.loading_line_view); 44 | 45 | textView = (TextView) findViewById(R.id.progress_tv); 46 | button = (Button) findViewById(R.id.startAnimationBtn); 47 | studyPlanProgressView = findViewById(R.id.study_plan_progress_view); 48 | 49 | circleProgressBarView.setProgressWithAnimation(60); 50 | circleProgressBarView.setProgressListener(new CircleProgressBarView.ProgressListener() { 51 | @Override 52 | public void currentProgressListener(float currentProgress) { 53 | textView.setText("当前进度:" + currentProgress); 54 | } 55 | }); 56 | circleProgressBarView.startProgressAnimation(); 57 | 58 | horizontalProgressBar.setProgressWithAnimation(60).setProgressListener(new HorizontalProgressBar.ProgressListener() { 59 | @Override 60 | public void currentProgressListener(float currentProgress) { 61 | } 62 | }); 63 | horizontalProgressBar.startProgressAnimation(); 64 | 65 | productProgressBar.setProgress(60).setProgressListener(new ProductProgressBar.ProgressListener() { 66 | @Override 67 | public void currentProgressListener(float currentProgress) { 68 | Log.e("allen", "currentProgressListener: " + currentProgress); 69 | } 70 | }); 71 | 72 | loadingView.startAnimation(); 73 | 74 | button.setOnClickListener(new View.OnClickListener() { 75 | @Override 76 | public void onClick(View v) { 77 | loadingLineView.startLoading(); 78 | loadingView.startAnimation(); 79 | horizontalProgressBar.setProgressWithAnimation(100); 80 | productProgressBar.setProgress(100); 81 | circleProgressBarView.setProgressWithAnimation(60).startProgressAnimation(); 82 | circleProgressBarView.setProgressListener(new CircleProgressBarView.ProgressListener() { 83 | @Override 84 | public void currentProgressListener(float currentProgress) { 85 | textView.setText("当前进度:" + currentProgress); 86 | } 87 | }); 88 | studyPlanProgressView.setData(getPlanData(true)); 89 | } 90 | }); 91 | studyPlanProgressView.setData(getPlanData(false)); 92 | 93 | } 94 | 95 | private List getPlanData(Boolean isAll) { 96 | List list = new ArrayList<>(); 97 | list.add("08月10日"); 98 | list.add("08月11日"); 99 | list.add("08月12日"); 100 | list.add("08月13日"); 101 | if (isAll) { 102 | list.add("08月14日"); 103 | list.add("08月15日"); 104 | list.add("08月16日"); 105 | } 106 | return list; 107 | } 108 | 109 | @Override 110 | protected void onResume() { 111 | super.onResume(); 112 | circleProgressBarView.resumeProgressAnimation(); 113 | } 114 | 115 | @Override 116 | protected void onPause() { 117 | super.onPause(); 118 | circleProgressBarView.pauseProgressAnimation(); 119 | } 120 | 121 | @Override 122 | protected void onDestroy() { 123 | super.onDestroy(); 124 | circleProgressBarView.stopProgressAnimation(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/RadarActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | import com.allen.androidcustomview.R; 7 | import com.allen.androidcustomview.widget.RadarWaveView; 8 | 9 | public class RadarActivity extends AppCompatActivity { 10 | 11 | private RadarWaveView radarView; 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_radar); 17 | 18 | radarView = (RadarWaveView) findViewById(R.id.radar_view); 19 | } 20 | 21 | @Override 22 | protected void onResume() { 23 | super.onResume(); 24 | radarView.start(); 25 | } 26 | 27 | @Override 28 | protected void onPause() { 29 | super.onPause(); 30 | radarView.pause(); 31 | } 32 | 33 | @Override 34 | protected void onDestroy() { 35 | super.onDestroy(); 36 | radarView.stop(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/RecyclerViewItemAnimActivity.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import android.support.v7.widget.DefaultItemAnimator 6 | import android.support.v7.widget.LinearLayoutManager 7 | import android.support.v7.widget.RecyclerView 8 | import com.allen.androidcustomview.R 9 | import com.allen.androidcustomview.adapter.ItemAnimAdapter 10 | import com.allen.androidcustomview.anim.RotateXItemAnimation 11 | import com.allen.androidcustomview.anim.RotateYItemAnimation 12 | import com.allen.androidcustomview.anim.ScaleItemAnimation 13 | import com.allen.androidcustomview.anim.SlideItemAnimation 14 | import kotlinx.android.synthetic.main.activity_recycler_view_item_anim.* 15 | import kotlin.random.Random 16 | 17 | /** 18 | *
19 |  *      @author : Allen
20 |  *      e-mail  : lygttpod@163.com
21 |  *      date    : 2019/05/11
22 |  *      desc    :
23 |  * 
24 | */ 25 | class RecyclerViewItemAnimActivity : AppCompatActivity() { 26 | 27 | var adapter: ItemAnimAdapter? = null 28 | 29 | override fun onCreate(savedInstanceState: Bundle?) { 30 | super.onCreate(savedInstanceState) 31 | setContentView(R.layout.activity_recycler_view_item_anim) 32 | initListener() 33 | initView() 34 | initData() 35 | } 36 | 37 | private fun initView() { 38 | adapter = ItemAnimAdapter(arrayListOf()) 39 | recycler_view.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false) 40 | recycler_view.adapter = adapter 41 | recycler_view.itemAnimator = DefaultItemAnimator() 42 | } 43 | 44 | private fun initListener() { 45 | normal_btn.setOnClickListener { setReverseLayout(false) } 46 | reverse_btn.setOnClickListener { setReverseLayout(true) } 47 | scale_btn.setOnClickListener { setItemAnimation(ScaleItemAnimation()) } 48 | slide_btn.setOnClickListener { setItemAnimation(SlideItemAnimation()) } 49 | rotate_x_btn.setOnClickListener { setItemAnimation(RotateXItemAnimation()) } 50 | rotate_y_btn.setOnClickListener { setItemAnimation(RotateYItemAnimation()) } 51 | 52 | add_btn.setOnClickListener { 53 | adapter?.addData(0, getItemData()) 54 | (recycler_view.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(0, 0) 55 | } 56 | 57 | remove_btn.setOnClickListener { 58 | if (adapter?.data?.size ?: 0 > 0) { 59 | adapter?.remove(0) 60 | (recycler_view.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(0, 0) 61 | } 62 | } 63 | } 64 | 65 | private fun setReverseLayout(reverseLayout: Boolean) { 66 | recycler_view.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, reverseLayout) 67 | adapter?.data?.clear() 68 | adapter?.notifyDataSetChanged() 69 | } 70 | 71 | private fun setItemAnimation(itemAnimation: RecyclerView.ItemAnimator) { 72 | adapter?.data?.clear() 73 | adapter?.notifyDataSetChanged() 74 | recycler_view.itemAnimator = itemAnimation 75 | } 76 | 77 | private fun initData(): ArrayList { 78 | val list: ArrayList = arrayListOf() 79 | list.add("人生如戏,全靠演技") 80 | list.add("年轻就是资本") 81 | list.add("我的一颗眼泪掉进了海洋,当我找到它的那一天就是我停止爱你的那一天") 82 | list.add("你若一直在,我便一直爱") 83 | list.add("路,跪着也要走完") 84 | list.add("美丽的彩虹就像一座七彩的桥一样高挂在雨后的天空") 85 | list.add("留情不留命,留命伤感情") 86 | list.add("宽容就是在别人和自己意见不一致时也不要勉强") 87 | list.add("那些曾经以为念念不忘的事情,就在我们念念不忘的过程里,被我们遗忘了") 88 | list.add("朝花夕拾捡的是枯萎") 89 | list.add("黄绢幼妇,其土老人") 90 | list.add("要有最朴素的生活,与最遥远的梦想,即使明日天寒地冻,路远马亡") 91 | list.add("不是路不平,而是你不行") 92 | return list 93 | } 94 | 95 | private fun getItemData(): String { 96 | return initData()[Random.nextInt(100) / 10 + 1] 97 | } 98 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/RevealAnimationActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.animation.Animator; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.View; 9 | import android.view.ViewAnimationUtils; 10 | import android.widget.Button; 11 | import android.widget.ImageView; 12 | 13 | import com.allen.androidcustomview.R; 14 | 15 | /** 16 | *
17 |  *      @author : xiaoyao
18 |  *      e-mail  : xiaoyao@51vest.com
19 |  *      date    : 2018/08/24
20 |  *      desc    : 揭露动画
21 |  *      version : 1.0
22 |  * 
23 | */ 24 | public class RevealAnimationActivity extends AppCompatActivity { 25 | 26 | private ImageView imageView; 27 | private Button startBtn; 28 | 29 | @Override 30 | protected void onCreate(@Nullable Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_reveal_animation); 33 | 34 | imageView = findViewById(R.id.img_iv); 35 | startBtn = findViewById(R.id.start_btn); 36 | 37 | 38 | final int centerX = 0; 39 | final int centerY = 0; 40 | startBtn.setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | final float radius = (float) Math.hypot(imageView.getWidth(), imageView.getHeight()); 44 | 45 | if (imageView.getVisibility() == View.VISIBLE) { 46 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 47 | Animator animator = ViewAnimationUtils.createCircularReveal(imageView, centerX, centerY, radius, 0); 48 | animator.setDuration(3000); 49 | animator.addListener(new Animator.AnimatorListener() { 50 | @Override 51 | public void onAnimationStart(Animator animation) { 52 | 53 | } 54 | 55 | @Override 56 | public void onAnimationEnd(Animator animation) { 57 | imageView.setVisibility(View.GONE); 58 | } 59 | 60 | @Override 61 | public void onAnimationCancel(Animator animation) { 62 | 63 | } 64 | 65 | @Override 66 | public void onAnimationRepeat(Animator animation) { 67 | 68 | } 69 | }); 70 | animator.start(); 71 | } 72 | 73 | } else { 74 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 75 | Animator animator = ViewAnimationUtils.createCircularReveal(imageView, centerX, centerY, 0, radius); 76 | animator.setDuration(3000); 77 | imageView.setVisibility(View.VISIBLE); 78 | animator.start(); 79 | } 80 | } 81 | } 82 | }); 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/SinaVoteActivity.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import com.allen.androidcustomview.R 6 | import com.allen.androidcustomview.bean.VoteBean 7 | import com.allen.androidcustomview.bean.VoteOption 8 | import com.allen.androidcustomview.data.getMockData 9 | import com.allen.androidcustomview.widget.vote.VoteLayoutAdapter 10 | import kotlinx.android.synthetic.main.activity_sina_vote.* 11 | 12 | /** 13 | *
14 |  *      @author : Allen
15 |  *      date    : 2019/08/06
16 |  *      desc    :
17 |  * 
18 | */ 19 | class SinaVoteActivity : AppCompatActivity(), VoteLayoutAdapter.OnVoteClickListener { 20 | 21 | var voteLayoutAdapter: VoteLayoutAdapter? = null 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | setContentView(R.layout.activity_sina_vote) 26 | voteLayoutAdapter = VoteLayoutAdapter(vote_ll) 27 | voteLayoutAdapter?.setData(getMockData()) 28 | voteLayoutAdapter?.onVoteClickListener = this 29 | } 30 | 31 | override fun onDestroy() { 32 | super.onDestroy() 33 | voteLayoutAdapter?.onDestroy() 34 | } 35 | 36 | override fun onVoteCommitBtnClick(mainVote: VoteBean?, optionIds: ArrayList, position: Int) { 37 | voteLayoutAdapter?.refreshDataAfterVotedSuccess(position) 38 | } 39 | 40 | override fun onVoteItemClick(mainVote: VoteBean?, voteOption: VoteOption?, position: Int) { 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/WaveByBezierActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | import com.allen.androidcustomview.R; 7 | import com.allen.androidcustomview.widget.WaveViewByBezier; 8 | 9 | public class WaveByBezierActivity extends AppCompatActivity { 10 | 11 | private WaveViewByBezier waveViewByBezier; 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_wave_by_bezier); 17 | 18 | waveViewByBezier = (WaveViewByBezier) findViewById(R.id.wave_bezier); 19 | 20 | waveViewByBezier.startAnimation(); 21 | } 22 | 23 | @Override 24 | protected void onPause() { 25 | super.onPause(); 26 | waveViewByBezier.pauseAnimation(); 27 | } 28 | 29 | @Override 30 | protected void onResume() { 31 | super.onResume(); 32 | waveViewByBezier.resumeAnimation(); 33 | } 34 | 35 | 36 | @Override 37 | protected void onDestroy() { 38 | super.onDestroy(); 39 | waveViewByBezier.stopAnimation(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/activity/WaveBySinCosActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.activity; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | import com.allen.androidcustomview.R; 7 | 8 | public class WaveBySinCosActivity extends AppCompatActivity { 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | setContentView(R.layout.activity_wave_by_sin_cos); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/adapter/HoverAdapter.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.adapter; 2 | 3 | import android.support.annotation.Nullable; 4 | 5 | import com.allen.androidcustomview.R; 6 | import com.allen.androidcustomview.bean.UserBean; 7 | import com.chad.library.adapter.base.BaseQuickAdapter; 8 | import com.chad.library.adapter.base.BaseViewHolder; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | *
14 |  *      @author : xiaoyao
15 |  *      e-mail  : xiaoyao@51vest.com
16 |  *      date    : 2018/04/16
17 |  *      desc    :
18 |  *      version : 1.0
19 |  * 
20 | */ 21 | 22 | public class HoverAdapter extends BaseQuickAdapter { 23 | 24 | public HoverAdapter( @Nullable List data) { 25 | super(R.layout.adapter_item_hover_user, data); 26 | } 27 | 28 | @Override 29 | protected void convert(BaseViewHolder helper, UserBean item) { 30 | helper.setText(R.id.user_name_tv,item.getUserName()); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/adapter/ItemAnimAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.adapter 2 | 3 | import com.allen.androidcustomview.R 4 | import com.chad.library.adapter.base.BaseQuickAdapter 5 | import com.chad.library.adapter.base.BaseViewHolder 6 | 7 | /** 8 | *
 9 |  *      @author : Allen
10 |  *      e-mail  :lygttpod@163.com
11 |  *      date    : 2019/05/11
12 |  *      desc    :
13 |  * 
14 | */ 15 | class ItemAnimAdapter(list: ArrayList) : BaseQuickAdapter(R.layout.item_danmu_layout, list) { 16 | override fun convert(helper: BaseViewHolder, item: String) { 17 | helper.setText(R.id.content_tv, item) 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/adapter/MainAdapter.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.adapter; 2 | 3 | import android.support.annotation.Nullable; 4 | 5 | import com.allen.androidcustomview.R; 6 | import com.allen.androidcustomview.bean.TypeBean; 7 | import com.chad.library.adapter.base.BaseQuickAdapter; 8 | import com.chad.library.adapter.base.BaseViewHolder; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | *
14 |  *      @author : xiaoyao
15 |  *      e-mail  : xiaoyao@51vest.com
16 |  *      date    : 2018/05/14
17 |  *      desc    :
18 |  *      version : 1.0
19 |  * 
20 | */ 21 | 22 | public class MainAdapter extends BaseQuickAdapter { 23 | 24 | public MainAdapter( @Nullable List data) { 25 | super(R.layout.adapter_item_main, data); 26 | } 27 | 28 | @Override 29 | protected void convert(BaseViewHolder helper, TypeBean item) { 30 | helper.setText(R.id.title_tv,item.getTitle()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/anim/RotateXItemAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.anim 2 | 3 | import android.support.v7.widget.RecyclerView 4 | import android.view.ViewPropertyAnimator 5 | 6 | /** 7 | *
 8 |  *      @author : Allen
 9 |  *      e-mail  : lygttpod@163.com
10 |  *      date    : 2019/05/15
11 |  *      desc    :
12 |  * 
13 | */ 14 | class RotateXItemAnimation(animDuration: Long = 500) : SuperItemAnimation(animDuration) { 15 | 16 | init { 17 | addDuration = animDuration 18 | removeDuration = animDuration 19 | } 20 | 21 | override fun setAddItemAnimInit(holder: RecyclerView.ViewHolder?) { 22 | holder?.itemView?.rotationX = -90f 23 | } 24 | 25 | override fun setAddItemAnim(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) { 26 | animator?.rotationX(0f) 27 | } 28 | 29 | override fun setAddItemAnimCancel(holder: RecyclerView.ViewHolder?) { 30 | holder?.itemView?.rotationX = 0f 31 | } 32 | 33 | override fun setRemoveItemAnim(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) { 34 | animator?.rotationX(-90f) 35 | } 36 | 37 | override fun setRemoveItemAnimEnd(holder: RecyclerView.ViewHolder?) { 38 | holder?.itemView?.rotationX = 0f 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/anim/RotateYItemAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.anim 2 | 3 | import android.support.v7.widget.RecyclerView 4 | import android.view.ViewPropertyAnimator 5 | 6 | /** 7 | *
 8 |  *      @author : Allen
 9 |  *      e-mail  : lygttpod@163.com
10 |  *      date    : 2019/05/15
11 |  *      desc    :
12 |  * 
13 | */ 14 | class RotateYItemAnimation(animDuration: Long = 500) : SuperItemAnimation(animDuration) { 15 | 16 | override fun setAddItemAnimInit(holder: RecyclerView.ViewHolder?) { 17 | holder?.itemView?.rotationY = -90f 18 | } 19 | 20 | override fun setAddItemAnim(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) { 21 | animator?.rotationY(0f) 22 | } 23 | 24 | override fun setAddItemAnimCancel(holder: RecyclerView.ViewHolder?) { 25 | holder?.itemView?.rotationY = 0f 26 | } 27 | 28 | override fun setRemoveItemAnim(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) { 29 | animator?.rotationY(-90f) 30 | } 31 | 32 | override fun setRemoveItemAnimEnd(holder: RecyclerView.ViewHolder?) { 33 | holder?.itemView?.rotationY = 0f 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/anim/ScaleItemAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.anim 2 | 3 | import android.support.v7.widget.RecyclerView 4 | import android.view.ViewPropertyAnimator 5 | 6 | /** 7 | *
 8 |  *      @author : Allen
 9 |  *      e-mail  : lygttpod@163.com
10 |  *      date    : 2019/05/15
11 |  *      desc    :
12 |  * 
13 | */ 14 | class ScaleItemAnimation(animDuration: Long = 500) : SuperItemAnimation(animDuration) { 15 | 16 | override fun setAddItemAnimInit(holder: RecyclerView.ViewHolder?) { 17 | holder?.itemView?.scaleX = 0f 18 | holder?.itemView?.scaleY = 0f 19 | } 20 | 21 | override fun setAddItemAnim(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) { 22 | holder?.itemView?.pivotX = 0f 23 | holder?.itemView?.pivotY = 0f 24 | animator?.scaleX(1f)?.scaleY(1f) 25 | } 26 | 27 | override fun setAddItemAnimCancel(holder: RecyclerView.ViewHolder?) { 28 | holder?.itemView?.scaleX = 1f 29 | holder?.itemView?.scaleY = 1f 30 | } 31 | 32 | override fun setRemoveItemAnim(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) { 33 | holder?.itemView?.pivotX = 1f 34 | holder?.itemView?.pivotY = 1f 35 | animator?.scaleX(0f)?.scaleY(0f) 36 | } 37 | 38 | override fun setRemoveItemAnimEnd(holder: RecyclerView.ViewHolder?) { 39 | holder?.itemView?.scaleX = 1f 40 | holder?.itemView?.scaleY = 1f 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/anim/SlideItemAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.anim 2 | 3 | import android.support.v7.widget.RecyclerView 4 | import android.view.ViewPropertyAnimator 5 | 6 | /** 7 | *
 8 |  *      @author : Allen
 9 |  *      e-mail  : lygttpod@163.com
10 |  *      date    : 2019/05/15
11 |  *      desc    :
12 |  * 
13 | */ 14 | class SlideItemAnimation(animDuration: Long = 500) : SuperItemAnimation(animDuration) { 15 | 16 | override fun setAddItemAnimInit(holder: RecyclerView.ViewHolder?) { 17 | val with = holder?.itemView?.width ?: 0 18 | holder?.itemView?.translationX = -with.toFloat() 19 | } 20 | 21 | override fun setAddItemAnim(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) { 22 | animator?.translationX(0f) 23 | } 24 | 25 | override fun setAddItemAnimCancel(holder: RecyclerView.ViewHolder?) { 26 | holder?.itemView?.translationX = 0f 27 | } 28 | 29 | override fun setRemoveItemAnim(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) { 30 | val with = holder?.itemView?.width ?: 0 31 | animator?.translationX(-with.toFloat()) 32 | } 33 | 34 | override fun setRemoveItemAnimEnd(holder: RecyclerView.ViewHolder?) { 35 | holder?.itemView?.translationX = 0f 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/anim/SuperItemAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.anim 2 | 3 | import android.support.v7.widget.RecyclerView 4 | import android.view.ViewPropertyAnimator 5 | 6 | /** 7 | *
 8 |  *      @author : Allen
 9 |  *      e-mail  : lygttpod@163.com
10 |  *      date    : 2019/05/15
11 |  *      desc    :
12 |  * 
13 | */ 14 | abstract class SuperItemAnimation(animDuration: Long = 200) : BaseItemAnimation() { 15 | 16 | init { 17 | addDuration = animDuration 18 | removeDuration = animDuration 19 | } 20 | 21 | abstract fun setAddItemAnimInit(holder: RecyclerView.ViewHolder?) 22 | abstract fun setAddItemAnim(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) 23 | abstract fun setAddItemAnimCancel(holder: RecyclerView.ViewHolder?) 24 | 25 | abstract fun setRemoveItemAnim(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) 26 | abstract fun setRemoveItemAnimEnd(holder: RecyclerView.ViewHolder?) 27 | 28 | 29 | override fun setAddItemAnimationInit(holder: RecyclerView.ViewHolder?) { 30 | setAddItemAnimInit(holder) 31 | } 32 | 33 | override fun setAddItemAnimation(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) { 34 | setAddItemAnim(holder, animator) 35 | } 36 | 37 | override fun setAddItemAnimationCancel(holder: RecyclerView.ViewHolder?) { 38 | setAddItemAnimCancel(holder) 39 | } 40 | 41 | override fun setRemoveAnimation(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) { 42 | setRemoveItemAnim(holder, animator) 43 | } 44 | 45 | override fun setRemoveAnimationEnd(holder: RecyclerView.ViewHolder?) { 46 | setRemoveItemAnimEnd(holder) 47 | } 48 | 49 | 50 | override fun setOldChangeAnimation(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) { 51 | animator?.alpha(0f) 52 | } 53 | 54 | override fun setOldChangeAnimationEnd(holder: RecyclerView.ViewHolder?) { 55 | holder?.itemView?.alpha = 1f 56 | } 57 | 58 | override fun setNewChangeAnimationInit(holder: RecyclerView.ViewHolder?) { 59 | holder?.itemView?.alpha = 0f 60 | } 61 | 62 | override fun setNewChangeAnimation(holder: RecyclerView.ViewHolder?, animator: ViewPropertyAnimator?) { 63 | animator?.alpha(1f) 64 | } 65 | 66 | override fun setNewChangeAnimationEnd(holder: RecyclerView.ViewHolder?) { 67 | holder?.itemView?.alpha = 1f 68 | } 69 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/bean/CircleBean.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.bean; 2 | 3 | import android.graphics.PointF; 4 | 5 | /** 6 | * Created by allen on 2016/12/9. 7 | */ 8 | 9 | public class CircleBean { 10 | 11 | /** 12 | * 真实轨迹坐标点 13 | */ 14 | PointF p; 15 | /** 16 | * 起点坐标 17 | */ 18 | PointF p0; 19 | /** 20 | * 进入动画的控制点坐标 21 | */ 22 | PointF p1; 23 | /** 24 | * 到达中心点做坐标 25 | */ 26 | PointF p2; 27 | /** 28 | * 飞出动画控制点的坐标 29 | */ 30 | PointF p3; 31 | /** 32 | * 结束位置坐标 33 | */ 34 | PointF p4; 35 | 36 | /** 37 | * 小球半径 38 | */ 39 | private float radius; 40 | /** 41 | * 圆圈的透明度 42 | */ 43 | private int alpha; 44 | 45 | 46 | public CircleBean(PointF p0, PointF p1, PointF p2, PointF p3, PointF p4, float radius, int alpha) { 47 | this.p0 = p0; 48 | this.p1 = p1; 49 | this.p2 = p2; 50 | this.p3 = p3; 51 | this.p4 = p4; 52 | this.radius = radius; 53 | this.alpha = alpha; 54 | } 55 | 56 | public int getAlpha() { 57 | return alpha; 58 | } 59 | 60 | public void setAlpha(int alpha) { 61 | this.alpha = alpha; 62 | } 63 | 64 | public PointF getP4() { 65 | return p4; 66 | } 67 | 68 | public void setP4(PointF p4) { 69 | this.p4 = p4; 70 | } 71 | 72 | public PointF getP3() { 73 | return p3; 74 | } 75 | 76 | public void setP3(PointF p3) { 77 | this.p3 = p3; 78 | } 79 | 80 | public PointF getP2() { 81 | return p2; 82 | } 83 | 84 | public void setP2(PointF p2) { 85 | this.p2 = p2; 86 | } 87 | 88 | public PointF getP1() { 89 | return p1; 90 | } 91 | 92 | public void setP1(PointF p1) { 93 | this.p1 = p1; 94 | } 95 | 96 | public PointF getP0() { 97 | return p0; 98 | } 99 | 100 | public void setP0(PointF p0) { 101 | this.p0 = p0; 102 | } 103 | 104 | public PointF getP() { 105 | return p; 106 | } 107 | 108 | public void setP(PointF p) { 109 | this.p = p; 110 | } 111 | 112 | public float getRadius() { 113 | return radius; 114 | } 115 | 116 | public void setRadius(float radius) { 117 | this.radius = radius; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/bean/TypeBean.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.bean; 2 | 3 | /** 4 | *
 5 |  *      @author : xiaoyao
 6 |  *      e-mail  : xiaoyao@51vest.com
 7 |  *      date    : 2018/05/14
 8 |  *      desc    :
 9 |  *      version : 1.0
10 |  * 
11 | */ 12 | 13 | public class TypeBean { 14 | private String title; 15 | private int type; 16 | 17 | public TypeBean(String title, int type) { 18 | this.title = title; 19 | this.type = type; 20 | } 21 | 22 | public String getTitle() { 23 | return title; 24 | } 25 | 26 | public void setTitle(String title) { 27 | this.title = title; 28 | } 29 | 30 | public int getType() { 31 | return type; 32 | } 33 | 34 | public void setType(int type) { 35 | this.type = type; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/bean/UserBean.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.bean; 2 | 3 | /** 4 | *
 5 |  *      @author : xiaoyao
 6 |  *      e-mail  : xiaoyao@51vest.com
 7 |  *      date    : 2018/04/16
 8 |  *      desc    :
 9 |  *      version : 1.0
10 |  * 
11 | */ 12 | 13 | public class UserBean { 14 | private String userName; 15 | private String sortLetters=""; 16 | 17 | 18 | public String getUserName() { 19 | return userName; 20 | } 21 | 22 | public void setUserName(String userName) { 23 | this.userName = userName; 24 | } 25 | 26 | public String getSortLetters() { 27 | return sortLetters; 28 | } 29 | 30 | public void setSortLetters(String sortLetters) { 31 | this.sortLetters = sortLetters; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/bean/VoteBean.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.bean 2 | 3 | 4 | /** 5 | *
 6 |  *      @author : Allen
 7 |  *      date    : 2019/08/01
 8 |  *      desc    :
 9 |  * 
10 | */ 11 | 12 | class VoteBean(val id: Int = 0, 13 | val title: String?, 14 | val choiceType: String?, 15 | val maxSelect: Int?, 16 | var voted: Boolean?, 17 | val sumVoteCount: Int?, 18 | val options: ArrayList? 19 | ) 20 | 21 | data class VoteOption(var id: Int?, 22 | var content: String?, 23 | var voteId: Int?, 24 | var showCount: Int?, 25 | var voted: Boolean?) -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/bean/WaveBean.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.bean; 2 | 3 | /** 4 | * Created by allen on 2016/12/14. 5 | * 水波参数的实体 6 | */ 7 | 8 | public class WaveBean { 9 | 10 | private int waveLength; 11 | 12 | private int waveAmplitude; 13 | 14 | private int waveColor; 15 | 16 | private int waveType; 17 | 18 | private int duration; 19 | 20 | public int getWaveLength() { 21 | return waveLength; 22 | } 23 | 24 | public void setWaveLength(int waveLength) { 25 | this.waveLength = waveLength; 26 | } 27 | 28 | public int getWaveAmplitude() { 29 | return waveAmplitude; 30 | } 31 | 32 | public void setWaveAmplitude(int waveAmplitude) { 33 | this.waveAmplitude = waveAmplitude; 34 | } 35 | 36 | public int getWaveColor() { 37 | return waveColor; 38 | } 39 | 40 | public void setWaveColor(int waveColor) { 41 | this.waveColor = waveColor; 42 | } 43 | 44 | public int getWaveType() { 45 | return waveType; 46 | } 47 | 48 | public void setWaveType(int waveType) { 49 | this.waveType = waveType; 50 | } 51 | 52 | public int getDuration() { 53 | return duration; 54 | } 55 | 56 | public void setDuration(int duration) { 57 | this.duration = duration; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/data/VoteData.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.data 2 | 3 | import com.allen.androidcustomview.bean.VoteBean 4 | import com.allen.androidcustomview.bean.VoteOption 5 | import kotlin.random.Random 6 | 7 | /** 8 | *
 9 |  *      @author : Allen
10 |  *      date    : 2019/08/06
11 |  *      desc    :
12 |  * 
13 | */ 14 | 15 | fun getMockData(): ArrayList { 16 | val list: ArrayList = arrayListOf() 17 | for (i in 0..1) 18 | list.add(getVoteBeanData(i)) 19 | return list 20 | } 21 | 22 | private fun getVoteBeanData(index: Int): VoteBean { 23 | val voteTitle: String = when (index) { 24 | 0 -> "哪吒票房能否突破30亿(多选)" 25 | 1 -> "你觉得谁最火呢?(单选)" 26 | else -> "" 27 | } 28 | return VoteBean(11, voteTitle, if (index == 0) "multiple" else "single", 2, false, Random.nextInt(10000, 20000), getVoteOptionsDatas(index)) 29 | } 30 | 31 | private fun getVoteOptionsDatas(index: Int): java.util.ArrayList? { 32 | var list: ArrayList = arrayListOf() 33 | for (i in 0..3) 34 | list.add(getVoteOptionData(index, i)) 35 | return list 36 | 37 | } 38 | 39 | private fun getVoteOptionData(index: Int, i: Int): VoteOption { 40 | 41 | val voteContent: String = when (i) { 42 | 0 -> if (index == 0) "当然可以" else "蔡徐坤" 43 | 1 -> if (index == 0) "估计不能" else "肖战" 44 | 2 -> if (index == 0) "拭目以待" else "李现" 45 | 3 -> if (index == 0) "保持中立" else "邓伦" 46 | else -> "" 47 | } 48 | return VoteOption(i, voteContent, i, Random.nextInt(6666,8888), false) 49 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/helper/DragViewHelper.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.helper 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.ImageView 8 | import android.widget.RelativeLayout 9 | import com.allen.androidcustomview.R 10 | import com.allen.androidcustomview.listener.OnDragTouchListener 11 | import com.allen.androidcustomview.utils.DisplayUtils 12 | 13 | /** 14 | *
15 |  *      @author : Allen
16 |  *      e-mail  : lygttpod@163.com
17 |  *      date    : 2019/03/14
18 |  *      desc    : 拖拽view辅助类
19 |  * 
20 | */ 21 | object DragViewHelper { 22 | 23 | @SuppressLint("ClickableViewAccessibility") 24 | fun addDragView(context: Context, 25 | parent: ViewGroup, 26 | imgUrl: String, 27 | defaultImgResId: Int = R.mipmap.ic_launcher, 28 | dragViewSize: Float = 60f, 29 | dragViewOriginalMarginRight: Float = 20f, 30 | dragViewOriginalMarginBottom: Float = 20f, 31 | autoPullToBorder: Boolean = true, 32 | onClick: (() -> Unit)? = null): ImageView { 33 | val dragView = ImageView(context) 34 | parent.post { 35 | val onDragTouchListener = OnDragTouchListener() 36 | onDragTouchListener.clickListener = { 37 | onClick?.invoke() 38 | } 39 | onDragTouchListener.mMaxWidth = parent.width 40 | onDragTouchListener.mMaxHeight = parent.height 41 | onDragTouchListener.mBorderMargin = DisplayUtils.dip2px(context, 15f).toFloat() 42 | onDragTouchListener.mIsAutoToBorder = autoPullToBorder 43 | dragView.scaleType = ImageView.ScaleType.CENTER_CROP 44 | dragView.setOnTouchListener(onDragTouchListener) 45 | val layoutParams = RelativeLayout.LayoutParams(DisplayUtils.dip2px(context, dragViewSize), DisplayUtils.dip2px(context, dragViewSize)) 46 | layoutParams.leftMargin = parent.width - DisplayUtils.dip2px(context, dragViewSize + dragViewOriginalMarginRight) 47 | layoutParams.topMargin = parent.height - DisplayUtils.dip2px(context, dragViewSize + dragViewOriginalMarginBottom) 48 | // GlideApp.with(context).load(imgUrl).into(dragView) 49 | dragView.setBackgroundResource(defaultImgResId) 50 | parent.addView(dragView, layoutParams) 51 | } 52 | 53 | return dragView 54 | } 55 | 56 | fun removeDragView(parent: ViewGroup, view: View?) { 57 | if (view != null) { 58 | parent.removeView(view) 59 | } 60 | } 61 | 62 | fun updateDragView(context: Context, dragView: ImageView?, imgUrl: String) { 63 | if (dragView != null) { 64 | // GlideApp.with(context).load(imgUrl).into(dragView) 65 | } 66 | } 67 | 68 | 69 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/tagview/TagActivity.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.tagview; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.GridLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | 8 | import com.allen.androidcustomview.R; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class TagActivity extends AppCompatActivity { 14 | 15 | private RecyclerView tagRecyclerView; 16 | 17 | private static final int MAX = 9; 18 | private List tagBeanList = new ArrayList<>(); 19 | 20 | private TagAdapter tagAdapter; 21 | 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_tag); 27 | 28 | initView(); 29 | initData(); 30 | setRecyclerView(); 31 | } 32 | 33 | private void initData() { 34 | tagBeanList.add(new TagBean("1","准时")); 35 | tagBeanList.add(new TagBean("2","非常绅士")); 36 | tagBeanList.add(new TagBean("3","非常有礼貌")); 37 | tagBeanList.add(new TagBean("4","很会照顾女生")); 38 | tagBeanList.add(new TagBean("5","我的男神是个大暖男哦")); 39 | tagBeanList.add(new TagBean("6","谈吐优雅")); 40 | tagBeanList.add(new TagBean("7","送我到楼下")); 41 | tagBeanList.add(new TagBean("9","迟到")); 42 | tagBeanList.add(new TagBean("10","态度恶劣")); 43 | tagBeanList.add(new TagBean("11","有不礼貌行为")); 44 | tagBeanList.add(new TagBean("12","有侮辱性语言有暴力倾向")); 45 | tagBeanList.add(new TagBean("13","人身攻击")); 46 | tagBeanList.add(new TagBean("14","临时改变行程")); 47 | tagBeanList.add(new TagBean("15","客户迟到并无理要求延长约会时间")); 48 | } 49 | 50 | private void setRecyclerView() { 51 | GridLayoutManager layoutManage = new GridLayoutManager(this, 2); 52 | layoutManage.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 53 | @Override 54 | public int getSpanSize(int position) { 55 | if (tagBeanList.get(position).getTag_name().length()>MAX) 56 | return 2; 57 | return 1; 58 | } 59 | }); 60 | tagRecyclerView.setLayoutManager(layoutManage); 61 | tagAdapter = new TagAdapter(tagBeanList); 62 | tagRecyclerView.setAdapter(tagAdapter); 63 | 64 | } 65 | 66 | private void initView() { 67 | tagRecyclerView = (RecyclerView) findViewById(R.id.tag_rv); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/tagview/TagAdapter.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.tagview; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | 10 | import com.allen.androidcustomview.R; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * Created by Allen on 2017/4/14. 17 | * 18 | * 评论页面的适配器 19 | */ 20 | 21 | public class TagAdapter extends RecyclerView.Adapter { 22 | 23 | private List tagList; 24 | 25 | private boolean isSelected = false; 26 | 27 | private List selectList; 28 | 29 | public TagAdapter(List tagList) { 30 | this.tagList = tagList; 31 | selectList = new ArrayList<>(); 32 | } 33 | 34 | @Override 35 | public TagAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 36 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.tag_layout, parent, false); 37 | ViewHolder vh = new ViewHolder(view); 38 | return vh; 39 | } 40 | 41 | @Override 42 | public void onBindViewHolder(final TagAdapter.ViewHolder holder, final int position) { 43 | holder.mTextView.setText(tagList.get(position).getTag_name()); 44 | holder.itemView.setTag(tagList.get(position)); 45 | holder.mTextView.setOnClickListener(new View.OnClickListener() { 46 | @Override 47 | public void onClick(View v) { 48 | isSelected = !holder.mTextView.isSelected(); 49 | if (isSelected) { 50 | holder.mTextView.setSelected(true); 51 | holder.mTextView.setBackgroundResource(R.drawable.tag_checked_bg); 52 | selectList.add(tagList.get(position)); 53 | } else { 54 | holder.mTextView.setSelected(false); 55 | holder.mTextView.setBackgroundResource(R.drawable.tag_normal_bg); 56 | selectList.remove(tagList.get(position)); 57 | } 58 | } 59 | }); 60 | 61 | } 62 | 63 | @Override 64 | public int getItemCount() { 65 | return tagList.size(); 66 | } 67 | 68 | public class ViewHolder extends RecyclerView.ViewHolder { 69 | public TextView mTextView; 70 | 71 | public ViewHolder(View view) { 72 | super(view); 73 | mTextView = (TextView) view.findViewById(R.id.tag_tv); 74 | } 75 | } 76 | 77 | public List getSelectData(){ 78 | return selectList; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/tagview/TagBean.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.tagview; 2 | 3 | /** 4 | * Created by Allen on 2017/4/15. 5 | * 6 | */ 7 | 8 | public class TagBean { 9 | 10 | public TagBean(String tag_id, String tag_name) { 11 | this.tag_id = tag_id; 12 | this.tag_name = tag_name; 13 | } 14 | 15 | /** 16 | * tag_id : 55 17 | * tag_name : 准时 18 | */ 19 | 20 | 21 | private String tag_id; 22 | private String tag_name; 23 | 24 | public String getTag_id() { 25 | return tag_id; 26 | } 27 | 28 | public void setTag_id(String tag_id) { 29 | this.tag_id = tag_id; 30 | } 31 | 32 | public String getTag_name() { 33 | return tag_name; 34 | } 35 | 36 | public void setTag_name(String tag_name) { 37 | this.tag_name = tag_name; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/tagview/recyclerview.md: -------------------------------------------------------------------------------- 1 | ###一、需求解析 2 | 1、先说下项目需求,不管是好评还是差评下边的Tag标签有不同的展示类型,有的字数多的会单独占一行处理(这边其实也可以扩充,比如说两三个字的可以一行显示三个Tag标签),第一眼看到这个需求准备使用网上的开源库TagLayout去实现,但是尝试了一下后发现其实他们实现的效果同项目要的效果还是有蛮大差距的,可以看到效果图里边是要求文字是居中对齐的,左右对称的。 3 | 2、想到使用GridView实现这个功能,定义adapter去实现没问题,问题是什么时候显示一行什么时候显示两行三行并不能确定,毕竟有时候服务端返回的没有类型标示只有tag_name和tag_id,你要根据什么设置类型呐,而且自从recyclerview之后现在要是还用GridView的话岂不是太落伍了。下边就重点介绍一下使用recyclerview实现如图效果。 4 | ###二、功能实现 5 | 我们知道recyclerview实现GridView效果只需配置一下参数就行了 6 | 7 | GridLayoutManager layoutManage = new GridLayoutManager(getContext(), 2); 8 | recycerView.setLayoutManager(layoutManage); 9 | 10 | 可以看到GridLayoutManager需要传递两个参数,一个是上下文对象,另一个是一行显示几列的参数常量,既然这个常量可以指定那么是不是这个值可以去控制呐,答案当然是yes 11 | 12 | 我们会注意到GridLayoutManager里边有个setSpanSizeLookup方法,本篇的重点就是这个方法(这个方法具体意义大家可以网上搜索,会有很多相关介绍,以及通过它实现一些复杂的布局,再次不做过多讨论) 13 | 14 | layoutManage.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 15 | @Override 16 | public int getSpanSize(int position) { 17 | return 0; 18 | } 19 | }); 20 | 21 | 其实getSpanSize返回值就是控制每行有几列的,根据这个思路我们不妨试试。因为recyclerview填充数据是根据adapter实现的,我们就把给adapter的数据源同样在setSpanSizeLookup这个方法里边判断一下不就行了吗? 22 | 根据这个思路于是有了下面的代码 23 | 24 | 25 | /** 26 | * 如果单个item显示的字数大于指定某个值就显示一列 默认2列 27 | */ 28 | 29 | //设置item数据大于多少字只显示一行 默认 超过九个字的程度只显示一列 30 | 31 | private static final int MAX = 9; 32 | 33 | 34 | private int setSpanSize(int position, List listEntities) { 35 | int count; 36 | if (listEntities.get(position).getTag_name().length() > MAX) { 37 | count = 2; 38 | } else { 39 | count = 1; 40 | } 41 | 42 | return count; 43 | } 44 | 45 | 46 | layoutManage.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 47 | @Override 48 | public int getSpanSize(int position) { 49 | return setSpanSize(position,list); 50 | } 51 | }); 52 | 53 | 54 | 核心代码就这么多,我们可以根据自己的需求随意定制样式 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/utils/BezierUtil.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.utils; 2 | 3 | import android.graphics.PointF; 4 | 5 | /** 6 | * Created by allen on 2016/12/15. 7 | *

8 | * 贝塞尔曲线计算工具类 9 | */ 10 | 11 | public class BezierUtil { 12 | 13 | 14 | /** 15 | * 二阶贝塞尔曲线 16 | * B(t) = Po*(1-t)^2 + 2*p1*t*(1-t)+t^2*p2 17 | * 18 | * @param t 曲线长度比例 19 | * @param p0 起始点 20 | * @param p1 控制点 21 | * @param p2 终止点 22 | * @return t对应的点 23 | */ 24 | public static PointF CalculateBezierPointForQuadratic(float t, PointF p0, PointF p1, PointF p2) { 25 | PointF point = new PointF(); 26 | float temp = 1 - t; 27 | // point.x = temp * temp * p0.x + 2 * t * temp * p1.x + t * t * p2.x; 28 | // point.y = temp * temp * p0.y + 2 * t * temp * p1.y + t * t * p2.y; 29 | point.x = (float) (Math.pow(temp, 2) * p0.x + 2 * t * temp * p1.x + Math.pow(t, 2) * p2.x); 30 | point.y = (float) (Math.pow(temp, 2) * p0.y + 2 * t * temp * p1.y + Math.pow(t, 2) * p2.y); 31 | return point; 32 | } 33 | 34 | /** 35 | * 三 36 | * 阶贝塞尔曲线 37 | * B(t) = Po*(1-t)^3 + 3*p1*t*(1-t)^2+3*p2*t^2*(1-t)+p3*t^3, 38 | * 39 | * @param t 曲线长度比例 40 | * @param p0 起始点 41 | * @param p1 控制点1 42 | * @param p2 控制点2 43 | * @param p3 终止点 44 | * @return t对应的点 45 | */ 46 | public static PointF CalculateBezierPointForCubic(float t, PointF p0, PointF p1, PointF p2, PointF p3) { 47 | PointF point = new PointF(); 48 | float temp = 1 - t; 49 | // point.x = p0.x * temp * temp * temp + 3 * p1.x * t * temp * temp + 3 * p2.x * t * t * temp + p3.x * t * t * t; 50 | // point.y = p0.y * temp * temp * temp + 3 * p1.y * t * temp * temp + 3 * p2.y * t * t * temp + p3.y * t * t * t; 51 | point.x = (float) (p0.x * Math.pow(temp, 3) + 3 * p1.x * t * Math.pow(temp, 2) + 3 * p2.x * Math.pow(t, 2) * temp + p3.x * Math.pow(t, 3)); 52 | point.y = (float) (p0.y * Math.pow(temp, 3) + 3 * p1.y * t * Math.pow(temp, 2) + 3 * p2.y * Math.pow(t, 2) * temp + p3.y * Math.pow(t, 3)); 53 | return point; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/utils/DisplayUtils.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.utils; 2 | 3 | import android.content.Context; 4 | import android.util.DisplayMetrics; 5 | import android.view.WindowManager; 6 | 7 | /** 8 | * 与屏幕信息有关的类,包括屏幕的长宽、分辨率、长度换算 9 | * 10 | */ 11 | public class DisplayUtils { 12 | 13 | 14 | /** 15 | * 获取屏幕分辨率 16 | * @param context 17 | * @return 18 | */ 19 | public static int[] getScreenDispaly(Context context) { 20 | WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 21 | int width = windowManager.getDefaultDisplay().getWidth();// 手机屏幕的宽度 22 | int height = windowManager.getDefaultDisplay().getHeight();// 手机屏幕的高度 23 | int result[] = { width, height }; 24 | return result; 25 | } 26 | 27 | /** 获取屏幕宽度 */ 28 | public static int getDisplayWidth(Context context) { 29 | if (context != null) { 30 | DisplayMetrics dm = context.getResources().getDisplayMetrics(); 31 | int w_screen = dm.widthPixels; 32 | // int h_screen = dm.heightPixels; 33 | return w_screen; 34 | } 35 | return 720; 36 | } 37 | 38 | /** 获取屏幕高度 */ 39 | public static int getDisplayHight(Context context) { 40 | if (context != null) { 41 | DisplayMetrics dm = context.getResources().getDisplayMetrics(); 42 | // int w_screen = dm.widthPixels; 43 | int h_screen = dm.heightPixels; 44 | return h_screen; 45 | } 46 | return 1280; 47 | } 48 | 49 | public static int dip2px(Context context, float dipValue) { 50 | final float scale = context.getResources().getDisplayMetrics().density; 51 | return (int) (dipValue * scale + 0.5f); 52 | } 53 | 54 | public static int px2dip(Context context, float pxValue) { 55 | final float scale = context.getResources().getDisplayMetrics().density; 56 | return (int) (pxValue / scale + 0.5f); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/utils/FingerprintUtil.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.utils; 2 | 3 | import android.app.KeyguardManager; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.support.v4.hardware.fingerprint.FingerprintManagerCompat; 8 | import android.support.v4.os.CancellationSignal; 9 | 10 | /** 11 | * Created by xiaoyao on 2017/9/14. 12 | * 指纹识别工具类 13 | */ 14 | 15 | public class FingerprintUtil { 16 | 17 | private static CancellationSignal cancellationSignal; 18 | 19 | public static void callFingerPrint(Context context, final OnCallBackListener listener) { 20 | 21 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 22 | return; 23 | } 24 | FingerprintManagerCompat managerCompat = FingerprintManagerCompat.from(context); 25 | if (!managerCompat.isHardwareDetected()) { //判断设备是否支持 26 | if (listener != null) 27 | listener.onSupportFailed(); 28 | return; 29 | } 30 | 31 | KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); 32 | if (!keyguardManager.isKeyguardSecure()) {//判断设备是否处于安全保护中 33 | if (listener != null) 34 | listener.onInsecurity(); 35 | return; 36 | } 37 | 38 | if (!managerCompat.hasEnrolledFingerprints()) { //判断设备是否已经注册过指纹 39 | if (listener != null) 40 | listener.onEnrollFailed(); //未注册 41 | return; 42 | } 43 | 44 | if (listener != null) 45 | listener.onAuthenticationStart(); //开始指纹识别 46 | 47 | cancellationSignal = new CancellationSignal(); //必须重新实例化,否则cancel 过一次就不能再使用了 48 | 49 | managerCompat.authenticate(null, 0, cancellationSignal, new FingerprintManagerCompat.AuthenticationCallback() { 50 | // 当出现错误的时候回调此函数,比如多次尝试都失败了的时候,errString是错误信息,比如华为的提示就是:尝试次数过多,请稍后再试。 51 | @Override 52 | public void onAuthenticationError(int errMsgId, CharSequence errString) { 53 | if (listener != null) 54 | listener.onAuthenticationError(errMsgId, errString); 55 | } 56 | 57 | // 当指纹验证失败的时候会回调此函数,失败之后允许多次尝试,失败次数过多会停止响应一段时间然后再停止sensor的工作 58 | @Override 59 | public void onAuthenticationFailed() { 60 | if (listener != null) 61 | listener.onAuthenticationFailed(); 62 | } 63 | 64 | @Override 65 | public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { 66 | if (listener != null) 67 | listener.onAuthenticationHelp(helpMsgId, helpString); 68 | } 69 | 70 | // 当验证的指纹成功时会回调此函数,然后不再监听指纹sensor 71 | @Override 72 | public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) { 73 | if (listener != null) 74 | listener.onAuthenticationSucceeded(result); 75 | } 76 | }, null); 77 | 78 | } 79 | 80 | public interface OnCallBackListener { 81 | void onSupportFailed(); 82 | 83 | void onInsecurity(); 84 | 85 | void onEnrollFailed(); 86 | 87 | void onAuthenticationStart(); 88 | 89 | void onAuthenticationError(int errMsgId, CharSequence errString); 90 | 91 | void onAuthenticationFailed(); 92 | 93 | void onAuthenticationHelp(int helpMsgId, CharSequence helpString); 94 | 95 | void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result); 96 | } 97 | 98 | public static void cancel() { 99 | if (cancellationSignal != null) 100 | cancellationSignal.cancel(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/utils/PinyinComparator.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.utils; 2 | 3 | 4 | import com.allen.androidcustomview.bean.UserBean; 5 | 6 | import java.util.Comparator; 7 | 8 | public class PinyinComparator implements Comparator { 9 | 10 | @Override 11 | public int compare(UserBean o1, UserBean o2) { 12 | if (o1.getSortLetters().equals("@") 13 | || o2.getSortLetters().equals("#")) { 14 | return -1; 15 | } else if (o1.getSortLetters().equals("#") 16 | || o2.getSortLetters().equals("@")) { 17 | return 1; 18 | } else { 19 | return o1.getSortLetters().compareTo(o2.getSortLetters()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/ArcView.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget 2 | 3 | import android.content.Context 4 | import android.graphics.* 5 | import android.util.AttributeSet 6 | import android.view.View 7 | import com.allen.androidcustomview.R 8 | 9 | /** 10 | *

11 |  *      @author : Allen
12 |  *      e-mail  : lygttpod@163.com
13 |  *      date    : 2019/07/07
14 |  *      desc    :
15 |  * 
16 | */ 17 | class ArcView : View { 18 | private var mWidth = 0 19 | private var mHeight = 0 20 | /** 21 | * 弧形高度 22 | */ 23 | private var mArcHeight = 0 24 | /** 25 | * 背景颜色 26 | */ 27 | private var mBgColor = Color.WHITE 28 | private var mPaint = Paint() 29 | private var mContext: Context? = null 30 | 31 | private var mPath = Path() 32 | 33 | constructor(context: Context) : this(context, null) 34 | constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) 35 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { 36 | initView(context, attrs, defStyleAttr) 37 | } 38 | 39 | private fun initView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) { 40 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ArcView) 41 | mArcHeight = typedArray.getDimensionPixelSize(R.styleable.ArcView_arcHeight, 0) 42 | mBgColor = typedArray.getColor(R.styleable.ArcView_bgColor, Color.WHITE) 43 | typedArray.recycle() 44 | 45 | mContext = context 46 | mPaint.style = Paint.Style.FILL_AND_STROKE 47 | mPaint.color = mBgColor 48 | mPaint.isAntiAlias = true 49 | mPaint.strokeWidth = 1f 50 | } 51 | 52 | override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { 53 | super.onSizeChanged(w, h, oldw, oldh) 54 | mWidth = w 55 | mHeight = h 56 | resetPath() 57 | } 58 | 59 | private fun resetPath() { 60 | mPath.reset() 61 | mPath.moveTo(0f, 0f) 62 | mPath.lineTo(0f, (mHeight - mArcHeight).toFloat()) 63 | mPath.quadTo((mWidth / 2).toFloat(), (mHeight + mArcHeight).toFloat(), mWidth.toFloat(), (mHeight - mArcHeight).toFloat()) 64 | mPath.lineTo(mWidth.toFloat(), 0f) 65 | mPath.close() 66 | } 67 | 68 | override fun onDraw(canvas: Canvas?) { 69 | super.onDraw(canvas) 70 | canvas?.drawPath(mPath, mPaint) 71 | } 72 | 73 | fun setArcViewBgColor(color: Int) { 74 | mBgColor = color 75 | mPaint.color = color 76 | invalidate() 77 | } 78 | 79 | fun getArcViewBgColor() = mBgColor 80 | 81 | fun setArcViewHeight(height: Int) { 82 | if (height == mHeight) return 83 | mHeight = height 84 | resetPath() 85 | invalidate() 86 | } 87 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/BaseView.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Paint; 5 | import android.support.annotation.Nullable; 6 | import android.util.AttributeSet; 7 | import android.util.TypedValue; 8 | import android.view.View; 9 | 10 | /** 11 | * Created by xiaoyao on 2017/5/23. 12 | */ 13 | 14 | public class BaseView extends View { 15 | 16 | public int mWidth; 17 | public int mHeight; 18 | public int mViewHeight; 19 | 20 | 21 | public BaseView(Context context) { 22 | this(context, null); 23 | 24 | mViewHeight = dp2px(45); 25 | } 26 | 27 | public BaseView(Context context, @Nullable AttributeSet attrs) { 28 | super(context, attrs); 29 | } 30 | 31 | @Override 32 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 33 | int widthMode = MeasureSpec.getMode(widthMeasureSpec); 34 | int width = MeasureSpec.getSize(widthMeasureSpec); 35 | 36 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 37 | int height = MeasureSpec.getSize(heightMeasureSpec); 38 | 39 | setMeasuredDimension(measureWidth(widthMode, width), measureHeight(heightMode, height)); 40 | } 41 | 42 | /** 43 | * 测量宽度 44 | * 45 | * @param mode 46 | * @param width 47 | * @return 48 | */ 49 | private int measureWidth(int mode, int width) { 50 | switch (mode) { 51 | case MeasureSpec.UNSPECIFIED: 52 | case MeasureSpec.AT_MOST: 53 | break; 54 | case MeasureSpec.EXACTLY: 55 | mWidth = width; 56 | break; 57 | } 58 | return mWidth; 59 | } 60 | 61 | /** 62 | * 测量高度 63 | * 64 | * @param mode 65 | * @param height 66 | * @return 67 | */ 68 | private int measureHeight(int mode, int height) { 69 | switch (mode) { 70 | case MeasureSpec.UNSPECIFIED: 71 | case MeasureSpec.AT_MOST: 72 | mHeight = mViewHeight; 73 | break; 74 | case MeasureSpec.EXACTLY: 75 | mHeight = height; 76 | break; 77 | } 78 | return mHeight; 79 | } 80 | 81 | /** 82 | * 统一处理paint 83 | * @param strokeWidth 84 | * @param color 85 | * @param style 86 | * @return 87 | */ 88 | public Paint getPaint(int strokeWidth, int color, Paint.Style style) { 89 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 90 | paint.setStrokeWidth(strokeWidth); 91 | paint.setColor(color); 92 | paint.setAntiAlias(true); 93 | paint.setStrokeCap(Paint.Cap.ROUND); 94 | paint.setStyle(style); 95 | return paint; 96 | } 97 | 98 | 99 | /** 100 | * dp 2 px 101 | * 102 | * @param dpVal 103 | */ 104 | protected int dp2px(int dpVal) { 105 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 106 | dpVal, getResources().getDisplayMetrics()); 107 | } 108 | 109 | /** 110 | * sp 2 px 111 | * 112 | * @param spVal 113 | * @return 114 | */ 115 | protected int sp2px(int spVal) { 116 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 117 | spVal, getResources().getDisplayMetrics()); 118 | 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/CarMoveView.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget 2 | 3 | import android.animation.Animator 4 | import android.animation.ValueAnimator 5 | import android.content.Context 6 | import android.graphics.* 7 | import android.graphics.drawable.BitmapDrawable 8 | import android.graphics.drawable.Drawable 9 | import android.util.AttributeSet 10 | import android.view.MotionEvent 11 | import android.view.View 12 | import com.allen.androidcustomview.R 13 | import kotlin.math.atan2 14 | 15 | 16 | /** 17 | *
 18 |  *      @author : Allen
 19 |  *      date    : 2019/07/23
 20 |  *      desc    : 小汽车跟随轨迹运动
 21 |  * 
22 | */ 23 | class CarMoveView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) { 24 | 25 | private var mWidth = 0 26 | private var mHeight = 0 27 | 28 | /** 29 | * 背景颜色 30 | */ 31 | private var mPathColor = Color.RED 32 | private var mPaint = Paint() 33 | private var mCarPaint = Paint() 34 | 35 | private var mRect = Rect() 36 | private var mMovePath = Path() 37 | 38 | private var mStartX = 0f 39 | private var mStartY = 0f 40 | 41 | private var pathMeasure: PathMeasure = PathMeasure() 42 | 43 | private val pos = FloatArray(2) 44 | private val tan = FloatArray(2) 45 | 46 | private var isMoveCar = false 47 | 48 | private var mRectWidth = 30 49 | 50 | private var mDuration = 5 51 | private var mCarDrawableRes: Drawable? = null 52 | private var mCarBitmapRes: Bitmap? = null 53 | 54 | init { 55 | initView(context, attrs, defStyleAttr) 56 | initPaint() 57 | mCarBitmapRes = (mCarDrawableRes as? BitmapDrawable)?.bitmap 58 | } 59 | 60 | private fun initView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) { 61 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarMoveView) 62 | mPathColor = typedArray.getColor(R.styleable.CarMoveView_carMovePathColor, mPathColor) 63 | mDuration = typedArray.getInt(R.styleable.CarMoveView_carMoveDuration, mDuration) 64 | mCarDrawableRes = typedArray.getDrawable(R.styleable.CarMoveView_carMoveDrawableRes) 65 | typedArray.recycle() 66 | } 67 | 68 | private fun initPaint() { 69 | mPaint.color = mPathColor 70 | mPaint.style = Paint.Style.STROKE 71 | mPaint.isAntiAlias = true 72 | 73 | mCarPaint.color = mPathColor 74 | mCarPaint.style = Paint.Style.FILL 75 | mCarPaint.isAntiAlias = true 76 | } 77 | 78 | override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { 79 | super.onSizeChanged(w, h, oldw, oldh) 80 | mWidth = w 81 | mHeight = h 82 | } 83 | 84 | override fun onDraw(canvas: Canvas?) { 85 | super.onDraw(canvas) 86 | drawPath(canvas) 87 | drawMoveCar(canvas) 88 | } 89 | 90 | private fun drawPath(canvas: Canvas?) { 91 | canvas?.drawPath(mMovePath, mPaint) 92 | } 93 | 94 | private fun drawMoveCar(canvas: Canvas?) { 95 | pathMeasure.setPath(mMovePath, false) 96 | if (isMoveCar) { 97 | // 计算图片旋转角度 98 | val degrees = (atan2(tan[1].toDouble(), tan[0].toDouble()) * 180.0 / Math.PI).toFloat() 99 | canvas?.rotate(degrees, pos[0], pos[1]) 100 | //小车中心点在运行轨道上 101 | mRect.set((pos[0] - mRectWidth).toInt(), (pos[1] - mRectWidth).toInt(), (pos[0] + mRectWidth).toInt(), (pos[1] + mRectWidth).toInt()) 102 | //小车轮子在运行轨道上 103 | //mRect.set((pos[0] - mRectWidth).toInt(), (pos[1] - mRectWidth * 2).toInt(), (pos[0] + mRectWidth).toInt(), (pos[1]).toInt()) 104 | if (mCarBitmapRes == null) { 105 | canvas?.drawRect(mRect, mCarPaint) 106 | } else { 107 | canvas?.drawBitmap(mCarBitmapRes, null, mRect, mPaint) 108 | } 109 | } 110 | } 111 | 112 | override fun onTouchEvent(event: MotionEvent): Boolean { 113 | when (event.action) { 114 | MotionEvent.ACTION_DOWN -> { 115 | mStartX = event.x 116 | mStartY = event.y 117 | mMovePath.reset() 118 | mMovePath.moveTo(mStartX, mStartY) 119 | return true 120 | } 121 | MotionEvent.ACTION_MOVE -> { 122 | val endX = (mStartX + event.x) / 2 123 | val endY = (mStartY + event.y) / 2 124 | mMovePath.quadTo(mStartX, mStartY, endX, endY) 125 | mStartX = event.x 126 | mStartY = event.y 127 | invalidate() 128 | return true 129 | } 130 | } 131 | return super.onTouchEvent(event) 132 | } 133 | 134 | fun startAnim() { 135 | isMoveCar = true 136 | val valueAnimator = ValueAnimator.ofFloat(0f, pathMeasure.length) 137 | valueAnimator.duration = mDuration * 1000L 138 | valueAnimator.addUpdateListener { 139 | val distance: Float = it.animatedValue as Float 140 | pathMeasure.getPosTan(distance, pos, tan) 141 | invalidate() 142 | } 143 | valueAnimator.addListener(object : Animator.AnimatorListener { 144 | override fun onAnimationRepeat(animation: Animator?) {} 145 | 146 | override fun onAnimationEnd(animation: Animator?) { 147 | isMoveCar = false 148 | } 149 | 150 | override fun onAnimationCancel(animation: Animator?) { 151 | isMoveCar = false 152 | } 153 | 154 | override fun onAnimationStart(animation: Animator?) {} 155 | 156 | }) 157 | valueAnimator.start() 158 | } 159 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/DividerItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Rect; 7 | import android.graphics.drawable.Drawable; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.View; 11 | 12 | /** 13 | *
 14 |  *      @author : xiaoyao
 15 |  *      e-mail  : xiaoyao@51vest.com
 16 |  *      date    : 2018/02/05
 17 |  *      desc    : recyclerview的分割线
 18 |  *      version : 1.0
 19 |  * 
20 | */ 21 | 22 | public class DividerItemDecoration extends RecyclerView.ItemDecoration { 23 | private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; 24 | 25 | public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; 26 | 27 | public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; 28 | 29 | 30 | private Drawable mDivider; 31 | 32 | private int mOrientation; 33 | 34 | private Context context; 35 | 36 | public DividerItemDecoration(Context context, int orientation) { 37 | final TypedArray a = context.obtainStyledAttributes(ATTRS); 38 | mDivider = a.getDrawable(0); 39 | this.context = context; 40 | a.recycle(); 41 | setOrientation(orientation); 42 | } 43 | 44 | public void setOrientation(int orientation) { 45 | if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { 46 | throw new IllegalArgumentException("invalid orientation"); 47 | } 48 | mOrientation = orientation; 49 | } 50 | 51 | @Override 52 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 53 | super.onDraw(c, parent, state); 54 | if (mOrientation == VERTICAL_LIST) { 55 | drawVertical(c, parent); 56 | } else { 57 | drawHorizontal(c, parent); 58 | } 59 | } 60 | 61 | public void drawVertical(Canvas c, RecyclerView parent) { 62 | final int left = parent.getPaddingLeft() + dip2px(context, 0); 63 | final int right = parent.getWidth() - parent.getPaddingRight() - dip2px(context, 0); 64 | 65 | final int childCount = parent.getChildCount(); 66 | 67 | for (int i = 0; i < childCount; i++) { 68 | final View child = parent.getChildAt(i); 69 | android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView( 70 | parent.getContext()); 71 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 72 | .getLayoutParams(); 73 | final int top = child.getBottom() + params.bottomMargin; 74 | final int bottom = top + mDivider.getIntrinsicHeight(); 75 | mDivider.setBounds(left, top, right, bottom); 76 | mDivider.draw(c); 77 | } 78 | } 79 | 80 | public void drawHorizontal(Canvas c, RecyclerView parent) { 81 | final int top = parent.getPaddingTop(); 82 | final int bottom = parent.getHeight() - parent.getPaddingBottom(); 83 | 84 | final int childCount = parent.getChildCount(); 85 | for (int i = 0; i < childCount; i++) { 86 | final View child = parent.getChildAt(i); 87 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 88 | .getLayoutParams(); 89 | final int left = child.getRight() + params.rightMargin; 90 | final int right = left + mDivider.getIntrinsicHeight(); 91 | mDivider.setBounds(left, top, right, bottom); 92 | mDivider.draw(c); 93 | } 94 | } 95 | 96 | @Override 97 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 98 | super.getItemOffsets(outRect, view, parent, state); 99 | if (mOrientation == VERTICAL_LIST) { 100 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); 101 | } else { 102 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); 103 | } 104 | } 105 | 106 | /** 107 | * 单位转换工具类 108 | * 109 | * @param context 上下文对象 110 | * @param dipValue 值 111 | * @return 返回值 112 | */ 113 | private int dip2px(Context context, float dipValue) { 114 | final float scale = context.getResources().getDisplayMetrics().density; 115 | return (int) (dipValue * scale + 0.5f); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/IndexView.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.util.AttributeSet; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | import android.widget.TextView; 10 | 11 | /** 12 | * Created by allen on 2016/10/26. 13 | */ 14 | 15 | public class IndexView extends View { 16 | 17 | private Context mContext; 18 | private TextView mShowTextDialog; 19 | 20 | 21 | private Paint mPaint; 22 | 23 | private int mWidth; 24 | private int mHeight; 25 | 26 | private int mCellWidth; 27 | private int mCellHeight; 28 | 29 | private int mWordSize; 30 | private int mwordColor; 31 | private int mChoose = -1;// 选中 32 | 33 | 34 | private int GRAY = 0xFFe8e8e8; 35 | private int DEFAULT_TEXT_COLOR = 0xFF999999; 36 | 37 | private static final String[] WORDS = new String[]{ 38 | "↑", "☆", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", 39 | "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", 40 | "X", "Y", "Z", "#" 41 | }; 42 | 43 | private OnTouchingLetterChangedListener mOnTouchingLetterChangedListener; 44 | 45 | public IndexView(Context context) { 46 | this(context, null); 47 | } 48 | 49 | public IndexView(Context context, AttributeSet attrs) { 50 | this(context, attrs, 0); 51 | } 52 | 53 | public IndexView(Context context, AttributeSet attrs, int defStyleAttr) { 54 | super(context, attrs, defStyleAttr); 55 | mContext = context; 56 | mWordSize = sp2px(mContext, 12); 57 | mwordColor = 0; 58 | initPaint(); 59 | } 60 | 61 | 62 | public void setShowTextDialog(TextView textDialog) { 63 | this.mShowTextDialog = textDialog; 64 | } 65 | 66 | private void initPaint() { 67 | mPaint = new Paint(); 68 | mPaint.setColor(DEFAULT_TEXT_COLOR); 69 | mPaint.setAntiAlias(true); 70 | mPaint.setTextSize(mWordSize); 71 | } 72 | 73 | @Override 74 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 75 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 76 | mWidth = getMeasuredWidth(); 77 | mHeight = getMeasuredHeight(); 78 | 79 | mCellHeight = mHeight / WORDS.length; 80 | } 81 | 82 | @Override 83 | protected void onDraw(Canvas canvas) { 84 | super.onDraw(canvas); 85 | for (int i = 0; i < WORDS.length; i++) { 86 | float xPos = mWidth / 2 - mPaint.measureText(WORDS[i]) / 2; 87 | float yPos = mCellHeight * i + mCellHeight; 88 | canvas.drawText(WORDS[i], xPos, yPos, mPaint); 89 | } 90 | 91 | } 92 | 93 | @Override 94 | public boolean onTouchEvent(MotionEvent event) { 95 | final int action = event.getAction(); 96 | final float y = event.getY();// 点击y坐标 97 | final int oldChoose = mChoose; 98 | final int c = (int) (y / getHeight() * WORDS.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数. 99 | 100 | 101 | switch (action) { 102 | case MotionEvent.ACTION_UP: 103 | setBackgroundColor(0x00000000); 104 | mChoose = -1;// 105 | invalidate(); 106 | if (mShowTextDialog != null) { 107 | mShowTextDialog.setVisibility(View.INVISIBLE); 108 | } 109 | break; 110 | 111 | default: 112 | setBackgroundColor(GRAY); 113 | if (oldChoose != c) { 114 | if (c >= 0 && c < WORDS.length) { 115 | if (mOnTouchingLetterChangedListener != null) { 116 | mOnTouchingLetterChangedListener.onTouchingLetterChanged(WORDS[c]); 117 | } 118 | if (mShowTextDialog != null) { 119 | mShowTextDialog.setText(WORDS[c]); 120 | mShowTextDialog.setVisibility(View.VISIBLE); 121 | } 122 | 123 | mChoose = c; 124 | invalidate(); 125 | } 126 | } 127 | 128 | break; 129 | } 130 | return true; 131 | } 132 | 133 | 134 | public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener letterChangedListener) { 135 | mOnTouchingLetterChangedListener = letterChangedListener; 136 | 137 | } 138 | 139 | public interface OnTouchingLetterChangedListener { 140 | void onTouchingLetterChanged(String letter); 141 | } 142 | 143 | /** 144 | * 文字字体大小sp转换px 145 | * 146 | * @param context 上下文对象 147 | * @param spValue sp的值 148 | * @return 返回值 149 | */ 150 | public int sp2px(Context context, float spValue) { 151 | final float scale = context.getResources().getDisplayMetrics().scaledDensity; 152 | return (int) (spValue * scale + 0.5f); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/banner/adapter/BannerViewPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget.banner.adapter; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v4.view.PagerAdapter; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import com.allen.androidcustomview.widget.banner.listener.OnPageClickListener; 9 | import com.allen.androidcustomview.widget.banner.holder.BannerViewHolder; 10 | import com.allen.androidcustomview.widget.banner.holder.BannerViewHolderCreator; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | *
 17 |  *      @author : xiaoyao
 18 |  *      e-mail  : xiaoyao@51vest.com
 19 |  *      date    : 2018/03/02
 20 |  *      desc    :
 21 |  *      version : 1.0
 22 |  * 
23 | */ 24 | 25 | public class BannerViewPagerAdapter extends PagerAdapter { 26 | 27 | private List mData; 28 | private BannerViewHolderCreator mCreator; 29 | private OnPageClickListener mPageClickListener; 30 | 31 | public BannerViewPagerAdapter(@NonNull List data, @NonNull BannerViewHolderCreator creator) { 32 | 33 | if (mData == null) { 34 | mData = new ArrayList<>(); 35 | } 36 | mData = data; 37 | mCreator = creator; 38 | } 39 | 40 | @Override 41 | public boolean isViewFromObject(View view, Object object) { 42 | return view == object; 43 | } 44 | 45 | @Override 46 | public Object instantiateItem(ViewGroup container, final int position) { 47 | View view = getView(position, container); 48 | container.addView(view); 49 | return view; 50 | } 51 | 52 | @Override 53 | public void destroyItem(ViewGroup container, int position, Object object) { 54 | container.removeView((View) object); 55 | } 56 | 57 | 58 | 59 | /** 60 | * 获取真实的Count 61 | * 62 | * @return 63 | */ 64 | public int getRealCount() { 65 | return mData == null ? 0 : mData.size(); 66 | } 67 | 68 | @Override 69 | public int getCount() { 70 | return getRealCount(); 71 | } 72 | 73 | /** 74 | * @param position 75 | * @param container 76 | * @return 77 | */ 78 | private View getView(int position, ViewGroup container) { 79 | 80 | final int realPosition = position % getRealCount(); 81 | BannerViewHolder holder = null; 82 | // create holder 83 | holder = mCreator.createViewHolder(); 84 | 85 | if (holder == null) { 86 | throw new RuntimeException("can not return a null holder"); 87 | } 88 | // create View 89 | View view = holder.createView(container.getContext()); 90 | 91 | if (mData != null && mData.size() > 0) { 92 | holder.onBind(container.getContext(), realPosition, mData.get(realPosition)); 93 | } 94 | 95 | // 添加page点击事件 96 | if (view != null) { 97 | view.setOnClickListener(new View.OnClickListener() { 98 | @Override 99 | public void onClick(View v) { 100 | if (mPageClickListener != null) { 101 | mPageClickListener.onPageClick(v, realPosition); 102 | } 103 | } 104 | }); 105 | } 106 | 107 | return view; 108 | } 109 | 110 | 111 | public List getData() { 112 | return mData; 113 | } 114 | 115 | public void setData(List mData) { 116 | this.mData = mData; 117 | } 118 | 119 | public void setPageClickListener(OnPageClickListener pageClickListener) { 120 | this.mPageClickListener = pageClickListener; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/banner/holder/BannerViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget.banner.holder; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | 6 | /** 7 | *
 8 |  *      @author : xiaoyao
 9 |  *      e-mail  : xiaoyao@51vest.com
10 |  *      date    : 2018/03/02
11 |  *      desc    :
12 |  *      version : 1.0
13 |  * 
14 | */ 15 | 16 | public interface BannerViewHolder { 17 | 18 | /** 19 | * 创建View 20 | * @param context 21 | * @return 22 | */ 23 | View createView(Context context); 24 | 25 | /** 26 | * 绑定数据 27 | * @param context 28 | * @param position 29 | * @param data 30 | */ 31 | void onBind(Context context, int position, T data); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/banner/holder/BannerViewHolderCreator.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget.banner.holder; 2 | 3 | /** 4 | *
 5 |  *      @author : xiaoyao
 6 |  *      e-mail  : xiaoyao@51vest.com
 7 |  *      date    : 2018/03/02
 8 |  *      desc    :
 9 |  *      version : 1.0
10 |  * 
11 | */ 12 | 13 | public interface BannerViewHolderCreator { 14 | /** 15 | * 创建 BannerViewHolder 16 | * 17 | * @return BannerViewHolder 18 | */ 19 | VH createViewHolder(); 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/banner/listener/OnPageChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget.banner.listener; 2 | 3 | /** 4 | *
 5 |  *      @author : xiaoyao
 6 |  *      e-mail  : xiaoyao@51vest.com
 7 |  *      date    : 2018/03/09
 8 |  *      desc    :
 9 |  *      version : 1.0
10 |  * 
11 | */ 12 | 13 | public interface OnPageChangeListener { 14 | 15 | /** 16 | * item 选中事件 17 | * 18 | * @param position position 19 | */ 20 | void onPageSelected(int position); 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/banner/listener/OnPageClickListener.java: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget.banner.listener; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | *
 7 |  *      @author : xiaoyao
 8 |  *      e-mail  : xiaoyao@51vest.com
 9 |  *      date    : 2018/03/02
10 |  *      desc    :
11 |  *      version : 1.0
12 |  * 
13 | */ 14 | 15 | public interface OnPageClickListener { 16 | 17 | /** 18 | * item 点击事件 19 | * 20 | * @param view view 21 | * @param position position 22 | */ 23 | void onPageClick(View view, int position); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/status/StatusBuilder.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget.status 2 | 3 | import android.view.View 4 | 5 | /** 6 | *
 7 |  *      @author : Allen
 8 |  *      e-mail  : lygttpod@163.com
 9 |  *      date    : 2019/03/19
10 |  *      desc    :
11 |  * 
12 | */ 13 | class StatusBuilder { 14 | 15 | class Builder{ 16 | 17 | var contentView: View? = null 18 | var errorView: View? = null 19 | var emptyView: View? = null 20 | var loadingView: View? = null 21 | 22 | fun setContentView(contentView: View):Builder { 23 | this.contentView = contentView 24 | return this 25 | } 26 | fun setContentView(layoutResId: Int):Builder { 27 | this.contentView = contentView 28 | return this 29 | } 30 | 31 | fun setErrorView(errorView: View):Builder { 32 | this.errorView = errorView 33 | return this 34 | } 35 | 36 | fun setEmptyView(emptyView: View):Builder { 37 | this.emptyView = emptyView 38 | return this 39 | } 40 | 41 | fun setLoadingView(loadingView: View):Builder { 42 | this.loadingView = loadingView 43 | return this 44 | } 45 | 46 | fun build(){ 47 | 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/status/StatusLayout.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget.status 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.widget.FrameLayout 6 | 7 | /** 8 | *
 9 |  *      @author : Allen
10 |  *      e-mail  : lygttpod@163.com
11 |  *      date    : 2019/03/19
12 |  *      desc    : 状态布局
13 |  * 
14 | */ 15 | 16 | class StatusLayout : FrameLayout { 17 | 18 | constructor(context: Context) : this(context, null) 19 | constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) 20 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { 21 | initAttrs(attrs) 22 | } 23 | 24 | private fun initAttrs(attrs: AttributeSet?) { 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/status/StatusManager.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget.status 2 | 3 | /** 4 | *
 5 |  *      @author : Allen
 6 |  *      e-mail  : lygttpod@163.com
 7 |  *      date    : 2019/03/19
 8 |  *      desc    :
 9 |  * 
10 | */ 11 | object StatusManager { 12 | 13 | 14 | fun setEmptyView(){ 15 | 16 | } 17 | 18 | fun setErrorView(){ 19 | 20 | } 21 | 22 | fun setContentView() { 23 | 24 | } 25 | 26 | fun setLoadingView() { 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/allen/androidcustomview/widget/vote/VoteLayoutAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.allen.androidcustomview.widget.vote 2 | 3 | import android.view.View 4 | import android.view.ViewGroup 5 | import com.allen.androidcustomview.bean.VoteBean 6 | import com.allen.androidcustomview.bean.VoteOption 7 | import java.lang.ref.WeakReference 8 | 9 | /** 10 | *
11 |  *      @author : Allen
12 |  *      date    : 2019/08/03
13 |  *      desc    :
14 |  * 
15 | */ 16 | class VoteLayoutAdapter(private val viewGroup: ViewGroup) { 17 | 18 | private var viewHolders = mutableListOf() 19 | 20 | var onVoteClickListener: OnVoteClickListener? = null 21 | 22 | fun setData(vote: ArrayList?) { 23 | viewGroup.removeAllViews() 24 | viewHolders.clear() 25 | if (vote == null || vote.size <= 0) { 26 | viewGroup.visibility = View.GONE 27 | } else { 28 | viewGroup.visibility = View.VISIBLE 29 | val size = vote.size 30 | for (i in 0 until size) { 31 | val viewHolder = onCreateViewHolder(viewGroup, i) 32 | viewHolder.bind(vote[i]) 33 | viewHolders.add(viewHolder) 34 | viewGroup.addView(viewHolder.voteContainerView) 35 | } 36 | } 37 | } 38 | 39 | fun refreshDataAfterVotedSuccess(position: Int) { 40 | viewHolders[position].voteContainerView.refreshDataAfterVoteSuccess() 41 | } 42 | 43 | fun refreshDataAfterVotedFailed(position: Int) { 44 | viewHolders[position].voteContainerView.refreshDataAfterVoteFailed() 45 | } 46 | 47 | fun onDestroy() { 48 | viewHolders.forEach { 49 | it.voteContainerView.onDestroy() 50 | } 51 | } 52 | 53 | private fun onCreateViewHolder(viewGroup: ViewGroup, position: Int): VoteViewHolder { 54 | val view = VoteContainerView(viewGroup.context) 55 | return VoteViewHolder(view, this, position) 56 | } 57 | 58 | class VoteViewHolder(view: VoteContainerView, adapter: VoteLayoutAdapter, var position: Int) { 59 | 60 | private val adapterRef = WeakReference(adapter) 61 | private fun ref(): VoteLayoutAdapter? { 62 | return adapterRef.get() 63 | } 64 | 65 | var voteContainerView = view 66 | private var mMainVote: VoteBean? = null 67 | 68 | fun bind(mainVote: VoteBean) { 69 | mMainVote = mainVote 70 | voteContainerView.setVoteData(mainVote) 71 | voteContainerView.onVoteClickListener = object : VoteContainerView.OnVoteClickListener { 72 | override fun onVoteCommitBtnClick(mainVote: VoteBean?, optionIds: ArrayList) { 73 | ref()?.onVoteClickListener?.onVoteCommitBtnClick(mainVote, optionIds, position) 74 | } 75 | 76 | override fun onVoteItemClick(mainVote: VoteBean?, voteOption: VoteOption?) { 77 | ref()?.onVoteClickListener?.onVoteItemClick(mainVote, voteOption, position) 78 | } 79 | 80 | } 81 | } 82 | 83 | } 84 | 85 | interface OnVoteClickListener { 86 | fun onVoteCommitBtnClick(mainVote: VoteBean?, optionIds: ArrayList, position: Int) 87 | fun onVoteItemClick(mainVote: VoteBean?, voteOption: VoteOption?, position: Int) 88 | } 89 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_gradual_assarts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_clickable.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_un_clickable.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_circle_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_item_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_vote_item_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tag_bg_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tag_checked_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tag_normal_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tag_text_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_alipay_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 13 | 14 | 18 | 19 | 20 | 28 | 29 | 30 | 31 | 37 | 38 | 39 | 42 | 43 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 59 | 60 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_animation_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_animation_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_banner.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 |