├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── dictionaries │ └── hcc.xml ├── encodings.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── io │ │ └── netopen │ │ └── hotbitmapgg │ │ └── androideverydaypractice │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── io │ │ │ └── netopen │ │ │ └── hotbitmapgg │ │ │ └── androideverydaypractice │ │ │ ├── StudyApp.java │ │ │ ├── activity │ │ │ ├── CustomWidgetActivity.java │ │ │ ├── FaceActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── MdWidgetActivity.java │ │ │ ├── PathDemoActivity.java │ │ │ └── RxJavaActivity.java │ │ │ ├── adapter │ │ │ ├── DemoAdapter.java │ │ │ └── FaceAdapter.java │ │ │ ├── base │ │ │ ├── AbsBaseActivity.java │ │ │ └── LazyFragment.java │ │ │ ├── demo │ │ │ └── HeimaDemoActivity.java │ │ │ ├── interfaces │ │ │ ├── OnTextChange.java │ │ │ ├── OneActivity.java │ │ │ └── TwoActivity.java │ │ │ ├── model │ │ │ ├── ExpressionPackage.java │ │ │ ├── GankMeiziInfo.java │ │ │ └── GankMeiziResult.java │ │ │ ├── network │ │ │ ├── ExpressionPackageApi.java │ │ │ ├── GankMeiziApi.java │ │ │ └── RetrofitHelper.java │ │ │ ├── recycleview │ │ │ ├── AbsRecyclerViewAdapter.java │ │ │ ├── AutoLoadOnScrollListener.java │ │ │ ├── DividerGridItemDecoration.java │ │ │ ├── DividerItemDecoration.java │ │ │ ├── MyItemTouchHelper.java │ │ │ ├── RecycleViewDemoActivity.java │ │ │ ├── RecycleViewDemoAdapter.java │ │ │ ├── RecycleViewDemoFragment_1.java │ │ │ ├── RecycleViewDemoFragment_2.java │ │ │ ├── RecycleViewItemTouchListener.java │ │ │ └── loadmore │ │ │ │ ├── EndlessRecyclerOnScrollListener.java │ │ │ │ ├── GridSpacingItemDecoration.java │ │ │ │ └── HeaderViewRecyclerAdapter.java │ │ │ ├── rxjava │ │ │ ├── RxBus.java │ │ │ ├── RxBus2.java │ │ │ ├── RxJavaDemoActivity.java │ │ │ ├── RxJavaSampleActivity.java │ │ │ └── RxTestActivity.java │ │ │ ├── utils │ │ │ ├── ACache.java │ │ │ ├── GankMeiziDateUtil.java │ │ │ ├── GlideDownloadImageUtil.java │ │ │ ├── LogUtil.java │ │ │ └── VibratorUtil.java │ │ │ ├── widget │ │ │ ├── image │ │ │ │ ├── PhotoImageView.java │ │ │ │ └── RatioImageView.java │ │ │ ├── loading │ │ │ │ ├── LoadCircular.java │ │ │ │ └── LoadCircularCD.java │ │ │ ├── lovelayout │ │ │ │ ├── BezierEvaluator.java │ │ │ │ └── LoveLikeLayout.java │ │ │ ├── other │ │ │ │ ├── Bezaer.java │ │ │ │ ├── Bezaer1.java │ │ │ │ ├── Bezaer2.java │ │ │ │ ├── BezaerView.java │ │ │ │ ├── CircleLoadingView.java │ │ │ │ ├── CommonView.java │ │ │ │ ├── CreditSesameNewView.java │ │ │ │ ├── CustomProgressBar.java │ │ │ │ ├── DragView.java │ │ │ │ ├── HackyViewPager.java │ │ │ │ ├── ItemArrowCardView.java │ │ │ │ ├── MemoryClearView.java │ │ │ │ ├── NestedSpringScrollView.java │ │ │ │ ├── PathDemoView.java │ │ │ │ ├── SearchViewAnim.java │ │ │ │ ├── SesameCreditView.java │ │ │ │ ├── SlackAnimView.java │ │ │ │ └── SpringScrollView.java │ │ │ ├── slidecard │ │ │ │ ├── CardDataItem.java │ │ │ │ ├── CardItemView.java │ │ │ │ ├── CardSlidePanel.java │ │ │ │ └── ViewDragHelper.java │ │ │ └── tablayout │ │ │ │ ├── TableView.java │ │ │ │ └── YZBRate.java │ │ │ └── widght_demo │ │ │ ├── BezaerActivity.java │ │ │ ├── BitmapStudyActivity.java │ │ │ ├── CircleProgressBarActivity.java │ │ │ ├── LoveActivity.java │ │ │ ├── ScrollDemoActivity.java │ │ │ ├── SlideGankMeiziActivity.java │ │ │ └── TableActivity.java │ └── res │ │ ├── anim │ │ └── slide_in_right.xml │ │ ├── drawable-hdpi │ │ ├── back.png │ │ ├── ic_arrow.png │ │ ├── ic_banana.png │ │ ├── icon_arrow.jpg │ │ ├── pl_blue.png │ │ ├── pl_red.png │ │ └── pl_yellow.png │ │ ├── drawable │ │ ├── back_shape.xml │ │ ├── edit_bg.xml │ │ ├── ignore_button.xml │ │ ├── ignore_normal.png │ │ ├── ignore_pressed.png │ │ ├── like_button.xml │ │ ├── like_normal.png │ │ └── like_pressed.png │ │ ├── layout │ │ ├── activity_bitmap_study.xml │ │ ├── activity_face.xml │ │ ├── activity_main.xml │ │ ├── activity_md.xml │ │ ├── activity_one.xml │ │ ├── activity_path_demo.xml │ │ ├── activity_progress.xml │ │ ├── activity_recycle.xml │ │ ├── activity_rx_bus.xml │ │ ├── activity_rx_test.xml │ │ ├── activity_rxjava.xml │ │ ├── activity_rxjava_demo.xml │ │ ├── activity_scroll_demo.xml │ │ ├── activity_slide_card.xml │ │ ├── activity_two.xml │ │ ├── activity_widget.xml │ │ ├── activity_widget_bezaer.xml │ │ ├── activity_widget_love.xml │ │ ├── activity_widget_table.xml │ │ ├── card_item.xml │ │ ├── card_item_face.xml │ │ ├── fragment_rxjava_1.xml │ │ ├── item_test_1.xml │ │ ├── layout_item_arrow_view.xml │ │ ├── layout_line_view.xml │ │ └── layout_toolbar.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── attr.xml │ │ ├── circle_loading_style.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── io │ └── netopen │ └── hotbitmapgg │ └── androideverydaypractice │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── projectFilesBackup └── .idea │ └── workspace.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | 10 | .idea/gradle.xml 11 | 12 | .idea/gradle.xml 13 | 14 | .idea/misc.xml 15 | 16 | .idea/misc.xml 17 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/dictionaries/hcc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AndroidEveryDayPractice 2 | 3 | 个人每日安卓学习代码的提交的项目. 4 | 5 | 6 | 7 | ## 说明 8 | 9 | 该项目是个人学习时代码所提交的项目,感兴趣的可以star一波,共同学习交流. 10 | 11 | * 主要包括 12 | * 自定义控件的练习 13 | * RxJava系列类库的学习 14 | * 各种GitHub上比较火的库的学习与使用 15 | * MD新特性的使用(动画,控件,tips等) 16 | * 学习安卓过程遇到的坑 17 | * 各种Tips 18 | 19 | ## Other 20 | 21 | * 知了日报客户端: https://github.com/HotBitmapGG/RxZhiHu 22 | 23 | * 高仿BiliBili客户端: https://github.com/HotBitmapGG/OhMyBiliBili 24 | 25 | * Gank.IO客户端: https://github.com/HotBitmapGG/StudyProject 26 | 27 | * 妹子福利App: https://github.com/HotBitmapGG/MoeQuest 28 | 29 | * 圆环进度条:https://github.com/HotBitmapGG/RingProgressBar 30 | 31 | * 仿芝麻信用圆环进度: https://github.com/HotBitmapGG/CreditSesameRingView 32 | 33 | * 轻量级的RecycleViewAdapter辅助类库 :https://github.com/HotBitmapGG/EasyRecycleAdapterHelper 34 | 35 | 36 | ## License 37 | 38 | Copyright 2016 HotBitmapGG 39 | 40 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 41 | 42 | http://www.apache.org/licenses/LICENSE-2.0 43 | 44 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 45 | 46 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | //apply plugin: 'realm-android' 3 | 4 | android { 5 | compileSdkVersion 23 6 | buildToolsVersion "23.0.3" 7 | 8 | defaultConfig { 9 | applicationId "io.netopen.hotbitmapgg.androideverydaypractice" 10 | minSdkVersion 22 11 | targetSdkVersion 23 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile fileTree(dir: 'libs', include: ['*.jar']) 25 | testCompile 'junit:junit:4.12' 26 | compile 'com.android.support:support-v4:23.4.0' 27 | compile 'com.android.support:appcompat-v7:23.4.0' 28 | compile 'com.android.support:recyclerview-v7:23.4.0' 29 | compile 'com.android.support:cardview-v7:23.4.0' 30 | compile 'com.android.support:design:23.4.0' 31 | compile 'com.github.bumptech.glide:glide:3.7.0' 32 | compile 'com.jakewharton:butterknife:7.0.1' 33 | compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4' 34 | compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4' 35 | compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4' 36 | compile 'com.squareup.okhttp3:okhttp:3.2.0' 37 | compile 'com.squareup.okhttp3:logging-interceptor:3.2.0' 38 | compile 'io.reactivex:rxandroid:1.1.0' 39 | compile 'io.reactivex:rxjava:1.1.0' 40 | compile 'com.jakewharton.rxbinding:rxbinding:0.3.0' 41 | compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.3.0' 42 | compile 'com.jakewharton.rxbinding:rxbinding-design:0.3.0' 43 | compile 'com.flyco.tablayout:FlycoTabLayout_Lib:2.0.6@aar' 44 | compile 'com.android.support:support-v13:23.4.0' 45 | compile 'com.trello:rxlifecycle-components:0.6.1' 46 | compile 'com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar' 47 | } 48 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/hcc/Desktop/SDK/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/io/netopen/hotbitmapgg/androideverydaypractice/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase 10 | { 11 | 12 | public ApplicationTest() 13 | { 14 | 15 | super(Application.class); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 30 | 31 | 34 | 35 | 36 | 39 | 40 | 41 | 44 | 45 | 46 | 49 | 50 | 51 | 54 | 55 | 56 | 59 | 60 | 61 | 64 | 65 | 66 | 69 | 70 | 71 | 74 | 75 | 76 | 79 | 80 | 81 | 84 | 85 | 86 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/StudyApp.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | 7 | public class StudyApp extends Application 8 | { 9 | 10 | public static Context mAppContext; 11 | 12 | @Override 13 | public void onCreate() 14 | { 15 | 16 | super.onCreate(); 17 | mAppContext = this; 18 | // // 配置Realm数据库 19 | // RealmConfiguration configuration = new RealmConfiguration.Builder(this).deleteRealmIfMigrationNeeded().schemaVersion(6).migration(new RealmMigration() 20 | // { 21 | // 22 | // @Override 23 | // public void migrate(DynamicRealm realm, long oldVersion, long newVersion) 24 | // { 25 | // 26 | // } 27 | // }).build(); 28 | // 29 | // Realm.setDefaultConfiguration(configuration); 30 | } 31 | 32 | 33 | public static Context getContext() 34 | { 35 | 36 | return mAppContext; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/activity/CustomWidgetActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.Toolbar; 6 | import android.view.View; 7 | 8 | import butterknife.Bind; 9 | import butterknife.OnClick; 10 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 11 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 12 | import io.netopen.hotbitmapgg.androideverydaypractice.widght_demo.BezaerActivity; 13 | import io.netopen.hotbitmapgg.androideverydaypractice.widght_demo.CircleProgressBarActivity; 14 | import io.netopen.hotbitmapgg.androideverydaypractice.widght_demo.LoveActivity; 15 | import io.netopen.hotbitmapgg.androideverydaypractice.widght_demo.SlideGankMeiziActivity; 16 | import io.netopen.hotbitmapgg.androideverydaypractice.widght_demo.TableActivity; 17 | 18 | 19 | public class CustomWidgetActivity extends AbsBaseActivity 20 | { 21 | 22 | @Bind(R.id.toolbar) 23 | Toolbar mToolbar; 24 | 25 | @Override 26 | public int getLayoutId() 27 | { 28 | 29 | return R.layout.activity_widget; 30 | } 31 | 32 | @Override 33 | public void initViews(Bundle savedInstanceState) 34 | { 35 | 36 | mToolbar.setTitle("自定义控件相关"); 37 | mToolbar.setNavigationIcon(R.drawable.back); 38 | mToolbar.setNavigationOnClickListener(new View.OnClickListener() 39 | { 40 | 41 | @Override 42 | public void onClick(View v) 43 | { 44 | 45 | onBackPressed(); 46 | } 47 | }); 48 | } 49 | 50 | @Override 51 | public void initToolBar() 52 | { 53 | 54 | } 55 | 56 | @OnClick(R.id.widget_1) 57 | void startLoveAnimLayout() 58 | { 59 | 60 | startActivity(new Intent(this, LoveActivity.class)); 61 | } 62 | 63 | @OnClick(R.id.widget_2) 64 | void startCircleProgress() 65 | { 66 | 67 | startActivity(new Intent(this, CircleProgressBarActivity.class)); 68 | } 69 | 70 | @OnClick(R.id.widget_3) 71 | void startTableView() 72 | { 73 | 74 | startActivity(new Intent(this, TableActivity.class)); 75 | } 76 | 77 | @OnClick(R.id.widget_4) 78 | void startBezaerDemo() 79 | { 80 | 81 | startActivity(new Intent(this, BezaerActivity.class)); 82 | } 83 | 84 | @OnClick(R.id.widget_5) 85 | void startTanTan() 86 | { 87 | 88 | startActivity(new Intent(this, SlideGankMeiziActivity.class)); 89 | } 90 | 91 | @OnClick(R.id.widget_6) 92 | void startPathDemo() 93 | { 94 | 95 | startActivity(new Intent(this, PathDemoActivity.class)); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.Toolbar; 6 | 7 | import butterknife.Bind; 8 | import butterknife.OnClick; 9 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 10 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 11 | 12 | public class MainActivity extends AbsBaseActivity 13 | { 14 | 15 | @Bind(R.id.toolbar) 16 | Toolbar mToolbar; 17 | 18 | @Override 19 | public int getLayoutId() 20 | { 21 | 22 | return R.layout.activity_main; 23 | } 24 | 25 | @Override 26 | public void initViews(Bundle savedInstanceState) 27 | { 28 | 29 | } 30 | 31 | @Override 32 | public void initToolBar() 33 | { 34 | 35 | mToolbar.setTitle(R.string.app_name); 36 | } 37 | 38 | 39 | @OnClick(R.id.main_btn_1) 40 | void startCustomWidgetActivity() 41 | { 42 | 43 | startActivity(new Intent(MainActivity.this, CustomWidgetActivity.class)); 44 | } 45 | 46 | 47 | @OnClick(R.id.main_btn_2) 48 | void startMdWidgetActivity() 49 | { 50 | 51 | startActivity(new Intent(MainActivity.this, MdWidgetActivity.class)); 52 | } 53 | 54 | 55 | @OnClick(R.id.main_btn_3) 56 | void startRxJavaActivity() 57 | { 58 | 59 | startActivity(new Intent(MainActivity.this, RxJavaActivity.class)); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/activity/MdWidgetActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.Toolbar; 6 | import android.view.View; 7 | 8 | import butterknife.Bind; 9 | import butterknife.OnClick; 10 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 11 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 12 | import io.netopen.hotbitmapgg.androideverydaypractice.recycleview.RecycleViewDemoActivity; 13 | import io.netopen.hotbitmapgg.androideverydaypractice.widght_demo.ScrollDemoActivity; 14 | 15 | 16 | public class MdWidgetActivity extends AbsBaseActivity 17 | { 18 | 19 | @Bind(R.id.toolbar) 20 | Toolbar mToolbar; 21 | 22 | @Override 23 | public int getLayoutId() 24 | { 25 | 26 | return R.layout.activity_md; 27 | } 28 | 29 | @Override 30 | public void initViews(Bundle savedInstanceState) 31 | { 32 | 33 | } 34 | 35 | @Override 36 | public void initToolBar() 37 | { 38 | mToolbar.setTitle("MaterialDesignDemo相关"); 39 | mToolbar.setNavigationIcon(R.drawable.back); 40 | mToolbar.setNavigationOnClickListener(new View.OnClickListener() 41 | { 42 | 43 | @Override 44 | public void onClick(View v) 45 | { 46 | 47 | onBackPressed(); 48 | } 49 | }); 50 | } 51 | 52 | 53 | @OnClick(R.id.md_btn_1) 54 | void startRecycleViewDemo() 55 | { 56 | 57 | startActivity(new Intent(this, RecycleViewDemoActivity.class)); 58 | } 59 | 60 | @OnClick(R.id.md_btn_2) 61 | void startScrollDemo() 62 | { 63 | 64 | startActivity(new Intent(this, ScrollDemoActivity.class)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/activity/PathDemoActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.activity; 2 | 3 | import android.os.Bundle; 4 | 5 | import butterknife.Bind; 6 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 7 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 8 | import io.netopen.hotbitmapgg.androideverydaypractice.widget.other.SlackAnimView; 9 | 10 | /** 11 | * Created by hcc on 16/7/27 21:11 12 | * 100332338@qq.com 13 | */ 14 | public class PathDemoActivity extends AbsBaseActivity 15 | { 16 | 17 | 18 | @Bind(R.id.slack_view) 19 | SlackAnimView slackView; 20 | 21 | @Override 22 | public int getLayoutId() 23 | { 24 | 25 | return R.layout.activity_path_demo; 26 | } 27 | 28 | @Override 29 | public void initViews(Bundle savedInstanceState) 30 | { 31 | 32 | slackView.reset(); 33 | slackView.start(); 34 | } 35 | 36 | @Override 37 | public void initToolBar() 38 | { 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/activity/RxJavaActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.Toolbar; 6 | import android.view.View; 7 | 8 | import butterknife.Bind; 9 | import butterknife.OnClick; 10 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 11 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 12 | import io.netopen.hotbitmapgg.androideverydaypractice.rxjava.RxJavaSampleActivity; 13 | import io.netopen.hotbitmapgg.androideverydaypractice.utils.LogUtil; 14 | import io.netopen.hotbitmapgg.androideverydaypractice.widget.other.ItemArrowCardView; 15 | 16 | public class RxJavaActivity extends AbsBaseActivity 17 | { 18 | 19 | @Bind(R.id.toolbar) 20 | Toolbar mToolbar; 21 | 22 | @Bind(R.id.btn_2) 23 | ItemArrowCardView mRxjavaSample; 24 | 25 | 26 | @Override 27 | public int getLayoutId() 28 | { 29 | 30 | return R.layout.activity_rxjava; 31 | } 32 | 33 | String s1 = "hcc"; 34 | 35 | String s2 = new String("hcc"); 36 | 37 | String s3 = "h" + "cc"; 38 | 39 | @Override 40 | public void initViews(Bundle savedInstanceState) 41 | { 42 | 43 | LogUtil.all(String.valueOf(s1 == s2)); 44 | LogUtil.all(String.valueOf(s1 == s3)); 45 | LogUtil.all(String.valueOf(s1 == s1.intern())); 46 | } 47 | 48 | @Override 49 | public void initToolBar() 50 | { 51 | 52 | mToolbar.setTitle("RxJava相关"); 53 | mToolbar.setNavigationIcon(R.drawable.back); 54 | mToolbar.setNavigationOnClickListener(new View.OnClickListener() 55 | { 56 | 57 | @Override 58 | public void onClick(View v) 59 | { 60 | 61 | onBackPressed(); 62 | } 63 | }); 64 | } 65 | 66 | 67 | @OnClick(R.id.btn_2) 68 | void startRxJavaSample() 69 | { 70 | 71 | startActivity(new Intent(this, RxJavaSampleActivity.class)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/adapter/DemoAdapter.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.BaseAdapter; 7 | import android.widget.ImageView; 8 | import android.widget.TextView; 9 | 10 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 11 | 12 | /** 13 | * Created by hcc on 2016/11/25 22:24 14 | * 100332338@qq.com 15 | */ 16 | 17 | public class DemoAdapter extends BaseAdapter 18 | { 19 | 20 | Context context; 21 | 22 | @Override 23 | public int getCount() 24 | { 25 | 26 | return 0; 27 | } 28 | 29 | @Override 30 | public Object getItem(int position) 31 | { 32 | 33 | return null; 34 | } 35 | 36 | @Override 37 | public long getItemId(int position) 38 | { 39 | 40 | return 0; 41 | } 42 | 43 | @Override 44 | public View getView(int position, View convertView, ViewGroup parent) 45 | { 46 | ViewHolder viewHolder = null; 47 | if(convertView == null) { 48 | convertView = View.inflate(context, R.layout.item_test_1, null); 49 | viewHolder = new ViewHolder(); 50 | viewHolder.mTextView= (TextView) convertView.findViewById(R.id.tab_layout); 51 | 52 | convertView.setTag(viewHolder); 53 | 54 | 55 | } 56 | else 57 | { 58 | viewHolder = (ViewHolder) convertView.getTag(); 59 | } 60 | 61 | 62 | return convertView; 63 | } 64 | 65 | private static class ViewHolder 66 | { 67 | public TextView mTextView; 68 | 69 | public ImageView mImageView; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/adapter/FaceAdapter.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.adapter; 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.ImageView; 8 | import android.widget.TextView; 9 | 10 | import com.bumptech.glide.Glide; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | import butterknife.Bind; 16 | import butterknife.ButterKnife; 17 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 18 | import io.netopen.hotbitmapgg.androideverydaypractice.model.ExpressionPackage; 19 | import io.netopen.hotbitmapgg.androideverydaypractice.recycleview.AbsRecyclerViewAdapter; 20 | 21 | /** 22 | * Created by 11 on 2016/4/5. 23 | */ 24 | public class FaceAdapter extends AbsRecyclerViewAdapter 25 | { 26 | private List datas = new ArrayList<>(); 27 | 28 | public FaceAdapter(RecyclerView recyclerView, List datas) 29 | { 30 | super(recyclerView); 31 | this.datas = datas; 32 | } 33 | 34 | @Override 35 | public ClickableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 36 | { 37 | bindContext(parent.getContext()); 38 | return new ItemViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.card_item_face, parent, false)); 39 | } 40 | 41 | @Override 42 | public void onBindViewHolder(ClickableViewHolder holder, int position) 43 | { 44 | if (holder instanceof ItemViewHolder) 45 | { 46 | ItemViewHolder itemViewHolder = (ItemViewHolder) holder; 47 | Glide.with(getContext()).load(datas.get(position).image_url).into(itemViewHolder.mImg); 48 | itemViewHolder.mTv.setText(datas.get(position).description); 49 | } 50 | 51 | super.onBindViewHolder(holder, position); 52 | } 53 | 54 | @Override 55 | public int getItemCount() 56 | { 57 | return datas == null ? 0 : datas.size(); 58 | } 59 | 60 | public class ItemViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder 61 | { 62 | @Bind(R.id.item_img) 63 | ImageView mImg; 64 | 65 | @Bind(R.id.item_tv) 66 | TextView mTv; 67 | 68 | public ItemViewHolder(View itemView) 69 | { 70 | super(itemView); 71 | ButterKnife.bind(this, itemView); 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/base/AbsBaseActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.base; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | 6 | import butterknife.ButterKnife; 7 | 8 | public abstract class AbsBaseActivity extends AppCompatActivity 9 | { 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) 13 | { 14 | 15 | super.onCreate(savedInstanceState); 16 | //设置布局内容 17 | setContentView(getLayoutId()); 18 | //初始化黄油刀控件绑定框架 19 | ButterKnife.bind(this); 20 | //初始化控件 21 | initViews(savedInstanceState); 22 | //初始化ToolBar 23 | initToolBar(); 24 | } 25 | 26 | 27 | @Override 28 | protected void onDestroy() 29 | { 30 | 31 | super.onDestroy(); 32 | ButterKnife.unbind(this); 33 | } 34 | 35 | public abstract int getLayoutId(); 36 | 37 | public abstract void initViews(Bundle savedInstanceState); 38 | 39 | public abstract void initToolBar(); 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/base/LazyFragment.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.base; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import butterknife.ButterKnife; 11 | 12 | /** 13 | * Tips: 14 | * 这里没有使用V4包下的Fragment 使用了V13下的Fragment 15 | * 都是可以向下兼容的 16 | */ 17 | public abstract class LazyFragment extends Fragment 18 | { 19 | 20 | private View rootView; 21 | 22 | @Nullable 23 | @Override 24 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 25 | { 26 | 27 | rootView = inflater.inflate(getLayoutId(), container, false); 28 | 29 | return rootView; 30 | } 31 | 32 | @Override 33 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) 34 | { 35 | 36 | super.onViewCreated(view, savedInstanceState); 37 | ButterKnife.bind(this, view); 38 | initViews(); 39 | } 40 | 41 | @Override 42 | public void onDetach() 43 | { 44 | 45 | super.onDetach(); 46 | } 47 | 48 | public abstract int getLayoutId(); 49 | 50 | public abstract void initViews(); 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/demo/HeimaDemoActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.demo; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | 7 | /** 8 | * Created by hcc on 2016/11/19 13:46 9 | * 100332338@qq.com 10 | */ 11 | 12 | public class HeimaDemoActivity extends AppCompatActivity 13 | { 14 | 15 | @Override 16 | protected void onCreate(@Nullable Bundle savedInstanceState) 17 | { 18 | 19 | super.onCreate(savedInstanceState); 20 | init(); 21 | } 22 | 23 | private void init() 24 | { 25 | //初始化管理员 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/interfaces/OnTextChange.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.interfaces; 2 | 3 | /** 4 | * Created by hcc on 2016/11/16 14:58 5 | * 100332338@qq.com 6 | * 7 | * 接口回调的演示demo 8 | */ 9 | 10 | public interface OnTextChange 11 | { 12 | 13 | void textChange(String text); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/interfaces/OneActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.interfaces; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.View; 8 | import android.widget.Button; 9 | 10 | import butterknife.Bind; 11 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 12 | 13 | /** 14 | * Created by hcc on 2016/11/16 15:03 15 | * 100332338@qq.com 16 | */ 17 | 18 | public class OneActivity extends AppCompatActivity 19 | { 20 | 21 | @Bind(R.id.btn) 22 | Button mButton; 23 | 24 | //把这个接口当做OneActivity的一个变量 25 | private OnTextChange onTextChange; 26 | 27 | //重写set方法 28 | public void setOnTextChange(OnTextChange onTextChange) 29 | { 30 | 31 | this.onTextChange = onTextChange; 32 | } 33 | 34 | @Override 35 | protected void onCreate(@Nullable Bundle savedInstanceState) 36 | { 37 | 38 | super.onCreate(savedInstanceState); 39 | setContentView(R.layout.activity_one); 40 | 41 | 42 | mButton.setOnClickListener(new View.OnClickListener() 43 | { 44 | 45 | @Override 46 | public void onClick(View v) 47 | { 48 | //点击这个按钮回调第二个activity里的文字改变方法 49 | if(onTextChange != null) 50 | onTextChange.textChange("接口回调改变的内容"); 51 | 52 | } 53 | }); 54 | 55 | 56 | } 57 | 58 | @Override 59 | protected void onActivityResult(int requestCode, int resultCode, Intent data) 60 | { 61 | 62 | super.onActivityResult(requestCode, resultCode, data); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/interfaces/TwoActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.interfaces; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.widget.TextView; 7 | 8 | import butterknife.Bind; 9 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 10 | 11 | /** 12 | * Created by hcc on 2016/11/16 15:08 13 | * 100332338@qq.com 14 | */ 15 | 16 | public class TwoActivity extends AppCompatActivity implements OnTextChange 17 | { 18 | 19 | @Bind(R.id.text_change) 20 | TextView mTv; 21 | 22 | @Override 23 | protected void onCreate(@Nullable Bundle savedInstanceState) 24 | { 25 | 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_two); 28 | 29 | //第二个界面实现文本改变接口 回调textchange方法 30 | new OneActivity().setOnTextChange(this); 31 | } 32 | 33 | 34 | /** 35 | * 这个就是接口回调方法 36 | * 37 | * @param text 38 | */ 39 | @Override 40 | public void textChange(String text) 41 | { 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/model/ExpressionPackage.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.model; 2 | 3 | public class ExpressionPackage 4 | { 5 | public String description; 6 | 7 | public String image_url; 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/model/GankMeiziInfo.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.model; 2 | 3 | 4 | public class GankMeiziInfo 5 | { 6 | 7 | public String _id; 8 | 9 | public String createdAt; 10 | 11 | public String desc; 12 | 13 | public String publishedAt; 14 | 15 | public String source; 16 | 17 | public String type; 18 | 19 | public String url; 20 | 21 | public boolean used; 22 | 23 | public String who; 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/model/GankMeiziResult.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.List; 6 | 7 | public class GankMeiziResult 8 | { 9 | 10 | public boolean error; 11 | 12 | @SerializedName("results") 13 | public List gankMeizis; 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/network/ExpressionPackageApi.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.network; 2 | 3 | 4 | import java.util.List; 5 | 6 | import io.netopen.hotbitmapgg.androideverydaypractice.model.ExpressionPackage; 7 | import retrofit2.http.GET; 8 | import retrofit2.http.Query; 9 | import rx.Observable; 10 | 11 | public interface ExpressionPackageApi 12 | { 13 | 14 | @GET("search") 15 | Observable> search(@Query("q") String query); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/network/GankMeiziApi.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.network; 2 | 3 | 4 | import io.netopen.hotbitmapgg.androideverydaypractice.model.GankMeiziResult; 5 | import retrofit2.http.GET; 6 | import retrofit2.http.Path; 7 | import rx.Observable; 8 | 9 | public interface GankMeiziApi 10 | { 11 | 12 | @GET("data/福利/{number}/{page}") 13 | Observable getGankMeizi(@Path("number") int number, @Path("page") int page); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/network/RetrofitHelper.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.network; 2 | 3 | import okhttp3.OkHttpClient; 4 | import retrofit2.Retrofit; 5 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 6 | import retrofit2.converter.gson.GsonConverterFactory; 7 | 8 | 9 | public class RetrofitHelper 10 | { 11 | 12 | public static final String BASE_GANK_URL = "http://gank.io/api/"; 13 | 14 | public static final String BASE_ZHUANGBI_URL = "http://zhuangbi.info/"; 15 | 16 | 17 | /** 18 | * Gank妹子Api 19 | * 20 | * @return 21 | */ 22 | public static GankMeiziApi getGankMeiziApi() 23 | { 24 | 25 | Retrofit mRetrofit = new Retrofit.Builder() 26 | .baseUrl(BASE_GANK_URL) 27 | .client(new OkHttpClient()) 28 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 29 | .addConverterFactory(GsonConverterFactory.create()) 30 | .build(); 31 | 32 | GankMeiziApi gankMeiziApi = mRetrofit.create(GankMeiziApi.class); 33 | 34 | return gankMeiziApi; 35 | } 36 | 37 | /** 38 | * 表情包搜索Api 39 | * 40 | * @return 41 | */ 42 | public static ExpressionPackageApi getExpressionPackageApi() 43 | { 44 | 45 | 46 | Retrofit retrofit = new Retrofit.Builder() 47 | .baseUrl(BASE_ZHUANGBI_URL) 48 | .client(new OkHttpClient()) 49 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 50 | .addConverterFactory(GsonConverterFactory.create()) 51 | .build(); 52 | 53 | ExpressionPackageApi expressionPackageApi = retrofit.create(ExpressionPackageApi.class); 54 | 55 | return expressionPackageApi; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/recycleview/AbsRecyclerViewAdapter.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.recycleview; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.IdRes; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | import android.view.animation.Animation; 8 | import android.view.animation.AnimationUtils; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 14 | 15 | /** 16 | * RecycleView通用适配器 17 | */ 18 | public abstract class AbsRecyclerViewAdapter extends RecyclerView.Adapter 19 | { 20 | 21 | private Context context; 22 | 23 | protected RecyclerView mRecyclerView; 24 | 25 | private int mLastPosition = -1; 26 | 27 | private static final int DELAY = 138; 28 | 29 | protected List mListeners = new ArrayList(); 30 | 31 | public AbsRecyclerViewAdapter(RecyclerView recyclerView) 32 | { 33 | 34 | this.mRecyclerView = recyclerView; 35 | this.mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() 36 | { 37 | 38 | @Override 39 | public void onScrollStateChanged(RecyclerView rv, int newState) 40 | { 41 | 42 | for (RecyclerView.OnScrollListener listener : mListeners) 43 | { 44 | listener.onScrollStateChanged(rv, newState); 45 | } 46 | } 47 | 48 | @Override 49 | public void onScrolled(RecyclerView rv, int dx, int dy) 50 | { 51 | 52 | for (RecyclerView.OnScrollListener listener : mListeners) 53 | { 54 | listener.onScrolled(rv, dx, dy); 55 | } 56 | } 57 | }); 58 | } 59 | 60 | public void addOnScrollListener(RecyclerView.OnScrollListener listener) 61 | { 62 | 63 | mListeners.add(listener); 64 | } 65 | 66 | public void showItemAnim(final View view, final int position) 67 | { 68 | 69 | if (position > mLastPosition) 70 | { 71 | view.setAlpha(0); 72 | view.postDelayed(new Runnable() 73 | { 74 | 75 | @Override 76 | public void run() 77 | { 78 | 79 | Animation animation = AnimationUtils.loadAnimation(view.getContext(), 80 | R.anim.slide_in_right); 81 | animation.setAnimationListener(new Animation.AnimationListener() 82 | { 83 | 84 | @Override 85 | public void onAnimationStart(Animation animation) 86 | { 87 | 88 | view.setAlpha(1); 89 | } 90 | 91 | 92 | @Override 93 | public void onAnimationEnd(Animation animation) 94 | { 95 | 96 | } 97 | 98 | 99 | @Override 100 | public void onAnimationRepeat(Animation animation) 101 | { 102 | 103 | } 104 | }); 105 | view.startAnimation(animation); 106 | } 107 | }, position); 108 | mLastPosition = position; 109 | } 110 | } 111 | 112 | public interface OnItemClickListener 113 | { 114 | 115 | public void onItemClick(int position, ClickableViewHolder holder); 116 | } 117 | 118 | public interface OnItemLongClickListener 119 | { 120 | 121 | public boolean onItemLongClick(int position, ClickableViewHolder holder); 122 | } 123 | 124 | private OnItemClickListener itemClickListener; 125 | 126 | private OnItemLongClickListener itemLongClickListener; 127 | 128 | public void setOnItemClickListener(OnItemClickListener listener) 129 | { 130 | 131 | this.itemClickListener = listener; 132 | } 133 | 134 | public void setOnItemLongClickListener(OnItemLongClickListener listener) 135 | { 136 | 137 | this.itemLongClickListener = listener; 138 | } 139 | 140 | public void bindContext(Context context) 141 | { 142 | 143 | this.context = context; 144 | } 145 | 146 | public Context getContext() 147 | { 148 | 149 | return this.context; 150 | } 151 | 152 | @Override 153 | public void onBindViewHolder(final ClickableViewHolder holder, final int position) 154 | { 155 | 156 | holder.getParentView().setOnClickListener(new View.OnClickListener() 157 | { 158 | 159 | @Override 160 | public void onClick(View v) 161 | { 162 | 163 | if (itemClickListener != null) 164 | { 165 | itemClickListener.onItemClick(position, holder); 166 | } 167 | } 168 | }); 169 | holder.getParentView().setOnLongClickListener(new View.OnLongClickListener() 170 | { 171 | 172 | @Override 173 | public boolean onLongClick(View v) 174 | { 175 | 176 | if (itemLongClickListener != null) 177 | { 178 | return itemLongClickListener.onItemLongClick(position, holder); 179 | } else 180 | { 181 | return false; 182 | } 183 | } 184 | }); 185 | } 186 | 187 | public class ClickableViewHolder extends RecyclerView.ViewHolder 188 | { 189 | 190 | private View parentView; 191 | 192 | public ClickableViewHolder(View itemView) 193 | { 194 | 195 | super(itemView); 196 | this.parentView = itemView; 197 | } 198 | 199 | public View getParentView() 200 | { 201 | 202 | return parentView; 203 | } 204 | 205 | public T $(@IdRes int id) 206 | { 207 | 208 | return (T) parentView.findViewById(id); 209 | } 210 | } 211 | } -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/recycleview/AutoLoadOnScrollListener.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.recycleview; 2 | 3 | import android.support.v7.widget.LinearLayoutManager; 4 | import android.support.v7.widget.RecyclerView; 5 | 6 | /** 7 | * RecycleView上拉加载更多 8 | */ 9 | public abstract class AutoLoadOnScrollListener extends RecyclerView.OnScrollListener 10 | { 11 | private int previousTotal = 0; 12 | 13 | private boolean loading = false; 14 | 15 | int totalItemCount, lastVisibleItem; 16 | 17 | private int currentPage = 1; 18 | 19 | private LinearLayoutManager mLinearLayoutManager; 20 | 21 | public AutoLoadOnScrollListener(LinearLayoutManager linearLayoutManager) 22 | { 23 | this.mLinearLayoutManager = linearLayoutManager; 24 | } 25 | 26 | @Override 27 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) 28 | { 29 | super.onScrolled(recyclerView, dx, dy); 30 | 31 | totalItemCount = mLinearLayoutManager.getItemCount(); 32 | lastVisibleItem = mLinearLayoutManager.findLastVisibleItemPosition(); 33 | 34 | if (!loading && (lastVisibleItem > totalItemCount - 3) && dy > 0) 35 | { 36 | currentPage++; 37 | onLoadMore(currentPage); 38 | loading = true; 39 | } 40 | } 41 | 42 | public abstract void onLoadMore(int currentPage); 43 | 44 | public boolean isLoading() 45 | { 46 | return loading; 47 | } 48 | 49 | public void setLoading(boolean loading) 50 | { 51 | this.loading = loading; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/recycleview/DividerItemDecoration.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.recycleview; 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 | public class DividerItemDecoration extends RecyclerView.ItemDecoration 14 | { 15 | 16 | private static final int[] ATTRS = new int[]{ 17 | android.R.attr.listDivider 18 | }; 19 | 20 | public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; 21 | 22 | public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; 23 | 24 | private Drawable mDivider; 25 | 26 | private int mOrientation; 27 | 28 | public DividerItemDecoration(Context context, int orientation) 29 | { 30 | 31 | final TypedArray a = context.obtainStyledAttributes(ATTRS); 32 | mDivider = a.getDrawable(0); 33 | a.recycle(); 34 | setOrientation(orientation); 35 | } 36 | 37 | public void setOrientation(int orientation) 38 | { 39 | 40 | if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) 41 | { 42 | throw new IllegalArgumentException("invalid orientation"); 43 | } 44 | mOrientation = orientation; 45 | } 46 | 47 | @Override 48 | public void onDraw(Canvas c, RecyclerView parent) 49 | { 50 | 51 | if (mOrientation == VERTICAL_LIST) 52 | { 53 | drawVertical(c, parent); 54 | } else 55 | { 56 | drawHorizontal(c, parent); 57 | } 58 | } 59 | 60 | 61 | public void drawVertical(Canvas c, RecyclerView parent) 62 | { 63 | 64 | final int left = parent.getPaddingLeft(); 65 | final int right = parent.getWidth() - parent.getPaddingRight(); 66 | 67 | final int childCount = parent.getChildCount(); 68 | for (int i = 0; i < childCount; i++) 69 | { 70 | final View child = parent.getChildAt(i); 71 | android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext()); 72 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 73 | .getLayoutParams(); 74 | final int top = child.getBottom() + params.bottomMargin; 75 | final int bottom = top + mDivider.getIntrinsicHeight(); 76 | mDivider.setBounds(left, top, right, bottom); 77 | mDivider.draw(c); 78 | } 79 | } 80 | 81 | public void drawHorizontal(Canvas c, RecyclerView parent) 82 | { 83 | 84 | final int top = parent.getPaddingTop(); 85 | final int bottom = parent.getHeight() - parent.getPaddingBottom(); 86 | 87 | final int childCount = parent.getChildCount(); 88 | for (int i = 0; i < childCount; i++) 89 | { 90 | final View child = parent.getChildAt(i); 91 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 92 | .getLayoutParams(); 93 | final int left = child.getRight() + params.rightMargin; 94 | final int right = left + mDivider.getIntrinsicHeight(); 95 | mDivider.setBounds(left, top, right, bottom); 96 | mDivider.draw(c); 97 | } 98 | } 99 | 100 | @Override 101 | public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) 102 | { 103 | 104 | if (mOrientation == VERTICAL_LIST) 105 | { 106 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); 107 | } else 108 | { 109 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/recycleview/RecycleViewDemoActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.recycleview; 2 | 3 | import android.app.Fragment; 4 | import android.app.FragmentManager; 5 | import android.os.Bundle; 6 | import android.support.v13.app.FragmentStatePagerAdapter; 7 | import android.support.v4.view.ViewPager; 8 | import android.support.v7.app.ActionBar; 9 | import android.support.v7.widget.Toolbar; 10 | import android.view.MenuItem; 11 | 12 | import com.flyco.tablayout.SlidingTabLayout; 13 | 14 | import java.util.ArrayList; 15 | import java.util.Arrays; 16 | import java.util.List; 17 | 18 | import butterknife.Bind; 19 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 20 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 21 | 22 | public class RecycleViewDemoActivity extends AbsBaseActivity 23 | { 24 | 25 | 26 | @Bind(R.id.toolbar) 27 | Toolbar mToolBar; 28 | 29 | @Bind(R.id.tab_layout) 30 | SlidingTabLayout mTabLayout; 31 | 32 | @Bind(R.id.viewpager) 33 | ViewPager mViewPager; 34 | 35 | private List titles = Arrays.asList("测试1", "测试2"); 36 | 37 | private List fragments = new ArrayList<>(); 38 | 39 | 40 | @Override 41 | public int getLayoutId() 42 | { 43 | return R.layout.activity_recycle; 44 | } 45 | 46 | @Override 47 | public void initViews(Bundle savedInstanceState) 48 | { 49 | fragments.add(RecycleViewDemoFragment_1.newInstance()); 50 | fragments.add(RecycleViewDemoFragment_2.newInstance()); 51 | 52 | 53 | mViewPager.setAdapter(new SamplePagerAdapter(getFragmentManager())); 54 | mTabLayout.setViewPager(mViewPager); 55 | 56 | } 57 | 58 | @Override 59 | public void initToolBar() 60 | { 61 | setSupportActionBar(mToolBar); 62 | ActionBar actionBar = getSupportActionBar(); 63 | if (actionBar != null) 64 | actionBar.setDisplayHomeAsUpEnabled(true); 65 | actionBar.setTitle("RecycleView各种用法"); 66 | } 67 | 68 | @Override 69 | public boolean onOptionsItemSelected(MenuItem item) 70 | { 71 | if(item.getItemId() == android.R.id.home) 72 | onBackPressed(); 73 | return super.onOptionsItemSelected(item); 74 | } 75 | 76 | private class SamplePagerAdapter extends FragmentStatePagerAdapter 77 | { 78 | public SamplePagerAdapter(FragmentManager fm) 79 | { 80 | super(fm); 81 | } 82 | 83 | @Override 84 | public Fragment getItem(int position) 85 | { 86 | return fragments.get(position); 87 | } 88 | 89 | @Override 90 | public CharSequence getPageTitle(int position) 91 | { 92 | return titles.get(position); 93 | } 94 | 95 | @Override 96 | public int getCount() 97 | { 98 | return titles.size(); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/recycleview/RecycleViewDemoAdapter.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.recycleview; 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 | import java.util.ArrayList; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 14 | 15 | 16 | public class RecycleViewDemoAdapter extends AbsRecyclerViewAdapter implements MyItemTouchHelper.ItemTouchAdapter 17 | { 18 | 19 | private List datas = new ArrayList<>(); 20 | 21 | public RecycleViewDemoAdapter(RecyclerView recyclerView, List datas) 22 | { 23 | super(recyclerView); 24 | this.datas = datas; 25 | } 26 | 27 | @Override 28 | public ClickableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 29 | { 30 | bindContext(parent.getContext()); 31 | return new RxjavaDemoViewHolder_1(LayoutInflater.from(getContext()).inflate(R.layout.item_test_1, parent, false)); 32 | } 33 | 34 | @Override 35 | public void onBindViewHolder(ClickableViewHolder holder, int position) 36 | { 37 | if (holder instanceof RxjavaDemoViewHolder_1) 38 | { 39 | RxjavaDemoViewHolder_1 viewHolder_1 = (RxjavaDemoViewHolder_1) holder; 40 | viewHolder_1.mTextView.setText(datas.get(position)); 41 | } 42 | 43 | super.onBindViewHolder(holder, position); 44 | } 45 | 46 | @Override 47 | public int getItemCount() 48 | { 49 | return datas.size(); 50 | } 51 | 52 | @Override 53 | public void onMove(int fromPosition, int toPosition) 54 | { 55 | if (fromPosition < toPosition) 56 | { 57 | 58 | for (int i = fromPosition; i < toPosition; i++) 59 | { 60 | Collections.swap(datas, i, i + 1); 61 | } 62 | } 63 | else 64 | { 65 | for (int i = fromPosition; i > toPosition; i--) 66 | { 67 | Collections.swap(datas, i, i - 1); 68 | } 69 | } 70 | 71 | notifyItemMoved(fromPosition, toPosition); 72 | } 73 | 74 | @Override 75 | public void onSwiped(int position) 76 | { 77 | datas.remove(position); 78 | notifyItemRemoved(position); 79 | } 80 | 81 | 82 | private class RxjavaDemoViewHolder_1 extends AbsRecyclerViewAdapter.ClickableViewHolder 83 | { 84 | 85 | public TextView mTextView; 86 | 87 | public RxjavaDemoViewHolder_1(View itemView) 88 | { 89 | super(itemView); 90 | mTextView = $(R.id.item_text); 91 | } 92 | 93 | 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/recycleview/RecycleViewDemoFragment_1.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.recycleview; 2 | 3 | import android.graphics.Color; 4 | import android.os.Handler; 5 | import android.support.design.widget.Snackbar; 6 | import android.support.v4.widget.SwipeRefreshLayout; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.support.v7.widget.helper.ItemTouchHelper; 10 | import android.view.View; 11 | import android.view.ViewTreeObserver; 12 | 13 | import java.util.Arrays; 14 | import java.util.List; 15 | 16 | import butterknife.Bind; 17 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 18 | import io.netopen.hotbitmapgg.androideverydaypractice.base.LazyFragment; 19 | import io.netopen.hotbitmapgg.androideverydaypractice.utils.VibratorUtil; 20 | 21 | /** 22 | * RecycleView练习 各种用法汇总 23 | *

24 | * 结合Api 以及Rxjava的使用 25 | * 26 | * 线性列表布局 27 | */ 28 | public class RecycleViewDemoFragment_1 extends LazyFragment 29 | { 30 | 31 | @Bind(R.id.recycle) 32 | RecyclerView mRecycleView; 33 | 34 | @Bind(R.id.swipe_refresh) 35 | SwipeRefreshLayout mRefreshLayout; 36 | 37 | private List datas = Arrays.asList("A", "B", "C", "D", "E", "F", "G", 38 | "H", "J", "K", "L", "M", "N", 39 | "O", "P", "Q", "R", "S", "T", 40 | "U", "V", "W", "X", "Y", "Z"); 41 | private ItemTouchHelper itemTouchHelper; 42 | 43 | public static RecycleViewDemoFragment_1 newInstance() 44 | { 45 | return new RecycleViewDemoFragment_1(); 46 | } 47 | 48 | @Override 49 | public int getLayoutId() 50 | { 51 | return R.layout.fragment_rxjava_1; 52 | } 53 | 54 | @Override 55 | public void initViews() 56 | { 57 | 58 | mRecycleView.setVisibility(View.GONE); 59 | mRefreshLayout.setColorSchemeResources(R.color.colorPrimary, R.color.colorPrimaryDark); 60 | mRefreshLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() 61 | { 62 | @Override 63 | public void onGlobalLayout() 64 | { 65 | mRefreshLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); 66 | mRefreshLayout.setRefreshing(true); 67 | loadData(); 68 | } 69 | }); 70 | mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() 71 | { 72 | @Override 73 | public void onRefresh() 74 | { 75 | 76 | mRefreshLayout.setRefreshing(false); 77 | } 78 | }); 79 | 80 | 81 | } 82 | 83 | private void loadData() 84 | { 85 | mRecycleView.setHasFixedSize(true); 86 | mRecycleView.setLayoutManager(new LinearLayoutManager(getActivity())); 87 | RecycleViewDemoAdapter mAdapter = new RecycleViewDemoAdapter(mRecycleView, datas); 88 | itemTouchHelper = new ItemTouchHelper(new MyItemTouchHelper(mAdapter)); 89 | itemTouchHelper.attachToRecyclerView(mRecycleView); 90 | mRecycleView.setAdapter(mAdapter); 91 | mRecycleView.addOnItemTouchListener( 92 | new RecycleViewItemTouchListener(mRecycleView) 93 | { 94 | 95 | @Override 96 | public void onLongClick(RecyclerView.ViewHolder vh) 97 | { 98 | itemTouchHelper.startDrag(vh); 99 | //设置长按拖拽震动 100 | VibratorUtil.vibrator(getActivity(), 100); 101 | } 102 | 103 | @Override 104 | public void onItemClick(RecyclerView.ViewHolder vh) 105 | { 106 | int layoutPosition = vh.getLayoutPosition(); 107 | Snackbar.make(mRecycleView, datas.get(layoutPosition), Snackbar.LENGTH_SHORT) 108 | .setActionTextColor(Color.YELLOW) 109 | .show(); 110 | } 111 | } 112 | ); 113 | 114 | 115 | new Handler().postDelayed(new Runnable() 116 | { 117 | @Override 118 | public void run() 119 | { 120 | mRefreshLayout.setRefreshing(false); 121 | mRecycleView.setVisibility(View.VISIBLE); 122 | } 123 | }, 2000); 124 | 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/recycleview/RecycleViewDemoFragment_2.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.recycleview; 2 | 3 | import android.graphics.Color; 4 | import android.os.Handler; 5 | import android.support.design.widget.Snackbar; 6 | import android.support.v4.widget.SwipeRefreshLayout; 7 | import android.support.v7.widget.GridLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.support.v7.widget.helper.ItemTouchHelper; 10 | import android.view.View; 11 | import android.view.ViewTreeObserver; 12 | 13 | import java.util.Arrays; 14 | import java.util.List; 15 | 16 | import butterknife.Bind; 17 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 18 | import io.netopen.hotbitmapgg.androideverydaypractice.base.LazyFragment; 19 | import io.netopen.hotbitmapgg.androideverydaypractice.utils.VibratorUtil; 20 | 21 | /** 22 | * RecycleView练习 各种用法汇总 23 | *

24 | * 结合Api 以及Rxjava的使用 25 | * 26 | * 表格布局 27 | */ 28 | public class RecycleViewDemoFragment_2 extends LazyFragment 29 | { 30 | 31 | @Bind(R.id.recycle) 32 | RecyclerView mRecycleView; 33 | 34 | @Bind(R.id.swipe_refresh) 35 | SwipeRefreshLayout mRefreshLayout; 36 | 37 | private List datas = Arrays.asList("A", "B", "C", "D", "E", "F", "G", 38 | "H", "J", "K", "L", "M", "N", 39 | "O", "P", "Q", "R", "S", "T", 40 | "U", "V", "W", "X", "Y", "Z"); 41 | private ItemTouchHelper itemTouchHelper; 42 | 43 | public static RecycleViewDemoFragment_2 newInstance() 44 | { 45 | return new RecycleViewDemoFragment_2(); 46 | } 47 | 48 | @Override 49 | public int getLayoutId() 50 | { 51 | return R.layout.fragment_rxjava_1; 52 | } 53 | 54 | @Override 55 | public void initViews() 56 | { 57 | 58 | mRecycleView.setVisibility(View.GONE); 59 | mRefreshLayout.setColorSchemeResources(R.color.colorPrimary, R.color.colorPrimaryDark); 60 | mRefreshLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() 61 | { 62 | @Override 63 | public void onGlobalLayout() 64 | { 65 | mRefreshLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); 66 | mRefreshLayout.setRefreshing(true); 67 | loadData(); 68 | } 69 | }); 70 | mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() 71 | { 72 | @Override 73 | public void onRefresh() 74 | { 75 | 76 | mRefreshLayout.setRefreshing(false); 77 | } 78 | }); 79 | 80 | 81 | } 82 | 83 | private void loadData() 84 | { 85 | mRecycleView.setHasFixedSize(true); 86 | mRecycleView.setLayoutManager(new GridLayoutManager(getActivity(), 3)); 87 | mRecycleView.addItemDecoration(new DividerGridItemDecoration()); 88 | RecycleViewDemoAdapter mAdapter = new RecycleViewDemoAdapter(mRecycleView, datas); 89 | itemTouchHelper = new ItemTouchHelper(new MyItemTouchHelper(mAdapter)); 90 | itemTouchHelper.attachToRecyclerView(mRecycleView); 91 | mRecycleView.setAdapter(mAdapter); 92 | mRecycleView.addOnItemTouchListener( 93 | new RecycleViewItemTouchListener(mRecycleView) 94 | { 95 | 96 | @Override 97 | public void onLongClick(RecyclerView.ViewHolder vh) 98 | { 99 | itemTouchHelper.startDrag(vh); 100 | //设置长按拖拽震动 101 | VibratorUtil.vibrator(getActivity(), 100); 102 | } 103 | 104 | @Override 105 | public void onItemClick(RecyclerView.ViewHolder vh) 106 | { 107 | int layoutPosition = vh.getLayoutPosition(); 108 | Snackbar.make(mRecycleView, datas.get(layoutPosition), Snackbar.LENGTH_SHORT) 109 | .setActionTextColor(Color.YELLOW) 110 | .show(); 111 | } 112 | } 113 | ); 114 | 115 | 116 | new Handler().postDelayed(new Runnable() 117 | { 118 | @Override 119 | public void run() 120 | { 121 | mRefreshLayout.setRefreshing(false); 122 | mRecycleView.setVisibility(View.VISIBLE); 123 | } 124 | }, 2000); 125 | 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/recycleview/RecycleViewItemTouchListener.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.recycleview; 2 | 3 | import android.support.v4.view.GestureDetectorCompat; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.GestureDetector; 6 | import android.view.MotionEvent; 7 | import android.view.View; 8 | 9 | 10 | public class RecycleViewItemTouchListener implements RecyclerView.OnItemTouchListener 11 | { 12 | private GestureDetectorCompat mGestureDetector; 13 | 14 | private RecyclerView mRcycleView; 15 | 16 | public RecycleViewItemTouchListener(RecyclerView mRcycleView) 17 | { 18 | this.mRcycleView = mRcycleView; 19 | mGestureDetector = new GestureDetectorCompat(mRcycleView.getContext(), 20 | new ItemTouchHelperGestureLisener()); 21 | } 22 | 23 | @Override 24 | public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) 25 | { 26 | mGestureDetector.onTouchEvent(e); 27 | return false; 28 | } 29 | 30 | @Override 31 | public void onTouchEvent(RecyclerView rv, MotionEvent e) 32 | { 33 | mGestureDetector.onTouchEvent(e); 34 | } 35 | 36 | @Override 37 | public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) 38 | { 39 | 40 | } 41 | 42 | 43 | /** 44 | * 监听手执触摸事件回调 45 | *

46 | * 单击事件 和 长按事件 47 | */ 48 | private class ItemTouchHelperGestureLisener extends GestureDetector.SimpleOnGestureListener 49 | { 50 | 51 | 52 | @Override 53 | public boolean onSingleTapUp(MotionEvent e) 54 | { 55 | View childViewUnder = mRcycleView.findChildViewUnder(e.getX(), e.getY()); 56 | if (childViewUnder != null) 57 | { 58 | RecyclerView.ViewHolder viewHolder = mRcycleView.getChildViewHolder(childViewUnder); 59 | onItemClick(viewHolder); 60 | } 61 | 62 | return true; 63 | } 64 | 65 | @Override 66 | public void onLongPress(MotionEvent e) 67 | { 68 | View childViewUnder = mRcycleView.findChildViewUnder(e.getX(), e.getY()); 69 | if (childViewUnder != null) 70 | { 71 | RecyclerView.ViewHolder viewHolder = mRcycleView.getChildViewHolder(childViewUnder); 72 | onLongClick(viewHolder); 73 | } 74 | 75 | super.onLongPress(e); 76 | } 77 | 78 | 79 | } 80 | 81 | 82 | public void onLongClick(RecyclerView.ViewHolder vh) 83 | { 84 | } 85 | 86 | public void onItemClick(RecyclerView.ViewHolder vh) 87 | { 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/recycleview/loadmore/EndlessRecyclerOnScrollListener.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.recycleview.loadmore; 2 | 3 | import android.support.v7.widget.LinearLayoutManager; 4 | import android.support.v7.widget.RecyclerView; 5 | 6 | /** 7 | * RecycleView上拉加载更多 8 | */ 9 | public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener 10 | { 11 | 12 | public static String TAG = EndlessRecyclerOnScrollListener.class.getSimpleName(); 13 | 14 | private int previousTotal = 0; 15 | 16 | private boolean loading = true; 17 | 18 | int lastCompletelyVisiableItemPosition, visibleItemCount, totalItemCount; 19 | 20 | private int currentPage = 1; 21 | 22 | private LinearLayoutManager mLinearLayoutManager; 23 | 24 | public EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager) 25 | { 26 | 27 | this.mLinearLayoutManager = linearLayoutManager; 28 | } 29 | 30 | @Override 31 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) 32 | { 33 | 34 | super.onScrolled(recyclerView, dx, dy); 35 | 36 | visibleItemCount = recyclerView.getChildCount(); 37 | totalItemCount = mLinearLayoutManager.getItemCount(); 38 | lastCompletelyVisiableItemPosition = mLinearLayoutManager.findLastCompletelyVisibleItemPosition(); 39 | 40 | if (loading) 41 | { 42 | if (totalItemCount > previousTotal) 43 | { 44 | loading = false; 45 | previousTotal = totalItemCount; 46 | } 47 | } 48 | if (!loading 49 | && (visibleItemCount > 0) 50 | && (lastCompletelyVisiableItemPosition >= totalItemCount - 1)) 51 | { 52 | currentPage++; 53 | onLoadMore(currentPage); 54 | loading = true; 55 | } 56 | } 57 | 58 | public abstract void onLoadMore(int currentPage); 59 | } -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/recycleview/loadmore/GridSpacingItemDecoration.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.recycleview.loadmore; 2 | 3 | import android.graphics.Rect; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.View; 6 | 7 | /** 8 | * Grid分割线 9 | */ 10 | public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration 11 | { 12 | 13 | private int spanCount; 14 | 15 | private int spacing; 16 | 17 | private boolean includeEdge; 18 | 19 | private int headerNum; 20 | 21 | public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge, int headerNum) 22 | { 23 | 24 | this.spanCount = spanCount; 25 | this.spacing = spacing; 26 | this.includeEdge = includeEdge; 27 | this.headerNum = headerNum; 28 | } 29 | 30 | @Override 31 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) 32 | { 33 | 34 | int position = parent.getChildAdapterPosition(view) - headerNum; // item position 35 | 36 | if (position >= 0) 37 | { 38 | int column = position % spanCount; // item column 39 | 40 | if (includeEdge) 41 | { 42 | outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing) 43 | outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing) 44 | 45 | if (position < spanCount) 46 | { // top edge 47 | outRect.top = spacing; 48 | } 49 | outRect.bottom = spacing; // item bottom 50 | } else 51 | { 52 | outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing) 53 | outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing) 54 | if (position >= spanCount) 55 | { 56 | outRect.top = spacing; // item top 57 | } 58 | } 59 | } else 60 | { 61 | outRect.left = 0; 62 | outRect.right = 0; 63 | outRect.top = 0; 64 | outRect.bottom = 0; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/rxjava/RxBus.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.rxjava; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import rx.Observable; 9 | import rx.subjects.PublishSubject; 10 | import rx.subjects.Subject; 11 | 12 | /** 13 | * Rxbus 14 | * 如果项目中已使用Rxjava 15 | * 可以使用Rxbus这种思想来替换掉EventBus 或者 Otto 16 | * 这类事件总线的开源库, 毕竟65535方法数还是很容易达到的 17 | */ 18 | public class RxBus 19 | { 20 | 21 | private static Map subjectList = new HashMap<>(); 22 | 23 | private RxBus() 24 | { 25 | 26 | } 27 | 28 | private static class RxBusHolder 29 | { 30 | 31 | private static final RxBus instance = new RxBus(); 32 | } 33 | 34 | public static synchronized RxBus getInstance() 35 | { 36 | 37 | return RxBusHolder.instance; 38 | } 39 | 40 | public synchronized Observable register(@NonNull Object object) 41 | { 42 | 43 | Subject subject = PublishSubject.create(); 44 | subjectList.put(object, subject); 45 | return subject; 46 | } 47 | 48 | public synchronized void unregister(Object object) 49 | { 50 | 51 | subjectList.remove(object); 52 | } 53 | 54 | public void post(@NonNull Object content) 55 | { 56 | 57 | synchronized (this) 58 | { 59 | for (Subject subject : subjectList.values()) 60 | { 61 | if (subject != null) 62 | { 63 | subject.onNext(content); 64 | } 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/rxjava/RxBus2.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.rxjava; 2 | 3 | 4 | import rx.Observable; 5 | import rx.subjects.PublishSubject; 6 | import rx.subjects.SerializedSubject; 7 | import rx.subjects.Subject; 8 | 9 | /** 10 | * RxBus第二种实现方法 11 | *

12 | * Subject同时充当了Observer和Observable的角色,Subject是非线程安全的, 13 | * 要避免该问题,需要将 Subject转换为一个 SerializedSubject , 14 | * 上述RxBus类中把线程非安全的PublishSubject包装成线程安全的Subject。 15 | 16 | * PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者 17 | *

18 | * ofType操作符只发射指定类型的数据,其内部就是filter+cast 19 | */ 20 | public class RxBus2 21 | { 22 | 23 | private static volatile RxBus2 mInstance; 24 | 25 | private final Subject bus; 26 | 27 | 28 | public RxBus2() 29 | { 30 | 31 | bus = new SerializedSubject<>(PublishSubject.create()); 32 | } 33 | 34 | /** 35 | * 单例模式RxBus2 36 | * 37 | * @return 38 | */ 39 | public static RxBus2 getInstance() 40 | { 41 | 42 | RxBus2 rxBus2 = mInstance; 43 | if (mInstance == null) 44 | { 45 | synchronized (RxBus2.class) 46 | { 47 | rxBus2 = mInstance; 48 | if (mInstance == null) 49 | { 50 | rxBus2 = new RxBus2(); 51 | mInstance = rxBus2; 52 | } 53 | } 54 | } 55 | 56 | return rxBus2; 57 | } 58 | 59 | 60 | /** 61 | * 发送消息 62 | * 63 | * @param object 64 | */ 65 | public void post(Object object) 66 | { 67 | 68 | bus.onNext(object); 69 | } 70 | 71 | /** 72 | * 接收消息 73 | * 74 | * @param eventType 75 | * @param 76 | * @return 77 | */ 78 | public Observable toObserverable(Class eventType) 79 | { 80 | 81 | return bus.ofType(eventType); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/rxjava/RxJavaDemoActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.rxjava; 2 | 3 | import android.os.Bundle; 4 | import android.widget.TextView; 5 | 6 | import butterknife.Bind; 7 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 8 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 9 | 10 | /** 11 | * Rxjava基本练习 12 | */ 13 | public class RxJavaDemoActivity extends AbsBaseActivity 14 | { 15 | 16 | @Bind(R.id.tv) 17 | TextView mTv; 18 | 19 | int[] ints = new int[]{1, 2, 3, 4, 5}; 20 | 21 | 22 | @Override 23 | public int getLayoutId() 24 | { 25 | return R.layout.activity_rx_bus; 26 | } 27 | 28 | @Override 29 | public void initViews(Bundle savedInstanceState) 30 | { 31 | 32 | // initData(); 33 | 34 | } 35 | 36 | // @Override 37 | // public void rxBusMessage(String str) 38 | // { 39 | // 40 | // LogUtil.all(str); 41 | // } 42 | 43 | 44 | private void initData() 45 | { 46 | // Observable.just(ints) 47 | // .subscribeOn(Schedulers.io()) 48 | // .map(new Func1() 49 | // { 50 | // @Override 51 | // public String call(int[] ints) 52 | // { 53 | // 54 | // return null; 55 | // } 56 | // }) 57 | // .flatMap(new Func1>() 58 | // { 59 | // @Override 60 | // public Observable call(String s) 61 | // { 62 | // return null; 63 | // } 64 | // }) 65 | // .take(3) 66 | // .debounce(400, TimeUnit.MILLISECONDS) 67 | // .observeOn(AndroidSchedulers.mainThread()) 68 | // .subscribe(new Observer() 69 | // { 70 | // @Override 71 | // public void onCompleted() 72 | // { 73 | // 74 | // } 75 | // 76 | // @Override 77 | // public void onError(Throwable e) 78 | // { 79 | // 80 | // } 81 | // 82 | // @Override 83 | // public void onNext(Object o) 84 | // { 85 | // 86 | // } 87 | // }); 88 | } 89 | 90 | @Override 91 | public void initToolBar() 92 | { 93 | 94 | } 95 | 96 | @Override 97 | protected void onDestroy() 98 | { 99 | 100 | super.onDestroy(); 101 | } 102 | 103 | // @Override 104 | // protected void initRxBus() 105 | // { 106 | // RxBus2.getInstance().toObserverable(Bundle.class) 107 | // .subscribe(new Action1() 108 | // { 109 | // 110 | // @Override 111 | // public void call(Bundle bundle) 112 | // { 113 | // 114 | // String str = bundle.getString("str"); 115 | // LogUtil.all(str); 116 | // } 117 | // }); 118 | // } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/utils/GankMeiziDateUtil.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.utils; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | 7 | /** 8 | * Gank妹子的创建时间转换工具类 9 | */ 10 | public class GankMeiziDateUtil 11 | { 12 | 13 | private final static String TIME_FORMAT_1 = "yyyy-MM-dd'T'HH:mm:ss.SS'Z'"; 14 | 15 | private final static String TIME_FORMAT_2 = "yy/MM/dd HH:mm:ss"; 16 | 17 | 18 | public static String convertTime(String createdAt) 19 | { 20 | 21 | try 22 | { 23 | SimpleDateFormat inputFormat = new SimpleDateFormat(TIME_FORMAT_1); 24 | SimpleDateFormat outputFormat = new SimpleDateFormat(TIME_FORMAT_2); 25 | 26 | Date date = inputFormat.parse(createdAt); 27 | String time = outputFormat.format(date); 28 | 29 | return time; 30 | } catch (ParseException e) 31 | { 32 | e.printStackTrace(); 33 | 34 | return ""; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/utils/GlideDownloadImageUtil.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.utils; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Environment; 7 | import android.os.SystemClock; 8 | 9 | import com.bumptech.glide.Glide; 10 | import com.bumptech.glide.request.target.Target; 11 | 12 | import java.io.File; 13 | import java.io.FileInputStream; 14 | import java.io.FileOutputStream; 15 | import java.util.concurrent.ExecutionException; 16 | 17 | import rx.Observable; 18 | import rx.Subscriber; 19 | import rx.functions.Func1; 20 | import rx.schedulers.Schedulers; 21 | 22 | /** 23 | * 使用Glide下载图片到本地工具类 24 | */ 25 | public class GlideDownloadImageUtil 26 | { 27 | 28 | public static Observable saveImageToLocal(final Context context, final String url, final String title, final String type) 29 | { 30 | 31 | return Observable.create(new Observable.OnSubscribe() 32 | { 33 | 34 | @Override 35 | public void call(Subscriber subscriber) 36 | { 37 | 38 | File file = null; 39 | try 40 | { 41 | file = Glide.with(context) 42 | .load(url) 43 | .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) 44 | .get(); 45 | 46 | subscriber.onNext(file); 47 | } catch (InterruptedException | ExecutionException e) 48 | { 49 | e.printStackTrace(); 50 | } 51 | } 52 | }).flatMap(new Func1>() 53 | { 54 | 55 | @Override 56 | public Observable call(File file) 57 | { 58 | 59 | File mFile = null; 60 | try 61 | { 62 | 63 | LogUtil.all(file.getAbsolutePath()); 64 | String path = Environment.getExternalStorageDirectory() + File.separator + "android"; 65 | File dir = new File(path); 66 | if (!dir.exists()) 67 | { 68 | dir.mkdirs(); 69 | } 70 | 71 | String fileName = null; 72 | LogUtil.all("下载图片"); 73 | if (type.equals("jpg")) 74 | { 75 | fileName = title + SystemClock.currentThreadTimeMillis() + ".jpg"; 76 | } else if (type.equals("gif")) 77 | { 78 | fileName = title + SystemClock.currentThreadTimeMillis() + ".gif"; 79 | } 80 | 81 | mFile = new File(dir, fileName); 82 | FileInputStream fis = new FileInputStream(file.getAbsolutePath()); 83 | 84 | int byteread = 0; 85 | byte[] buf = new byte[1444]; 86 | 87 | FileOutputStream fos = new FileOutputStream(mFile.getAbsolutePath()); 88 | while ((byteread = fis.read(buf)) != -1) 89 | { 90 | fos.write(buf, 0, byteread); 91 | } 92 | 93 | fos.close(); 94 | fis.close(); 95 | } catch (Exception e) 96 | { 97 | e.printStackTrace(); 98 | LogUtil.all("图片保存失败" + e.getMessage()); 99 | } 100 | 101 | //更新本地图库 102 | Uri uri = Uri.fromFile(mFile); 103 | Intent mIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri); 104 | context.sendBroadcast(mIntent); 105 | 106 | 107 | return Observable.just(uri); 108 | } 109 | }).subscribeOn(Schedulers.io()); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/utils/LogUtil.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.utils; 2 | 3 | import android.util.Log; 4 | 5 | public class LogUtil 6 | { 7 | 8 | private static final String TAG = "LogUtil"; 9 | 10 | // 是否显示Log消息 11 | private static boolean isShow = true; 12 | 13 | public static boolean isShow() 14 | { 15 | return isShow; 16 | } 17 | 18 | public static void setShow(boolean show) 19 | { 20 | isShow = show; 21 | } 22 | 23 | public static void i(String tag, String msg) 24 | { 25 | if (isShow) 26 | Log.i(tag, msg); 27 | } 28 | 29 | public static void w(String tag, String msg) 30 | { 31 | if (isShow) 32 | Log.w(tag, msg); 33 | } 34 | 35 | public static void e(String tag, String msg) 36 | { 37 | if (isShow) 38 | Log.e(tag, msg); 39 | } 40 | 41 | public static void all(String msg) 42 | { 43 | if (isShow) 44 | Log.e("all", msg); 45 | } 46 | 47 | public static void i(String msg) 48 | { 49 | if (isShow) 50 | Log.i(TAG, msg); 51 | } 52 | 53 | public static void w(String msg) 54 | { 55 | if (isShow) 56 | Log.w(TAG, msg); 57 | } 58 | 59 | public static void e(String msg) 60 | { 61 | if (isShow) 62 | Log.e(TAG, msg); 63 | } 64 | 65 | public static void v(String msg) 66 | { 67 | if (isShow) 68 | Log.v(TAG, msg); 69 | } 70 | 71 | public static void d(String msg) 72 | { 73 | if (isShow) 74 | Log.d(TAG, msg); 75 | } 76 | 77 | public static void d(String tag, String msg) 78 | { 79 | if (isShow) 80 | Log.d(tag, msg); 81 | } 82 | 83 | public static void w(String tag, String msg, Exception e) 84 | { 85 | if (isShow) 86 | Log.w(tag, msg, e); 87 | } 88 | 89 | public static void v(String tag, String msg) 90 | { 91 | if (isShow) 92 | Log.v(tag, msg); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/utils/VibratorUtil.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.os.Vibrator; 6 | 7 | /** 8 | * 震动工具类 9 | */ 10 | public class VibratorUtil 11 | { 12 | 13 | public static void vibrator(Activity activity, long time) 14 | { 15 | Vibrator mVibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE); 16 | mVibrator.vibrate(time); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/image/RatioImageView.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.image; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ImageView; 6 | 7 | public class RatioImageView extends ImageView 8 | { 9 | 10 | private int originalWidth; 11 | 12 | private int originalHeight; 13 | 14 | 15 | public RatioImageView(Context context) 16 | { 17 | 18 | super(context); 19 | } 20 | 21 | 22 | public RatioImageView(Context context, AttributeSet attrs) 23 | { 24 | 25 | super(context, attrs); 26 | } 27 | 28 | 29 | public RatioImageView(Context context, AttributeSet attrs, int defStyleAttr) 30 | { 31 | 32 | super(context, attrs, defStyleAttr); 33 | } 34 | 35 | 36 | public void setOriginalSize(int originalWidth, int originalHeight) 37 | { 38 | 39 | this.originalWidth = originalWidth; 40 | this.originalHeight = originalHeight; 41 | } 42 | 43 | 44 | @Override 45 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 46 | { 47 | 48 | if (originalWidth > 0 && originalHeight > 0) 49 | { 50 | float ratio = (float) originalWidth / (float) originalHeight; 51 | 52 | int width = MeasureSpec.getSize(widthMeasureSpec); 53 | int height = MeasureSpec.getSize(heightMeasureSpec); 54 | 55 | if (width > 0) 56 | { 57 | height = (int) ((float) width / ratio); 58 | } 59 | 60 | setMeasuredDimension(width, height); 61 | } else 62 | { 63 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 64 | } 65 | } 66 | 67 | 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/loading/LoadCircular.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.loading; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.util.AttributeSet; 8 | import android.view.View; 9 | 10 | 11 | public class LoadCircular extends View 12 | { 13 | 14 | private Paint mPaint; 15 | 16 | private float width = 0f; 17 | 18 | private float maxRadius = 0f; 19 | 20 | private int startAngle = 0; 21 | 22 | public LoadCircular(Context context) 23 | { 24 | 25 | this(context, null); 26 | } 27 | 28 | public LoadCircular(Context context, AttributeSet attrs) 29 | { 30 | 31 | this(context, attrs, 0); 32 | } 33 | 34 | public LoadCircular(Context context, AttributeSet attrs, int defStyleAttr) 35 | { 36 | 37 | super(context, attrs, defStyleAttr); 38 | init(); 39 | } 40 | 41 | private void init() 42 | { 43 | //初始化画笔 44 | mPaint = new Paint(); 45 | mPaint.setAntiAlias(true); 46 | mPaint.setStyle(Paint.Style.FILL); 47 | mPaint.setColor(Color.BLACK); 48 | } 49 | 50 | @Override 51 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 52 | { 53 | 54 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 55 | 56 | if (getMeasuredWidth() > getHeight()) 57 | { 58 | width = getMeasuredHeight(); 59 | } else 60 | { 61 | width = getMeasuredWidth(); 62 | } 63 | 64 | maxRadius = width / 30f; 65 | } 66 | 67 | @Override 68 | protected void onDraw(Canvas canvas) 69 | { 70 | 71 | for (int i = 0; i < 9; i++) 72 | { 73 | float x1 = (float) ((width / 2f - maxRadius) * Math.cos(startAngle + 45f * i * Math.PI / 180f)); 74 | float y1 = (float) ((width / 2f - maxRadius) * Math.sin(startAngle + 45f * i * Math.PI / 180f)); 75 | 76 | canvas.drawCircle(width / 2f - x1, width / 2f - y1, maxRadius, mPaint); 77 | } 78 | 79 | canvas.drawCircle(width / 2f, width / 2f, width / 2f - maxRadius * 6, mPaint); 80 | 81 | 82 | super.onDraw(canvas); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/loading/LoadCircularCD.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.loading; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.RectF; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | public class LoadCircularCD extends View 12 | { 13 | float width = 0f; 14 | 15 | float padding = 0f; 16 | 17 | private Paint mPaint; 18 | 19 | public LoadCircularCD(Context context) 20 | { 21 | this(context, null); 22 | } 23 | 24 | public LoadCircularCD(Context context, AttributeSet attrs) 25 | { 26 | this(context, null, 0); 27 | } 28 | 29 | public LoadCircularCD(Context context, AttributeSet attrs, int defStyleAttr) 30 | { 31 | super(context, attrs, defStyleAttr); 32 | init(); 33 | } 34 | 35 | private void init() 36 | { 37 | mPaint = new Paint(); 38 | mPaint.setAntiAlias(true); 39 | mPaint.setStyle(Paint.Style.STROKE); 40 | mPaint.setColor(Color.BLACK); 41 | 42 | } 43 | 44 | @Override 45 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 46 | { 47 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 48 | 49 | if (getMeasuredWidth() > getHeight()) 50 | { 51 | width = getMeasuredHeight(); 52 | } 53 | else 54 | { 55 | width = getMeasuredWidth(); 56 | } 57 | 58 | padding = 5f; 59 | 60 | 61 | } 62 | 63 | @Override 64 | protected void onDraw(Canvas canvas) 65 | { 66 | 67 | canvas.save(); 68 | mPaint.setStrokeWidth(2); 69 | //绘制外层圆形 70 | canvas.drawCircle(width / 2, width / 2, width / 2 - padding, mPaint); 71 | mPaint.setStrokeWidth(3); 72 | //绘制内圈圆形 73 | canvas.drawCircle(width / 2, width / 2, padding, mPaint); 74 | 75 | //绘制左边两个圆弧 76 | mPaint.setStrokeWidth(3); 77 | RectF rectF1 = new RectF(); 78 | rectF1.set(width / 2 - width / 3, width / 2 - width / 3, 79 | width / 2 + width / 3, width / 2 + width / 3); 80 | canvas.drawArc(rectF1, 0, 80, false, mPaint); 81 | canvas.drawArc(rectF1, 180, 80, false, mPaint); 82 | 83 | mPaint.setStrokeWidth(2); 84 | RectF rectF2 = new RectF(); 85 | rectF2.set(width / 2 - width / 4, width / 2 - width / 4, 86 | width / 2 + width / 4, width / 2 + width / 4); 87 | canvas.drawArc(rectF2, 0, 80, false, mPaint); 88 | canvas.drawArc(rectF2, 180, 80, false, mPaint); 89 | 90 | 91 | super.onDraw(canvas); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/lovelayout/BezierEvaluator.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.lovelayout; 2 | 3 | import android.animation.TypeEvaluator; 4 | import android.graphics.PointF; 5 | 6 | public class BezierEvaluator implements TypeEvaluator 7 | { 8 | 9 | 10 | private PointF pointF1; 11 | private PointF pointF2; 12 | 13 | public BezierEvaluator(PointF pointF1, PointF pointF2) 14 | { 15 | this.pointF1 = pointF1; 16 | this.pointF2 = pointF2; 17 | } 18 | 19 | @Override 20 | public PointF evaluate(float time, PointF startValue, PointF endValue) 21 | { 22 | 23 | float timeLeft = 1.0f - time; 24 | PointF point = new PointF();//结果 25 | 26 | point.x = timeLeft * timeLeft * timeLeft * (startValue.x) 27 | + 3 * timeLeft * timeLeft * time * (pointF1.x) 28 | + 3 * timeLeft * time * time * (pointF2.x) 29 | + time * time * time * (endValue.x); 30 | 31 | point.y = timeLeft * timeLeft * timeLeft * (startValue.y) 32 | + 3 * timeLeft * timeLeft * time * (pointF1.y) 33 | + 3 * timeLeft * time * time * (pointF2.y) 34 | + time * time * time * (endValue.y); 35 | return point; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/other/Bezaer.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.other; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.graphics.PointF; 9 | import android.util.AttributeSet; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | 13 | /** 14 | * 二阶贝塞尔曲线练习 15 | */ 16 | public class Bezaer extends View 17 | { 18 | 19 | private Paint mPaint; 20 | 21 | private int centerX, centerY; 22 | 23 | private PointF start, end, center; 24 | 25 | public Bezaer(Context context) 26 | { 27 | this(context, null); 28 | } 29 | 30 | public Bezaer(Context context, AttributeSet attrs) 31 | { 32 | this(context, attrs, 0); 33 | } 34 | 35 | public Bezaer(Context context, AttributeSet attrs, int defStyleAttr) 36 | { 37 | super(context, attrs, defStyleAttr); 38 | init(); 39 | } 40 | 41 | /** 42 | * 初始化 43 | */ 44 | private void init() 45 | { 46 | 47 | mPaint = new Paint(); 48 | mPaint.setAntiAlias(true); 49 | mPaint.setColor(Color.BLACK); 50 | mPaint.setStrokeWidth(8); 51 | mPaint.setStyle(Paint.Style.STROKE); 52 | mPaint.setTextSize(60); 53 | 54 | start = new PointF(0, 0); 55 | end = new PointF(0, 0); 56 | center = new PointF(0, 0); 57 | 58 | 59 | } 60 | 61 | @Override 62 | protected void onSizeChanged(int w, int h, int oldw, int oldh) 63 | { 64 | super.onSizeChanged(w, h, oldw, oldh); 65 | 66 | centerX = w / 2; 67 | centerY = h / 2; 68 | 69 | //初始化数据点跟控制点的位置 70 | start.x = centerX - 200; 71 | start.y = centerY; 72 | end.x = centerX + 200; 73 | end.y = centerY; 74 | center.x = centerX; 75 | center.y = centerY - 100; 76 | } 77 | 78 | 79 | @Override 80 | public boolean onTouchEvent(MotionEvent event) 81 | { 82 | //根据触摸位置更新控制点 并进行重绘 83 | float x = event.getX(); 84 | float y = event.getY(); 85 | 86 | center.x = x; 87 | center.y = y; 88 | 89 | invalidate(); 90 | 91 | return true; 92 | } 93 | 94 | @Override 95 | protected void onDraw(Canvas canvas) 96 | { 97 | super.onDraw(canvas); 98 | 99 | //绘制控制点 100 | mPaint.setColor(Color.GRAY); 101 | mPaint.setStrokeWidth(20); 102 | canvas.drawPoint(start.x, start.y, mPaint); 103 | canvas.drawPoint(end.x, end.y, mPaint); 104 | canvas.drawPoint(center.x, center.y, mPaint); 105 | 106 | //绘制辅助线 107 | mPaint.setStrokeWidth(4); 108 | canvas.drawLine(start.x, start.y, center.x, center.y, mPaint); 109 | canvas.drawLine(end.x, end.y, center.x, center.y, mPaint); 110 | 111 | //绘制贝塞尔曲线 112 | mPaint.setColor(Color.RED); 113 | mPaint.setStrokeWidth(10); 114 | 115 | //根据路径来绘制贝塞尔曲线的 这里是二阶贝塞尔曲线 116 | Path mPath = new Path(); 117 | mPath.moveTo(start.x, start.y); 118 | mPath.quadTo(center.x, center.y, end.x, end.y); 119 | 120 | canvas.drawPath(mPath, mPaint); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/other/Bezaer1.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.other; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.util.AttributeSet; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | import android.view.ViewConfiguration; 12 | 13 | /** 14 | * Created by hcc on 2016/7/21. 15 | */ 16 | public class Bezaer1 extends View 17 | { 18 | 19 | private Path mPath; 20 | 21 | private Paint mPaint; 22 | 23 | private float mX; 24 | 25 | private float mY; 26 | 27 | private float offset = ViewConfiguration.get(getContext()).getScaledTouchSlop(); 28 | 29 | public Bezaer1(Context context) 30 | { 31 | this(context, null); 32 | } 33 | 34 | public Bezaer1(Context context, AttributeSet attrs) 35 | { 36 | this(context, attrs, 0); 37 | } 38 | 39 | public Bezaer1(Context context, AttributeSet attrs, int defStyleAttr) 40 | { 41 | super(context, attrs, defStyleAttr); 42 | 43 | init(); 44 | 45 | } 46 | 47 | private void init() 48 | { 49 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 50 | mPaint.setColor(Color.BLACK); 51 | mPaint.setStyle(Paint.Style.STROKE); 52 | mPaint.setStrokeWidth(5); 53 | 54 | mPath = new Path(); 55 | } 56 | 57 | @Override 58 | public boolean onTouchEvent(MotionEvent event) 59 | { 60 | switch (event.getAction()) 61 | { 62 | case MotionEvent.ACTION_DOWN: 63 | 64 | mPaint.reset(); 65 | //获取按下的点 66 | float x = event.getX(); 67 | float y = event.getY(); 68 | mX = x; 69 | mY = y; 70 | 71 | mPath.moveTo(x, y); 72 | 73 | break; 74 | 75 | case MotionEvent.ACTION_MOVE: 76 | //移动时候进行涂鸦 77 | float x1 = event.getX(); 78 | float y1 = event.getY(); 79 | float preX = mX; 80 | float preY = mY; 81 | float dx = Math.abs(x1 - preX); 82 | float dy = Math.abs(y1 - preY); 83 | if (dx >= offset || dy >= offset) 84 | { 85 | //贝塞尔曲线的控制点为起点和终点的中间点 86 | float cX = (x1 + preX) / 2; 87 | float cY = (y1 + preY) / 2; 88 | //mPath.quadTo(preX, preY, cX, cY); 89 | mPath.lineTo(x1 , y1); 90 | mX = x1; 91 | mX = y1; 92 | 93 | } 94 | 95 | 96 | } 97 | invalidate(); 98 | return true; 99 | } 100 | 101 | @Override 102 | protected void onDraw(Canvas canvas) 103 | { 104 | super.onDraw(canvas); 105 | canvas.drawPath(mPath, mPaint); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/other/Bezaer2.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.other; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | import android.view.animation.BounceInterpolator; 11 | 12 | /** 13 | * Created by hcc on 2016/7/21. 14 | */ 15 | public class Bezaer2 extends View implements View.OnClickListener 16 | { 17 | 18 | private Paint mPaint; 19 | 20 | private Paint mAuxiliaryPaint; 21 | 22 | private Paint mAuxiliaryTextPaint; 23 | 24 | private float mAuxiliaryOneX; 25 | 26 | private float mAuxiliaryOneY; 27 | 28 | private float mAuxiliaryTwoX; 29 | 30 | private float mAuxiliaryTwoY; 31 | 32 | private float mStartPointX; 33 | 34 | private float mStartPointY; 35 | 36 | private float mEndPointX; 37 | 38 | private float mEndPointY; 39 | 40 | private int width; 41 | 42 | private int height; 43 | 44 | private Path mPath = new Path(); 45 | 46 | private ValueAnimator valueAnimator; 47 | 48 | public Bezaer2(Context context) 49 | { 50 | this(context, null); 51 | } 52 | 53 | public Bezaer2(Context context, AttributeSet attrs) 54 | { 55 | this(context, null, 0); 56 | } 57 | 58 | public Bezaer2(Context context, AttributeSet attrs, int defStyleAttr) 59 | { 60 | super(context, attrs, defStyleAttr); 61 | init(); 62 | } 63 | 64 | private void init() 65 | { 66 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 67 | mPaint.setStyle(Paint.Style.STROKE); 68 | mPaint.setStrokeWidth(7); 69 | 70 | mAuxiliaryPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 71 | mAuxiliaryPaint.setStyle(Paint.Style.STROKE); 72 | mAuxiliaryPaint.setStrokeWidth(2); 73 | 74 | mAuxiliaryTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 75 | mAuxiliaryTextPaint.setStyle(Paint.Style.STROKE); 76 | mAuxiliaryTextPaint.setTextSize(20); 77 | 78 | setOnClickListener(this); 79 | 80 | 81 | } 82 | 83 | @Override 84 | protected void onSizeChanged(int w, int h, int oldw, int oldh) 85 | { 86 | super.onSizeChanged(w, h, oldw, oldh); 87 | 88 | //确定各点的位置 89 | mStartPointX = w / 4; 90 | mStartPointY = h - 200; 91 | 92 | mEndPointX = w / 4 * 3; 93 | mEndPointY = h - 200; 94 | 95 | mAuxiliaryOneX = mStartPointX; 96 | mAuxiliaryOneY = mStartPointY; 97 | 98 | mAuxiliaryTwoX = mEndPointX; 99 | mAuxiliaryTwoY = mEndPointY; 100 | 101 | width = w; 102 | height = h; 103 | 104 | //设置动画 105 | valueAnimator = ValueAnimator.ofFloat(mStartPointY, h); 106 | valueAnimator.setInterpolator(new BounceInterpolator()); 107 | valueAnimator.setDuration(1000); 108 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() 109 | { 110 | @Override 111 | public void onAnimationUpdate(ValueAnimator valueAnimator) 112 | { 113 | mAuxiliaryOneY = (float) valueAnimator.getAnimatedValue(); 114 | mAuxiliaryTwoY = (float) valueAnimator.getAnimatedValue(); 115 | invalidate(); 116 | } 117 | }); 118 | 119 | 120 | } 121 | 122 | @Override 123 | protected void onDraw(Canvas canvas) 124 | { 125 | super.onDraw(canvas); 126 | 127 | canvas.save(); 128 | canvas.translate(width / 2, height / 2); 129 | 130 | mPath.reset(); 131 | mPath.moveTo(mStartPointX, mStartPointY); 132 | 133 | //绘制辅助点 134 | canvas.drawPoint(mAuxiliaryOneX, mAuxiliaryOneY, mAuxiliaryPaint); 135 | //绘制文字 136 | canvas.drawText("辅助点1", mAuxiliaryOneX, mAuxiliaryOneY, mAuxiliaryTextPaint); 137 | canvas.drawText("辅助点2", mAuxiliaryTwoX, mAuxiliaryTwoY, mAuxiliaryTextPaint); 138 | canvas.drawText("起始点", mStartPointX, mStartPointY, mAuxiliaryTextPaint); 139 | canvas.drawText("终止点", mEndPointX, mEndPointY, mAuxiliaryTextPaint); 140 | //绘制辅助线 141 | canvas.drawLine(mStartPointX, mStartPointY, mAuxiliaryOneX, mAuxiliaryOneY, mAuxiliaryPaint); 142 | canvas.drawLine(mEndPointX, mEndPointY, mAuxiliaryTwoX, mAuxiliaryTwoY, mAuxiliaryPaint); 143 | canvas.drawLine(mAuxiliaryOneX, mAuxiliaryOneY, mAuxiliaryTwoX, mAuxiliaryTwoY, mAuxiliaryPaint); 144 | //三阶贝塞尔曲线 145 | mPath.cubicTo(mAuxiliaryOneX, mAuxiliaryOneY, mAuxiliaryTwoX, mAuxiliaryTwoY, mEndPointX, mEndPointY); 146 | canvas.drawPath(mPath, mPaint); 147 | 148 | canvas.restore(); 149 | 150 | } 151 | 152 | @Override 153 | public void onClick(View view) 154 | { 155 | valueAnimator.start(); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/other/CustomProgressBar.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.other; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.Paint.Style; 8 | import android.graphics.RectF; 9 | import android.util.AttributeSet; 10 | import android.view.View; 11 | 12 | 13 | public class CustomProgressBar extends View 14 | { 15 | 16 | private int mCenterX; 17 | 18 | private int mCenterY; 19 | 20 | private Paint mPaint; 21 | 22 | private int mRadius0 = 87; 23 | 24 | private int mRadius1 = 97; 25 | 26 | private int mRadius = 113; 27 | 28 | private int mRadius2 = 130; 29 | 30 | private int mRadius3 = 150; 31 | 32 | private RectF mOval = new RectF(); 33 | 34 | private RectF mOval2 = new RectF(); 35 | 36 | private RectF mOval3 = new RectF(); 37 | 38 | private float mCurrentAngle = 270; 39 | 40 | private float mStartAngle = 135; 41 | 42 | private float mEndAngle = 270; 43 | 44 | /** 45 | * @param context 46 | * @param attrs 47 | */ 48 | public CustomProgressBar(Context context, AttributeSet attrs) 49 | { 50 | super(context, attrs); 51 | mPaint = new Paint(); 52 | mPaint.setAntiAlias(true); 53 | mPaint.setStyle(Style.STROKE); 54 | mPaint.setColor(Color.RED); 55 | } 56 | 57 | @Override 58 | protected synchronized void onDraw(Canvas canvas) 59 | { 60 | mCenterX = getWidth() / 2; 61 | mCenterY = getHeight() / 2; 62 | mOval.set(mCenterX - mRadius, mCenterY - mRadius, mCenterX + mRadius, mCenterY + mRadius); 63 | mOval2.set(mCenterX - mRadius2, mCenterY - mRadius2, mCenterX + mRadius2, mCenterY + mRadius2); 64 | mOval3.set(mCenterX - mRadius3, mCenterY - mRadius3, mCenterX + mRadius3, mCenterY + mRadius3); 65 | 66 | mPaint.setStrokeWidth(2); 67 | mPaint.setAlpha(26); 68 | canvas.drawArc(mOval3, mStartAngle, mEndAngle, false, mPaint); 69 | 70 | mPaint.setAlpha(51); 71 | canvas.drawArc(mOval2, mStartAngle, mEndAngle, false, mPaint); 72 | 73 | mPaint.setAlpha(153); 74 | drawLines(canvas); 75 | 76 | mPaint.setStrokeWidth(20); 77 | mPaint.setAlpha(102); 78 | canvas.drawArc(mOval, mStartAngle, mEndAngle, false, mPaint); 79 | 80 | 81 | mPaint.setAlpha(255); 82 | canvas.drawArc(mOval, mStartAngle, mCurrentAngle, false, mPaint); 83 | } 84 | 85 | private void drawLines(Canvas canvas) 86 | { 87 | for (int angle = 0; angle < 360; angle += 3) 88 | { 89 | double d = 2 * Math.PI * angle / 360; 90 | float x0 = (float) (mRadius0 * Math.cos(d) + mCenterX); 91 | float y0 = (float) (mRadius0 * Math.sin(d) + mCenterY); 92 | float x1 = (float) (mRadius1 * Math.cos(d) + mCenterX); 93 | float y1 = (float) (mRadius1 * Math.sin(d) + mCenterY); 94 | canvas.drawLine(x0, y0, x1, y1, mPaint); 95 | } 96 | } 97 | 98 | public void setPercentage(float percent) 99 | { 100 | // mCurrentAngle = mStartAngle + percent * (mEndAngle - mStartAngle); 101 | mCurrentAngle = percent * mEndAngle; 102 | invalidate(); 103 | } 104 | 105 | public float getPercentage() 106 | { 107 | return 0.0f; 108 | } 109 | } -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/other/DragView.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.other; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | import android.view.View; 8 | import android.widget.Scroller; 9 | 10 | 11 | /** 12 | * View滑动的几种方法 13 | *

14 | * 1.layout方法: 15 | * 在View进行绘制时,会调用onLayout()方法来设置显示的位置, 16 | * 因此,我们可以通过修改View的left、top、right、bottom四个属性来控制View的坐标。 17 | * 要控制View随手指滑动,因此需要在onTouchEvent()事件中进行滑动控制 18 | *

19 | * 2.offsetLeftAndRight()和offsetTopAndBottom() 20 | *

21 | * 3.LayoutParams 22 | *

23 | * 4.scrollTo与scrollBy 24 | *

25 | * 5.Scroller辅助类 26 | */ 27 | public class DragView extends View 28 | { 29 | 30 | int lastX; 31 | 32 | int lastY; 33 | 34 | int defultWidth = dp2px(200); 35 | 36 | int defultHeight = dp2px(200); 37 | 38 | Scroller mScroller; 39 | 40 | public DragView(Context context) 41 | { 42 | this(context, null); 43 | } 44 | 45 | public DragView(Context context, AttributeSet attrs) 46 | { 47 | this(context, attrs, 0); 48 | } 49 | 50 | public DragView(Context context, AttributeSet attrs, int defStyleAttr) 51 | { 52 | super(context, attrs, defStyleAttr); 53 | init(); 54 | } 55 | 56 | private void init() 57 | { 58 | setBackgroundColor(Color.RED); 59 | mScroller = new Scroller(getContext()); 60 | } 61 | 62 | /** 63 | * easureSpec.EXACTLY:表示确定大小, 64 | * MeasureSpec.AT_MOST:表示最大大小, 65 | * MeasureSpec.UNSPECIFIED:不确定。 66 | * 67 | * @param widthMeasureSpec 68 | * @param heightMeasureSpec 69 | */ 70 | @Override 71 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 72 | { 73 | int widthSize = MeasureSpec.getSize(widthMeasureSpec); 74 | int heightSize = MeasureSpec.getSize(heightMeasureSpec); 75 | int widthMode = MeasureSpec.getMode(widthMeasureSpec); 76 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 77 | 78 | if (widthMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.AT_MOST) 79 | { 80 | widthSize = defultWidth; 81 | heightSize = defultHeight; 82 | } 83 | 84 | 85 | setMeasuredDimension(widthSize, heightSize); 86 | } 87 | 88 | @Override 89 | public boolean onTouchEvent(MotionEvent event) 90 | { 91 | int x = (int) event.getX(); 92 | int y = (int) event.getY(); 93 | 94 | switch (event.getAction()) 95 | { 96 | case MotionEvent.ACTION_DOWN: 97 | //触摸事件按下的点 98 | lastX = x; 99 | lastY = y; 100 | break; 101 | 102 | 103 | case MotionEvent.ACTION_MOVE: 104 | 105 | //触摸事件移动时的点 106 | int offsetX = x - lastX; 107 | int offsetY = y - lastY; 108 | 109 | // layout(getLeft() + offsetX, 110 | // getTop() + offsetY, 111 | // getRight() + offsetX, 112 | // getBottom() + offsetY); 113 | 114 | // offsetLeftAndRight(offsetX); 115 | // offsetTopAndBottom(offsetY); 116 | 117 | // ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams(); 118 | // layoutParams.leftMargin = getLeft() + offsetX; 119 | // layoutParams.topMargin = getTop() + offsetY; 120 | // setLayoutParams(layoutParams); 121 | 122 | 123 | //使用ScrollBy进行滑动 这里需要使用与平常相反的坐标 124 | int scrollX = lastX - x; 125 | int scrollY = lastY - y; 126 | //调用ViewGroup的ScrollBy进行滑动 127 | ((View) getParent()).scrollBy(scrollX, scrollY); 128 | 129 | 130 | break; 131 | 132 | case MotionEvent.ACTION_UP: 133 | View mViewGroup = (View) getParent(); 134 | mScroller.startScroll(mViewGroup.getScrollX(), mViewGroup.getScrollY() 135 | , -mViewGroup.getScrollX(), -mViewGroup.getScrollY()); 136 | 137 | invalidate(); 138 | 139 | break; 140 | } 141 | 142 | 143 | return true; 144 | } 145 | 146 | @Override 147 | public void computeScroll() 148 | { 149 | if (mScroller.computeScrollOffset()) 150 | { 151 | ((View) getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); 152 | invalidate(); 153 | } 154 | 155 | super.computeScroll(); 156 | } 157 | 158 | public int dp2px(int dp) 159 | { 160 | float density = getContext().getResources().getDisplayMetrics().density; 161 | int px = (int) ((dp * density) + 0.5f); 162 | 163 | return px; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/other/HackyViewPager.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.other; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.ViewPager; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | 8 | import io.netopen.hotbitmapgg.androideverydaypractice.widget.image.PhotoImageView; 9 | 10 | 11 | public class HackyViewPager extends ViewPager 12 | { 13 | 14 | public HackyViewPager(Context context) 15 | { 16 | 17 | super(context); 18 | } 19 | 20 | public HackyViewPager(Context context, AttributeSet attrs) 21 | { 22 | 23 | super(context, attrs); 24 | } 25 | 26 | @Override 27 | protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) 28 | { 29 | 30 | if (v instanceof PhotoImageView) 31 | { 32 | return ((PhotoImageView) v).canScrollHorizontallyFroyo(-dx); 33 | } else 34 | { 35 | return super.canScroll(v, checkV, dx, x, y); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/other/ItemArrowCardView.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.other; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | import android.widget.RelativeLayout; 8 | import android.widget.TextView; 9 | 10 | import butterknife.Bind; 11 | import butterknife.ButterKnife; 12 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 13 | 14 | 15 | public class ItemArrowCardView extends RelativeLayout 16 | { 17 | 18 | private String name; 19 | 20 | @Bind(R.id.arrow_name) 21 | TextView mTextView; 22 | 23 | public ItemArrowCardView(Context context) 24 | { 25 | 26 | this(context, null); 27 | } 28 | 29 | public ItemArrowCardView(Context context, AttributeSet attrs) 30 | { 31 | 32 | this(context, attrs, 0); 33 | } 34 | 35 | public ItemArrowCardView(Context context, AttributeSet attrs, int defStyleAttr) 36 | { 37 | 38 | super(context, attrs, defStyleAttr); 39 | 40 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ItemArrowCardView); 41 | name = typedArray.getString(R.styleable.ItemArrowCardView_name); 42 | typedArray.recycle(); 43 | 44 | View view = inflate(context, R.layout.layout_item_arrow_view, this); 45 | ButterKnife.bind(view); 46 | 47 | init(); 48 | } 49 | 50 | /** 51 | * 初始化 52 | */ 53 | private void init() 54 | { 55 | 56 | mTextView.setText(name); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/other/MemoryClearView.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.other; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.View; 6 | 7 | /** 8 | * Created by hcc on 16/7/24 12:19 9 | * 100332338@qq.com 10 | */ 11 | public class MemoryClearView extends View 12 | { 13 | 14 | public MemoryClearView(Context context, AttributeSet attrs) 15 | { 16 | 17 | super(context, attrs); 18 | } 19 | 20 | public MemoryClearView(Context context) 21 | { 22 | 23 | super(context); 24 | } 25 | 26 | public MemoryClearView(Context context, AttributeSet attrs, int defStyleAttr) 27 | { 28 | 29 | super(context, attrs, defStyleAttr); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/other/NestedSpringScrollView.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.other; 2 | 3 | import android.animation.ObjectAnimator; 4 | import android.content.Context; 5 | import android.graphics.Rect; 6 | import android.support.v4.widget.NestedScrollView; 7 | import android.util.AttributeSet; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | 11 | 12 | public class NestedSpringScrollView extends NestedScrollView 13 | { 14 | 15 | // data 16 | private static final float MOVE_FACTOR = 0.5f; // 移动因子,手指移动100px,那么View就只移动50px 17 | 18 | private static final int ANIM_TIME = 300; // 松开手指后, 界面回到正常位置需要的动画时间 19 | 20 | private float startY;// 手指按下时的Y值, 用于在移动时计算移动距离,如果按下时不能上拉和下拉, 21 | // 会在手指移动时更新为当前手指的Y值 22 | 23 | // ui 24 | private View contentView; // ScrollView的唯一内容控件 25 | 26 | private Rect originalRect = new Rect();// 用于记录正常的布局位置 27 | 28 | // flag 29 | private boolean canPullDown = false; // 是否可以继续下拉 30 | 31 | private boolean canPullUp = false; // 是否可以继续上拉 32 | 33 | private boolean isMoved = false; // 记录是否移动了布局 34 | 35 | public NestedSpringScrollView(Context context) 36 | { 37 | 38 | super(context); 39 | } 40 | 41 | public NestedSpringScrollView(Context context, AttributeSet attrs) 42 | { 43 | 44 | super(context, attrs); 45 | } 46 | 47 | public NestedSpringScrollView(Context context, AttributeSet attrs, int defStyle) 48 | { 49 | 50 | super(context, attrs, defStyle); 51 | } 52 | 53 | 54 | @Override 55 | protected void onFinishInflate() 56 | { 57 | 58 | if (getChildCount() > 0) 59 | { 60 | contentView = getChildAt(0); 61 | } 62 | 63 | super.onFinishInflate(); 64 | } 65 | 66 | @Override 67 | protected void onLayout(boolean changed, int l, int t, int r, int b) 68 | { 69 | 70 | super.onLayout(changed, l, t, r, b); 71 | if (contentView == null) 72 | return; 73 | // ScrollView中的唯一子控件的位置信息, 这个位置信息在整个控件的生命周期中保持不变 74 | originalRect.set(contentView.getLeft(), contentView.getTop(), contentView.getRight(), contentView.getBottom()); 75 | } 76 | 77 | /** 78 | * 在触摸事件中, 处理上拉和下拉的逻辑 79 | */ 80 | @Override 81 | public boolean dispatchTouchEvent(MotionEvent ev) 82 | { 83 | 84 | if (contentView == null) 85 | { 86 | return super.dispatchTouchEvent(ev); 87 | } 88 | // 手指是否移动到了当前ScrollView控件之外 89 | boolean isTouchOutOfScrollView = ev.getY() >= this.getHeight() || ev.getY() <= 0; 90 | if (isTouchOutOfScrollView) 91 | { // 如果移动到了当前ScrollView控件之外 92 | if (isMoved) // 如果当前contentView已经被移动, 首先把布局移到原位置, 然后消费点这个事件 93 | boundBack(); 94 | return true; 95 | } 96 | int action = ev.getAction(); 97 | switch (action) 98 | { 99 | case MotionEvent.ACTION_DOWN: 100 | // 判断是否可以上拉和下拉 101 | canPullDown = isCanPullDown(); 102 | canPullUp = isCanPullUp(); 103 | // 记录按下时的Y值 104 | startY = ev.getY(); 105 | break; 106 | case MotionEvent.ACTION_UP: 107 | boundBack(); 108 | break; 109 | case MotionEvent.ACTION_MOVE: 110 | // 在移动的过程中, 既没有滚动到可以上拉的程度, 也没有滚动到可以下拉的程度 111 | if (!canPullDown && !canPullUp) 112 | { 113 | startY = ev.getY(); 114 | canPullDown = isCanPullDown(); 115 | canPullUp = isCanPullUp(); 116 | break; 117 | } 118 | // 计算手指移动的距离 119 | float nowY = ev.getY(); 120 | int deltaY = (int) (nowY - startY); 121 | 122 | // 是否应该移动布局 123 | boolean shouldMove = (canPullDown && deltaY > 0) // 可以下拉, 并且手指向下移动 124 | || (canPullUp && deltaY < 0) // 可以上拉, 并且手指向上移动 125 | || (canPullUp && canPullDown); // 既可以上拉也可以下拉(这种情况出现在ScrollView包裹的控件比ScrollView还小) 126 | if (shouldMove) 127 | { 128 | // 计算偏移量 129 | int offset = (int) (deltaY * MOVE_FACTOR); 130 | // 随着手指的移动而移动布局 131 | contentView.layout(originalRect.left, originalRect.top + offset, originalRect.right, 132 | originalRect.bottom + offset); 133 | isMoved = true; // 记录移动了布局 134 | } 135 | break; 136 | } 137 | return super.dispatchTouchEvent(ev); 138 | } 139 | 140 | /** 141 | * 将内容布局移动到原位置 可以在UP事件中调用, 也可以在其他需要的地方调用, 如手指移动到当前ScrollView外时 142 | */ 143 | private void boundBack() 144 | { 145 | 146 | if (!isMoved) 147 | return; // 如果没有移动布局, 则跳过执行 148 | // 开启动画 149 | // TranslateAnimation anim = new TranslateAnimation(0, 0, contentView.getTop(), originalRect.top); 150 | // anim.setDuration(ANIM_TIME); 151 | // contentView.startAnimation(anim); 152 | 153 | ObjectAnimator.ofFloat(contentView, View.TRANSLATION_Y, contentView.getTop(), originalRect.top) 154 | .setDuration(ANIM_TIME) 155 | .start(); 156 | // 设置回到正常的布局位置 157 | contentView.layout(originalRect.left, originalRect.top, originalRect.right, originalRect.bottom); 158 | // 将标志位设回false 159 | canPullDown = false; 160 | canPullUp = false; 161 | isMoved = false; 162 | } 163 | 164 | /** 165 | * 判断是否滚动到顶部 166 | */ 167 | private boolean isCanPullDown() 168 | { 169 | 170 | return getScrollY() == 0 || contentView.getHeight() < getHeight() + getScrollY(); 171 | } 172 | 173 | /** 174 | * 判断是否滚动到底部 175 | */ 176 | private boolean isCanPullUp() 177 | { 178 | 179 | return contentView.getHeight() <= getHeight() + getScrollY(); 180 | } 181 | } -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/other/PathDemoView.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.other; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Canvas; 7 | import android.graphics.Color; 8 | import android.graphics.Matrix; 9 | import android.graphics.Paint; 10 | import android.graphics.Path; 11 | import android.graphics.PathMeasure; 12 | import android.util.AttributeSet; 13 | import android.view.View; 14 | 15 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 16 | 17 | 18 | /** 19 | * Created by hcc on 2016/7/27. 20 | *

21 | * 自定义控件学习之Path练习 22 | */ 23 | public class PathDemoView extends View 24 | { 25 | 26 | private Paint mPaint; 27 | 28 | private int width; 29 | 30 | private int height; 31 | 32 | //用来记录当前的位置 取值[0,1] 映射整个path的长度 33 | private float currentValues = 0; 34 | 35 | //当前的点的实际位置 36 | private float[] pos; 37 | 38 | //当前的切线值 用于计算图片旋转的角度 39 | private float[] tan; 40 | 41 | //小箭头图片 42 | private Bitmap bitmap; 43 | 44 | //图片旋转所需要的矩阵 45 | private Matrix matrix; 46 | 47 | private Path path; 48 | 49 | public PathDemoView(Context context) 50 | { 51 | 52 | this(context, null); 53 | } 54 | 55 | public PathDemoView(Context context, AttributeSet attrs) 56 | { 57 | 58 | this(context, attrs, 0); 59 | } 60 | 61 | public PathDemoView(Context context, AttributeSet attrs, int defStyleAttr) 62 | { 63 | 64 | super(context, attrs, defStyleAttr); 65 | init(); 66 | } 67 | 68 | private void init() 69 | { 70 | //初始化变量 71 | pos = new float[2]; 72 | tan = new float[2]; 73 | 74 | BitmapFactory.Options options = new BitmapFactory.Options(); 75 | options.inSampleSize = 2; 76 | bitmap = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.icon_arrow, options); 77 | 78 | matrix = new Matrix(); 79 | 80 | mPaint = new Paint(); 81 | mPaint.setAntiAlias(true); 82 | mPaint.setStyle(Paint.Style.STROKE); 83 | mPaint.setStrokeWidth(8); 84 | mPaint.setColor(Color.BLACK); 85 | 86 | path = new Path(); 87 | } 88 | 89 | @Override 90 | protected void onSizeChanged(int w, int h, int oldw, int oldh) 91 | { 92 | 93 | super.onSizeChanged(w, h, oldw, oldh); 94 | width = w; 95 | height = h; 96 | } 97 | 98 | @Override 99 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 100 | { 101 | 102 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 103 | } 104 | 105 | @Override 106 | protected void onDraw(Canvas canvas) 107 | { 108 | //移动中心点 109 | canvas.translate(width / 2, height / 2); 110 | //添加一个圆 111 | path.addCircle(0, 0, 200, Path.Direction.CW); 112 | //创建pathMeasure 用于测量path 113 | PathMeasure pathMeasure = new PathMeasure(path, false); 114 | //计算当前位置在总长度上的比例 115 | currentValues += 0.05; 116 | if (currentValues >= 1) 117 | { 118 | currentValues = 0; 119 | } 120 | 121 | //获取path当前位置的坐标 122 | pathMeasure.getPosTan(pathMeasure.getLength() * currentValues, pos, tan); 123 | //重置Matrix 124 | matrix.reset(); 125 | //计算图片选装的角度 126 | float dagress = (float) Math.atan2(tan[1], tan[0] * 180 / Math.PI); 127 | //旋转图片 128 | matrix.postRotate(dagress, bitmap.getWidth() / 2, bitmap.getHeight() / 2); 129 | //图片默认是由左上角顶点开始 这里把他移动到图片中心点进行重合 130 | matrix.postTranslate(pos[0] - bitmap.getWidth() / 2, pos[1] - bitmap.getHeight() / 2); 131 | 132 | //绘制路径 133 | canvas.drawPath(path, mPaint); 134 | //绘制Bitmap 135 | canvas.drawBitmap(bitmap, matrix, mPaint); 136 | //重绘界面 137 | invalidate(); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/other/SpringScrollView.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.other; 2 | 3 | import android.content.Context; 4 | import android.graphics.Rect; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | import android.view.View; 8 | import android.view.animation.TranslateAnimation; 9 | import android.widget.ScrollView; 10 | 11 | 12 | public class SpringScrollView extends ScrollView 13 | { 14 | 15 | // data 16 | private static final float MOVE_FACTOR = 0.5f; // 移动因子,手指移动100px,那么View就只移动50px 17 | 18 | private static final int ANIM_TIME = 300; // 松开手指后, 界面回到正常位置需要的动画时间 19 | 20 | private float startY;// 手指按下时的Y值, 用于在移动时计算移动距离,如果按下时不能上拉和下拉, 21 | // 会在手指移动时更新为当前手指的Y值 22 | 23 | // ui 24 | private View contentView; // ScrollView的唯一内容控件 25 | private Rect originalRect = new Rect();// 用于记录正常的布局位置 26 | 27 | // flag 28 | private boolean canPullDown = false; // 是否可以继续下拉 29 | private boolean canPullUp = false; // 是否可以继续上拉 30 | private boolean isMoved = false; // 记录是否移动了布局 31 | 32 | public SpringScrollView(Context context) 33 | { 34 | super(context); 35 | } 36 | 37 | public SpringScrollView(Context context, AttributeSet attrs) 38 | { 39 | super(context, attrs); 40 | } 41 | 42 | public SpringScrollView(Context context, AttributeSet attrs, int defStyle) 43 | { 44 | super(context, attrs, defStyle); 45 | } 46 | 47 | 48 | @Override 49 | protected void onFinishInflate() 50 | { 51 | if (getChildCount() > 0) 52 | { 53 | contentView = getChildAt(0); 54 | } 55 | } 56 | 57 | @Override 58 | protected void onLayout(boolean changed, int l, int t, int r, int b) 59 | { 60 | super.onLayout(changed, l, t, r, b); 61 | if (contentView == null) 62 | return; 63 | // ScrollView中的唯一子控件的位置信息, 这个位置信息在整个控件的生命周期中保持不变 64 | originalRect.set(contentView.getLeft(), contentView.getTop(), contentView.getRight(), contentView.getBottom()); 65 | } 66 | 67 | /** 68 | * 在触摸事件中, 处理上拉和下拉的逻辑 69 | */ 70 | @Override 71 | public boolean dispatchTouchEvent(MotionEvent ev) 72 | { 73 | if (contentView == null) 74 | { 75 | return super.dispatchTouchEvent(ev); 76 | } 77 | // 手指是否移动到了当前ScrollView控件之外 78 | boolean isTouchOutOfScrollView = ev.getY() >= this.getHeight() || ev.getY() <= 0; 79 | if (isTouchOutOfScrollView) 80 | { // 如果移动到了当前ScrollView控件之外 81 | if (isMoved) // 如果当前contentView已经被移动, 首先把布局移到原位置, 然后消费点这个事件 82 | boundBack(); 83 | return true; 84 | } 85 | int action = ev.getAction(); 86 | switch (action) 87 | { 88 | case MotionEvent.ACTION_DOWN: 89 | // 判断是否可以上拉和下拉 90 | canPullDown = isCanPullDown(); 91 | canPullUp = isCanPullUp(); 92 | // 记录按下时的Y值 93 | startY = ev.getY(); 94 | break; 95 | case MotionEvent.ACTION_UP: 96 | boundBack(); 97 | break; 98 | case MotionEvent.ACTION_MOVE: 99 | // 在移动的过程中, 既没有滚动到可以上拉的程度, 也没有滚动到可以下拉的程度 100 | if (!canPullDown && !canPullUp) 101 | { 102 | startY = ev.getY(); 103 | canPullDown = isCanPullDown(); 104 | canPullUp = isCanPullUp(); 105 | break; 106 | } 107 | // 计算手指移动的距离 108 | float nowY = ev.getY(); 109 | int deltaY = (int) (nowY - startY); 110 | 111 | // 是否应该移动布局 112 | boolean shouldMove = (canPullDown && deltaY > 0) // 可以下拉, 并且手指向下移动 113 | || (canPullUp && deltaY < 0) // 可以上拉, 并且手指向上移动 114 | || (canPullUp && canPullDown); // 既可以上拉也可以下拉(这种情况出现在ScrollView包裹的控件比ScrollView还小) 115 | if (shouldMove) 116 | { 117 | // 计算偏移量 118 | int offset = (int) (deltaY * MOVE_FACTOR); 119 | // 随着手指的移动而移动布局 120 | contentView.layout(originalRect.left, originalRect.top + offset, originalRect.right, 121 | originalRect.bottom + offset); 122 | isMoved = true; // 记录移动了布局 123 | } 124 | break; 125 | } 126 | return super.dispatchTouchEvent(ev); 127 | } 128 | 129 | /** 130 | * 将内容布局移动到原位置 可以在UP事件中调用, 也可以在其他需要的地方调用, 如手指移动到当前ScrollView外时 131 | */ 132 | private void boundBack() 133 | { 134 | if (!isMoved) 135 | return; // 如果没有移动布局, 则跳过执行 136 | // 开启动画 137 | TranslateAnimation anim = new TranslateAnimation(0, 0, contentView.getTop(), originalRect.top); 138 | anim.setDuration(ANIM_TIME); 139 | contentView.startAnimation(anim); 140 | // 设置回到正常的布局位置 141 | contentView.layout(originalRect.left, originalRect.top, originalRect.right, originalRect.bottom); 142 | // 将标志位设回false 143 | canPullDown = false; 144 | canPullUp = false; 145 | isMoved = false; 146 | } 147 | 148 | /** 149 | * 判断是否滚动到顶部 150 | */ 151 | private boolean isCanPullDown() 152 | { 153 | return getScrollY() == 0 || contentView.getHeight() < getHeight() + getScrollY(); 154 | } 155 | 156 | /** 157 | * 判断是否滚动到底部 158 | */ 159 | private boolean isCanPullUp() 160 | { 161 | return contentView.getHeight() <= getHeight() + getScrollY(); 162 | } 163 | } -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/slidecard/CardDataItem.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.slidecard; 2 | 3 | /** 4 | * 卡片数据装载对象 5 | * 6 | * @author xmuSistone 7 | */ 8 | public class CardDataItem 9 | { 10 | 11 | public String imgUrl; 12 | 13 | public String detailed; 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/slidecard/CardItemView.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.slidecard; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.util.AttributeSet; 6 | import android.widget.ImageView; 7 | import android.widget.LinearLayout; 8 | import android.widget.TextView; 9 | 10 | import com.bumptech.glide.Glide; 11 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 12 | 13 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 14 | import io.netopen.hotbitmapgg.androideverydaypractice.utils.GankMeiziDateUtil; 15 | 16 | /** 17 | * 卡片View项 18 | * 19 | * @author xmuSistone 20 | */ 21 | @SuppressLint("NewApi") 22 | public class CardItemView extends LinearLayout 23 | { 24 | 25 | public ImageView imageView; 26 | 27 | private TextView textView; 28 | 29 | public CardItemView(Context context) 30 | { 31 | 32 | this(context, null); 33 | } 34 | 35 | public CardItemView(Context context, AttributeSet attrs) 36 | { 37 | 38 | this(context, attrs, 0); 39 | } 40 | 41 | public CardItemView(Context context, AttributeSet attrs, int defStyle) 42 | { 43 | 44 | super(context, attrs, defStyle); 45 | inflate(context, R.layout.card_item, this); 46 | imageView = (ImageView) findViewById(R.id.card_image_view); 47 | textView = (TextView) findViewById(R.id.card_text); 48 | } 49 | 50 | public void fillData(CardDataItem itemData) 51 | { 52 | 53 | Glide.with(getContext()). 54 | load(itemData.imgUrl). 55 | centerCrop().diskCacheStrategy(DiskCacheStrategy.ALL). 56 | into(imageView); 57 | 58 | String time = GankMeiziDateUtil.convertTime(itemData.detailed); 59 | textView.setText(time); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widget/tablayout/YZBRate.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widget.tablayout; 2 | 3 | 4 | public class YZBRate 5 | { 6 | private String date; 7 | private double rate; 8 | 9 | public YZBRate(String date, double rate) 10 | { 11 | this.date = date; 12 | this.rate = rate; 13 | } 14 | 15 | public String getDate() 16 | { 17 | return date; 18 | } 19 | 20 | public void setDate(String date) 21 | { 22 | this.date = date; 23 | } 24 | 25 | public double getRate() 26 | { 27 | return rate; 28 | } 29 | 30 | public void setRate(double rate) 31 | { 32 | this.rate = rate; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widght_demo/BezaerActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widght_demo; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.ActionBar; 5 | import android.support.v7.widget.Toolbar; 6 | import android.view.MenuItem; 7 | 8 | import butterknife.Bind; 9 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 10 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 11 | 12 | public class BezaerActivity extends AbsBaseActivity 13 | { 14 | 15 | 16 | @Bind(R.id.toolbar) 17 | Toolbar mToolbar; 18 | 19 | @Override 20 | public int getLayoutId() 21 | { 22 | 23 | return R.layout.activity_widget_bezaer; 24 | } 25 | 26 | @Override 27 | public void initViews(Bundle savedInstanceState) 28 | { 29 | 30 | } 31 | 32 | @Override 33 | public void initToolBar() 34 | { 35 | 36 | mToolbar.setTitle("贝塞尔线练习"); 37 | setSupportActionBar(mToolbar); 38 | ActionBar actionBar = getSupportActionBar(); 39 | if (actionBar != null) 40 | actionBar.setDisplayHomeAsUpEnabled(true); 41 | } 42 | 43 | @Override 44 | public boolean onOptionsItemSelected(MenuItem item) 45 | { 46 | 47 | if (item.getItemId() == android.R.id.home) 48 | { 49 | onBackPressed(); 50 | } 51 | 52 | return super.onOptionsItemSelected(item); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widght_demo/BitmapStudyActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widght_demo; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Matrix; 8 | import android.graphics.Paint; 9 | import android.graphics.PorterDuff; 10 | import android.graphics.PorterDuffXfermode; 11 | import android.graphics.Rect; 12 | import android.graphics.RectF; 13 | import android.os.Bundle; 14 | import android.widget.ImageView; 15 | 16 | import butterknife.Bind; 17 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 18 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 19 | 20 | 21 | public class BitmapStudyActivity extends AbsBaseActivity 22 | { 23 | 24 | @Bind(R.id.image_view) 25 | ImageView imageView; 26 | 27 | @Override 28 | public int getLayoutId() 29 | { 30 | return R.layout.activity_bitmap_study; 31 | } 32 | 33 | @Override 34 | public void initViews(Bundle savedInstanceState) 35 | { 36 | //drawBitmap(); 37 | //setRoundImageView(R.mipmap.no_media, 20, imageView); 38 | 39 | // Canvas canvas = new Canvas(); 40 | // drawMatrixBitmap(R.mipmap.no_media , canvas); 41 | } 42 | 43 | @Override 44 | public void initToolBar() 45 | { 46 | 47 | } 48 | 49 | /** 50 | * 绘制Bitmap 51 | */ 52 | public void drawBitmap() 53 | { 54 | //创建一个bitmap 55 | Bitmap bitmap = Bitmap.createBitmap(800, 400, Bitmap.Config.ARGB_8888); 56 | //创建Canvas画布 57 | Canvas canvas = new Canvas(bitmap); 58 | //设置画布背景颜色 59 | canvas.drawColor(Color.LTGRAY); 60 | //创建画笔 61 | Paint paint = new Paint(); 62 | //设置抗锯齿 63 | paint.setAntiAlias(true); 64 | //设置画笔颜色 65 | paint.setColor(Color.WHITE); 66 | //设置字体大小 67 | paint.setTextSize(60); 68 | //绘制文字 69 | canvas.drawText("WhatTheFuck!", 200, 200, paint); 70 | //将绘制好的显示在ImageView上 71 | imageView.setImageBitmap(bitmap); 72 | 73 | } 74 | 75 | 76 | /** 77 | * 创建圆角图片 78 | *

79 | * PorterDuffXfermode的使用 80 | *

81 | * 相关知识 方便复习: 82 | *

83 | * PorterDuff.Mode.CLEAR 84 | * 绘制不会提交到画布上 85 | * PorterDuff.Mode.SRC 86 | * 只显示绘制源图像 87 | * PorterDuff.Mode.DST 88 | * 只显示目标图像,即已在画布上的初始图像 89 | * PorterDuff.Mode.SRC_OVER 90 | * 正常绘制显示,即后绘制的叠加在原来绘制的图上 91 | * PorterDuff.Mode.DST_OVER 92 | * 上下两层都显示但是下层(DST)居上显示 93 | * PorterDuff.Mode.SRC_IN 94 | * 取两层绘制的交集且只显示上层(SRC) 95 | * PorterDuff.Mode.DST_IN 96 | * 取两层绘制的交集且只显示下层(DST) 97 | * PorterDuff.Mode.SRC_OUT 98 | * 取两层绘制的不相交的部分且只显示上层(SRC) 99 | * PorterDuff.Mode.DST_OUT 100 | * 取两层绘制的不相交的部分且只显示下层(DST) 101 | * PorterDuff.Mode.SRC_ATOP 102 | * 两层相交,取下层(DST)的非相交部分和上层(SRC)的相交部分 103 | * PorterDuff.Mode.DST_ATOP 104 | * 两层相交,取上层(SRC)的非相交部分和下层(DST)的相交部分 105 | * PorterDuff.Mode.XOR 106 | * 挖去两图层相交的部分 107 | * PorterDuff.Mode.DARKEN 108 | * 显示两图层全部区域且加深交集部分的颜色 109 | * PorterDuff.Mode.LIGHTEN 110 | * 显示两图层全部区域且点亮交集部分的颜色 111 | * PorterDuff.Mode.MULTIPLY 112 | * 显示两图层相交部分且加深该部分的颜色 113 | * PorterDuff.Mode.SCREEN 114 | * 显示两图层全部区域且将该部分颜色变为透明色 115 | * 116 | * @param bitmap 117 | * @param pixels 118 | * @return 119 | */ 120 | public Bitmap createRoundBitmap(Bitmap bitmap, float pixels) 121 | { 122 | 123 | //先获取Bitmap的宽高 124 | int width = bitmap.getWidth(); 125 | int height = bitmap.getHeight(); 126 | //创建一个新的Bitmap 127 | Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 128 | //创建画布 129 | Canvas canvas = new Canvas(newBitmap); 130 | //创建画笔 131 | Paint paint = new Paint(); 132 | //设置颜色 133 | paint.setColor(Color.BLACK); 134 | //设置抗锯齿 135 | paint.setAntiAlias(true); 136 | //创建矩形 137 | Rect rect = new Rect(0, 0, width, height); 138 | RectF rectF = new RectF(rect); 139 | //绘制圆角矩形 140 | canvas.drawRoundRect(rectF, pixels, pixels, paint); 141 | //创建 PorterDuffXfermode 142 | PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN); 143 | //给画笔设置画图模式 144 | paint.setXfermode(xfermode); 145 | //绘制到Bitmap上 146 | canvas.drawBitmap(bitmap, rect, rect, paint); 147 | 148 | 149 | return newBitmap; 150 | } 151 | 152 | 153 | /** 154 | * 设置图片给ImageView显示圆角 155 | * 156 | * @param res 157 | * @param angle 158 | * @param imageView 159 | */ 160 | public void setRoundImageView(int res, float angle, ImageView imageView) 161 | { 162 | // Drawable drawable = getResources().getDrawable(res); 163 | // BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; 164 | // Bitmap bitmap = bitmapDrawable.getBitmap(); 165 | 166 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), res); 167 | 168 | Bitmap roundBitmap = createRoundBitmap(bitmap, angle); 169 | imageView.setImageBitmap(roundBitmap); 170 | } 171 | 172 | 173 | /** 174 | * 利用matrix来实现图片的平移和缩放 175 | */ 176 | public void drawMatrixBitmap(int res , Canvas canvas) 177 | { 178 | //创建画笔 179 | Paint paint = new Paint(); 180 | paint.setAntiAlias(true); 181 | //创建bitmap 182 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), res); 183 | int width = bitmap.getWidth(); 184 | int height = bitmap.getHeight(); 185 | //创建Matrix矩阵 186 | Matrix matrix = new Matrix(); 187 | //绘制bitmap 188 | canvas.drawBitmap(bitmap, matrix, paint); 189 | //平移 190 | matrix.setTranslate(width / 2, height); 191 | canvas.drawBitmap(bitmap, matrix, paint); 192 | //缩放 193 | matrix.postScale(02.f, 02.f); 194 | canvas.drawBitmap(bitmap, matrix, paint); 195 | 196 | 197 | } 198 | 199 | } 200 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widght_demo/CircleProgressBarActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widght_demo; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.ObjectAnimator; 6 | import android.os.Bundle; 7 | import android.support.v7.app.ActionBar; 8 | import android.support.v7.widget.Toolbar; 9 | import android.view.MenuItem; 10 | import android.view.View; 11 | import android.view.animation.LinearInterpolator; 12 | import android.widget.TextView; 13 | 14 | import butterknife.Bind; 15 | import butterknife.OnClick; 16 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 17 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 18 | import io.netopen.hotbitmapgg.androideverydaypractice.widget.other.CustomProgressBar; 19 | 20 | 21 | public class CircleProgressBarActivity extends AbsBaseActivity 22 | { 23 | 24 | @Bind(R.id.progress) 25 | CustomProgressBar mCustomProgressBar; 26 | 27 | @Bind(R.id.tv_hint) 28 | TextView mHint; 29 | 30 | @Bind(R.id.toolbar) 31 | Toolbar mToolbar; 32 | 33 | @Override 34 | public int getLayoutId() 35 | { 36 | 37 | return R.layout.activity_progress; 38 | } 39 | 40 | @Override 41 | public void initViews(Bundle savedInstanceState) 42 | { 43 | 44 | startAmin(); 45 | } 46 | 47 | @Override 48 | public void initToolBar() 49 | { 50 | 51 | mToolbar.setTitle("自定义圆形进度条"); 52 | setSupportActionBar(mToolbar); 53 | ActionBar actionBar = getSupportActionBar(); 54 | if (actionBar != null) 55 | actionBar.setDisplayHomeAsUpEnabled(true); 56 | } 57 | 58 | @Override 59 | public boolean onOptionsItemSelected(MenuItem item) 60 | { 61 | 62 | if (item.getItemId() == android.R.id.home) 63 | { 64 | onBackPressed(); 65 | } 66 | 67 | return super.onOptionsItemSelected(item); 68 | } 69 | 70 | 71 | private void startAmin() 72 | { 73 | 74 | ObjectAnimator mObjectAnimator = ObjectAnimator.ofFloat(mCustomProgressBar, "percentage", 1); 75 | mObjectAnimator.setDuration(2000); 76 | mObjectAnimator.setInterpolator(new LinearInterpolator()); 77 | mObjectAnimator.addListener(new AnimatorListenerAdapter() 78 | { 79 | 80 | @Override 81 | public void onAnimationEnd(Animator animation) 82 | { 83 | //动画结束后 显示分数 84 | try 85 | { 86 | ObjectAnimator animator = ObjectAnimator.ofFloat(mHint, "alpha", 0f, 1f); 87 | animator.setDuration(1000); 88 | animator.setInterpolator(new LinearInterpolator()); 89 | animator.start(); 90 | mHint.setVisibility(View.VISIBLE); 91 | } catch (Exception e) 92 | { 93 | e.printStackTrace(); 94 | } 95 | 96 | 97 | super.onAnimationEnd(animation); 98 | } 99 | }); 100 | mObjectAnimator.start(); 101 | } 102 | 103 | @OnClick(R.id.tv_hint) 104 | void onHint() 105 | { 106 | 107 | mHint.setVisibility(View.GONE); 108 | startAmin(); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widght_demo/LoveActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widght_demo; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.ActionBar; 5 | import android.support.v7.widget.Toolbar; 6 | import android.view.MenuItem; 7 | import android.view.View; 8 | 9 | import butterknife.Bind; 10 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 11 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 12 | import io.netopen.hotbitmapgg.androideverydaypractice.widget.lovelayout.LoveLikeLayout; 13 | 14 | public class LoveActivity extends AbsBaseActivity 15 | { 16 | 17 | @Bind(R.id.love) 18 | LoveLikeLayout mLoveLikeLayout; 19 | 20 | @Bind(R.id.toolbar) 21 | Toolbar mToolbar; 22 | 23 | 24 | @Override 25 | public int getLayoutId() 26 | { 27 | 28 | return R.layout.activity_widget_love; 29 | } 30 | 31 | @Override 32 | public void initViews(Bundle savedInstanceState) 33 | { 34 | 35 | mLoveLikeLayout.setOnClickListener(new View.OnClickListener() 36 | { 37 | 38 | @Override 39 | public void onClick(View view) 40 | { 41 | 42 | mLoveLikeLayout.addLove(); 43 | } 44 | }); 45 | } 46 | 47 | @Override 48 | public void initToolBar() 49 | { 50 | 51 | mToolbar.setTitle("爱心点赞效果"); 52 | setSupportActionBar(mToolbar); 53 | ActionBar actionBar = getSupportActionBar(); 54 | if (actionBar != null) 55 | actionBar.setDisplayHomeAsUpEnabled(true); 56 | } 57 | 58 | @Override 59 | public boolean onOptionsItemSelected(MenuItem item) 60 | { 61 | 62 | if (item.getItemId() == android.R.id.home) 63 | { 64 | onBackPressed(); 65 | } 66 | 67 | return super.onOptionsItemSelected(item); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widght_demo/ScrollDemoActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widght_demo; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.widget.Toolbar; 5 | import android.view.View; 6 | 7 | import butterknife.Bind; 8 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 9 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 10 | 11 | /** 12 | * 安卓实现几种滑动的演示界面 13 | */ 14 | public class ScrollDemoActivity extends AbsBaseActivity 15 | { 16 | 17 | @Bind(R.id.toolbar) 18 | Toolbar mToolbar; 19 | 20 | @Override 21 | public int getLayoutId() 22 | { 23 | 24 | return R.layout.activity_scroll_demo; 25 | } 26 | 27 | @Override 28 | public void initViews(Bundle savedInstanceState) 29 | { 30 | 31 | } 32 | 33 | @Override 34 | public void initToolBar() 35 | { 36 | 37 | mToolbar.setNavigationIcon(R.drawable.back); 38 | mToolbar.setTitle("滑动实现演示"); 39 | mToolbar.setNavigationOnClickListener(new View.OnClickListener() 40 | { 41 | 42 | @Override 43 | public void onClick(View v) 44 | { 45 | 46 | onBackPressed(); 47 | } 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widght_demo/SlideGankMeiziActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widght_demo; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.ActionBar; 5 | import android.support.v7.widget.Toolbar; 6 | import android.view.MenuItem; 7 | import android.view.View; 8 | import android.widget.RelativeLayout; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import butterknife.Bind; 14 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 15 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 16 | import io.netopen.hotbitmapgg.androideverydaypractice.model.GankMeiziInfo; 17 | import io.netopen.hotbitmapgg.androideverydaypractice.model.GankMeiziResult; 18 | import io.netopen.hotbitmapgg.androideverydaypractice.network.RetrofitHelper; 19 | import io.netopen.hotbitmapgg.androideverydaypractice.widget.slidecard.CardDataItem; 20 | import io.netopen.hotbitmapgg.androideverydaypractice.widget.slidecard.CardSlidePanel; 21 | import rx.android.schedulers.AndroidSchedulers; 22 | import rx.functions.Action0; 23 | import rx.functions.Action1; 24 | import rx.functions.Func1; 25 | import rx.schedulers.Schedulers; 26 | 27 | 28 | public class SlideGankMeiziActivity extends AbsBaseActivity 29 | { 30 | 31 | @Bind(R.id.toolbar) 32 | Toolbar mToolbar; 33 | 34 | @Bind(R.id.image_slide_panel) 35 | CardSlidePanel mCardSlidePanel; 36 | 37 | @Bind(R.id.root_layout) 38 | RelativeLayout mRootLayout; 39 | 40 | private int pageNum = 100; 41 | 42 | private int page = 1; 43 | 44 | //滑动的卡片item集合 45 | private List dataList = new ArrayList<>(); 46 | 47 | //Gank妹子集合 48 | private List meizis = new ArrayList<>(); 49 | 50 | @Override 51 | public int getLayoutId() 52 | { 53 | 54 | return R.layout.activity_slide_card; 55 | } 56 | 57 | @Override 58 | public void initViews(Bundle savedInstanceState) 59 | { 60 | 61 | getGankMeizi(); 62 | 63 | mCardSlidePanel.setCardSwitchListener(new CardSlidePanel.CardSwitchListener() 64 | { 65 | 66 | @Override 67 | public void onShow(int index) 68 | { 69 | 70 | } 71 | 72 | @Override 73 | public void onCardVanish(int index, int type) 74 | { 75 | 76 | } 77 | 78 | @Override 79 | public void onItemClick(View cardImageView, int index) 80 | { 81 | 82 | } 83 | }); 84 | } 85 | 86 | private void getGankMeizi() 87 | { 88 | 89 | RetrofitHelper.getGankMeiziApi().getGankMeizi(pageNum, page) 90 | .doOnSubscribe(new Action0() 91 | { 92 | 93 | @Override 94 | public void call() 95 | { 96 | 97 | showProgress(); 98 | } 99 | }) 100 | .map(new Func1>() 101 | { 102 | 103 | @Override 104 | public List call(GankMeiziResult gankMeiziResult) 105 | { 106 | 107 | return gankMeiziResult.gankMeizis; 108 | } 109 | }) 110 | .subscribeOn(Schedulers.io()) 111 | .observeOn(AndroidSchedulers.mainThread()) 112 | .subscribe(new Action1>() 113 | { 114 | 115 | @Override 116 | public void call(List gankMeiziInfos) 117 | { 118 | meizis.addAll(gankMeiziInfos); 119 | finishTask(); 120 | } 121 | }, new Action1() 122 | { 123 | 124 | @Override 125 | public void call(Throwable throwable) 126 | { 127 | 128 | showError(); 129 | } 130 | }); 131 | } 132 | 133 | /** 134 | * 根据返回的妹子图片 135 | * 初始化卡片数据 136 | */ 137 | private void finishTask() 138 | { 139 | 140 | hideProgress(); 141 | CardDataItem dataItem; 142 | for (int i = 0; i < meizis.size(); i++) 143 | { 144 | dataItem = new CardDataItem(); 145 | dataItem.detailed = meizis.get(i).createdAt; 146 | dataItem.imgUrl = meizis.get(i).url; 147 | dataList.add(dataItem); 148 | } 149 | 150 | mCardSlidePanel.fillData(dataList); 151 | } 152 | 153 | @Override 154 | public void initToolBar() 155 | { 156 | 157 | mToolbar.setTitle("仿探探滑动卡片效果"); 158 | setSupportActionBar(mToolbar); 159 | ActionBar actionBar = getSupportActionBar(); 160 | if (actionBar != null) 161 | actionBar.setDisplayHomeAsUpEnabled(true); 162 | } 163 | 164 | @Override 165 | public boolean onOptionsItemSelected(MenuItem item) 166 | { 167 | 168 | if (item.getItemId() == android.R.id.home) 169 | { 170 | onBackPressed(); 171 | } 172 | 173 | return super.onOptionsItemSelected(item); 174 | } 175 | 176 | public void showProgress() 177 | { 178 | 179 | mRootLayout.setVisibility(View.GONE); 180 | } 181 | 182 | public void hideProgress() 183 | { 184 | 185 | mRootLayout.setVisibility(View.VISIBLE); 186 | } 187 | 188 | public void showError() 189 | { 190 | 191 | mRootLayout.setVisibility(View.GONE); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /app/src/main/java/io/netopen/hotbitmapgg/androideverydaypractice/widght_demo/TableActivity.java: -------------------------------------------------------------------------------- 1 | package io.netopen.hotbitmapgg.androideverydaypractice.widght_demo; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.ActionBar; 5 | import android.support.v7.widget.Toolbar; 6 | import android.view.MenuItem; 7 | 8 | import butterknife.Bind; 9 | import io.netopen.hotbitmapgg.androideverydaypractice.R; 10 | import io.netopen.hotbitmapgg.androideverydaypractice.base.AbsBaseActivity; 11 | 12 | 13 | public class TableActivity extends AbsBaseActivity 14 | { 15 | 16 | @Bind(R.id.toolbar) 17 | Toolbar mToolbar; 18 | 19 | @Override 20 | public int getLayoutId() 21 | { 22 | 23 | return R.layout.activity_widget_table; 24 | } 25 | 26 | @Override 27 | public void initViews(Bundle savedInstanceState) 28 | { 29 | 30 | } 31 | 32 | @Override 33 | public void initToolBar() 34 | { 35 | 36 | mToolbar.setTitle("TableView练习"); 37 | setSupportActionBar(mToolbar); 38 | ActionBar actionBar = getSupportActionBar(); 39 | if (actionBar != null) 40 | actionBar.setDisplayHomeAsUpEnabled(true); 41 | } 42 | 43 | @Override 44 | public boolean onOptionsItemSelected(MenuItem item) 45 | { 46 | 47 | if (item.getItemId() == android.R.id.home) 48 | { 49 | onBackPressed(); 50 | } 51 | 52 | return super.onOptionsItemSelected(item); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/AndroidEveryDayPractice/HEAD/app/src/main/res/drawable-hdpi/back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/AndroidEveryDayPractice/HEAD/app/src/main/res/drawable-hdpi/ic_arrow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_banana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/AndroidEveryDayPractice/HEAD/app/src/main/res/drawable-hdpi/ic_banana.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/icon_arrow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/AndroidEveryDayPractice/HEAD/app/src/main/res/drawable-hdpi/icon_arrow.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/pl_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/AndroidEveryDayPractice/HEAD/app/src/main/res/drawable-hdpi/pl_blue.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/pl_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/AndroidEveryDayPractice/HEAD/app/src/main/res/drawable-hdpi/pl_red.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/pl_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/AndroidEveryDayPractice/HEAD/app/src/main/res/drawable-hdpi/pl_yellow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/back_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/edit_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ignore_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ignore_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/AndroidEveryDayPractice/HEAD/app/src/main/res/drawable/ignore_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ignore_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/AndroidEveryDayPractice/HEAD/app/src/main/res/drawable/ignore_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/like_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/like_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/AndroidEveryDayPractice/HEAD/app/src/main/res/drawable/like_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/like_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/AndroidEveryDayPractice/HEAD/app/src/main/res/drawable/like_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_bitmap_study.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_face.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 15 | 16 | 27 | 28 | 29 | 30 | 31 | 32 | 36 | 37 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 |