Commit c125f4f5c5a989b25534e2939c497e5d632ddc14

Authored by 韩亚云
1 parent cb7ee015

图库模块:图片预览,网格模式全屏预览

Showing 45 changed files with 4247 additions and 66 deletions
app/strike/src/main/AndroidManifest.xml
@@ -17,7 +17,8 @@ @@ -17,7 +17,8 @@
17 android:roundIcon="@mipmap/ic_launcher_round" 17 android:roundIcon="@mipmap/ic_launcher_round"
18 android:supportsRtl="true" 18 android:supportsRtl="true"
19 android:theme="@style/AppTheme"> 19 android:theme="@style/AppTheme">
20 - <activity android:name="com.cnlive.strike.demo.activity.HappyChinaActivity"></activity> 20 + <activity android:name="com.cnlive.strike.imgutil.SimplePrevActivity"></activity>
  21 + <activity android:name="com.cnlive.strike.demo.activity.HappyChinaActivity" />
21 22
22 <provider 23 <provider
23 android:name="androidx.core.content.FileProvider" 24 android:name="androidx.core.content.FileProvider"
app/strike/src/main/java/com/cnlive/strike/imgutil/ImgActivity.java
@@ -3,6 +3,7 @@ package com.cnlive.strike.imgutil; @@ -3,6 +3,7 @@ package com.cnlive.strike.imgutil;
3 import androidx.appcompat.app.AppCompatActivity; 3 import androidx.appcompat.app.AppCompatActivity;
4 4
5 import android.animation.ObjectAnimator; 5 import android.animation.ObjectAnimator;
  6 +import android.content.Intent;
6 import android.graphics.Bitmap; 7 import android.graphics.Bitmap;
7 import android.os.Bundle; 8 import android.os.Bundle;
8 import android.os.Handler; 9 import android.os.Handler;
@@ -85,6 +86,8 @@ public class ImgActivity extends AppCompatActivity { @@ -85,6 +86,8 @@ public class ImgActivity extends AppCompatActivity {
85 iv_test9 = findViewById(R.id.iv_test9); 86 iv_test9 = findViewById(R.id.iv_test9);
86 iv_test10 = findViewById(R.id.iv_test10); 87 iv_test10 = findViewById(R.id.iv_test10);
87 iv_test11 = findViewById(R.id.iv_test11); 88 iv_test11 = findViewById(R.id.iv_test11);
  89 +
  90 + findViewById(R.id.simpla_see).setOnClickListener(view -> startActivity(new Intent(this,SimplePrevActivity.class)));
88 } 91 }
89 92
90 93
@@ -100,6 +103,7 @@ public class ImgActivity extends AppCompatActivity { @@ -100,6 +103,7 @@ public class ImgActivity extends AppCompatActivity {
100 } 103 }
101 }; 104 };
102 105
  106 +
103 ImageLoader.with(this) 107 ImageLoader.with(this)
104 .url(URL1) 108 .url(URL1)
105 .animate(animation) 109 .animate(animation)
@@ -125,7 +129,7 @@ public class ImgActivity extends AppCompatActivity { @@ -125,7 +129,7 @@ public class ImgActivity extends AppCompatActivity {
125 data.setShowImg(URL1); 129 data.setShowImg(URL1);
126 iv_test1.setOnClickListener(view -> PreviewImageViewActivity.startPreviewPictrue(this, view, data)); 130 iv_test1.setOnClickListener(view -> PreviewImageViewActivity.startPreviewPictrue(this, view, data));
127 131
128 -// ImageLoader.with(this) 132 +// LoadImage.with(this)
129 // .url(URL1) 133 // .url(URL1)
130 // .scale(ScaleMode.FIT_CENTER) 134 // .scale(ScaleMode.FIT_CENTER)
131 // .into(iv_test2); 135 // .into(iv_test2);
@@ -168,7 +172,7 @@ public class ImgActivity extends AppCompatActivity { @@ -168,7 +172,7 @@ public class ImgActivity extends AppCompatActivity {
168 .into(iv_test7); 172 .into(iv_test7);
169 173
170 //加载本地图片 174 //加载本地图片
171 -// ImageLoader.with(this) 175 +// LoadImage.with(this)
172 // .file(new File(getFilesDir(), IMG_NAME_C)) 176 // .file(new File(getFilesDir(), IMG_NAME_C))
173 // .placeHolder(R.mipmap.ic_launcher) 177 // .placeHolder(R.mipmap.ic_launcher)
174 // .scale(ScaleMode.FIT_CENTER) 178 // .scale(ScaleMode.FIT_CENTER)
app/strike/src/main/java/com/cnlive/strike/imgutil/SimplePrevActivity.java 0 → 100644
  1 +package com.cnlive.strike.imgutil;
  2 +
  3 +
  4 +import android.graphics.drawable.Drawable;
  5 +import android.view.KeyEvent;
  6 +import android.view.View;
  7 +import android.widget.ImageView;
  8 +
  9 +import com.bumptech.glide.request.target.SimpleTarget;
  10 +import com.bumptech.glide.request.transition.Transition;
  11 +import com.cnlive.cloud.R;
  12 +import com.cnlive.core.gridview.AutoGridView;
  13 +import com.cnlive.core.gridview.GridImgUtil;
  14 +import com.cnlive.core.gridview.adapter.BaseAutoGridHolder;
  15 +import com.cnlive.core.gridview.adapter.SimpleAutoGridAdapter;
  16 +import com.cnlive.core.imagepreview.ImagePreView;
  17 +import com.cnlive.core.imagepreview.PhotoLoader;
  18 +import com.cnlive.core.imagepreview.ViewerStatus;
  19 +import com.cnlive.core.imagepreview.listener.OnBrowseStatusListener;
  20 +import com.cnlive.core.libs.base.frame.activity.BaseActivity;
  21 +import com.cnlive.core.libs.base.util.GlideUtil;
  22 +
  23 +import java.util.ArrayList;
  24 +import java.util.List;
  25 +
  26 +import androidx.annotation.NonNull;
  27 +import androidx.annotation.Nullable;
  28 +
  29 +public class SimplePrevActivity extends BaseActivity {
  30 +
  31 + private ImagePreView preView;
  32 + private AutoGridView autoGridView;
  33 + List<String> list = new ArrayList<>();
  34 + private SimpleAutoGridAdapter adapter;
  35 +
  36 +
  37 + @Override
  38 + protected int getViewLayoutId() {
  39 + return R.layout.activity_simple_prev;
  40 + }
  41 +
  42 +
  43 + @Override
  44 + protected void initView() {
  45 + preView = findViewById(R.id.image_pre);
  46 + autoGridView = findViewById(R.id.grid_view);
  47 + list.add("https://b-ssl.duitang.com/uploads/item/201505/09/20150509221719_kyNrM.jpeg");
  48 + list.add("https://b-ssl.duitang.com/uploads/item/201709/26/20170926131419_8YhLA.jpeg");
  49 + list.add("https://b-ssl.duitang.com/uploads/item/201505/11/20150511122951_MAwVZ.jpeg");
  50 + list.add("https://b-ssl.duitang.com/uploads/item/201704/23/20170423205828_BhNSv.jpeg");
  51 + list.add("https://b-ssl.duitang.com/uploads/item/201706/30/20170630181644_j4mh5.jpeg");
  52 +
  53 + preView.overlayStatusBar(false)
  54 + .imageData(list)
  55 + .imageLoader(new PhotoLoader());
  56 +
  57 + adapter = new SimpleAutoGridAdapter<String, BaseAutoGridHolder>(list);
  58 + adapter.setImageLoader(new SimpleAutoGridAdapter.ImageLoader() {
  59 + @Override
  60 + public void onLoadImage(int position, Object item, ImageView imageView) {
  61 +
  62 + GridImgUtil.loadImage(SimplePrevActivity.this, item, new SimpleTarget<Drawable>() {
  63 + @Override
  64 + public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
  65 + preView.getViewData().get(position).setImageWidth(resource.getIntrinsicWidth());
  66 + preView.getViewData().get(position).setImageHeight(resource.getIntrinsicHeight());
  67 + imageView.setImageDrawable(resource);
  68 + }
  69 +
  70 + @Override
  71 + public void onLoadFailed(@Nullable Drawable errorDrawable) {
  72 + super.onLoadFailed(errorDrawable);
  73 + imageView.setImageDrawable(errorDrawable);
  74 + }
  75 + });
  76 + }
  77 + });
  78 + autoGridView.setOnItemClickListener(new AutoGridView.OnItemClickListener() {
  79 + @Override
  80 + public void onItemClick(int position, View view) {
  81 + preView.bindViewGroup(autoGridView);
  82 + preView.watch(position);
  83 + }
  84 + });
  85 +
  86 + autoGridView.setAdapter(adapter);
  87 + preView.setOnBrowseStatusListener(new OnBrowseStatusListener() {
  88 + @Override
  89 + public void onBrowseStatus(int status) {
  90 + //可以根据状态去设置状态栏颜色
  91 + if(status == ViewerStatus.STATUS_BEGIN_OPEN){
  92 +
  93 + }else if(status == ViewerStatus.STATUS_SILENCE){
  94 +
  95 + }
  96 + }
  97 + });
  98 + }
  99 +
  100 + @Override
  101 + public boolean onKeyDown(int keyCode, KeyEvent event) {
  102 + boolean b = preView.onKeyDown(keyCode, event);
  103 + if (b) {
  104 + return b;
  105 + }
  106 + return super.onKeyDown(keyCode, event);
  107 + }
  108 +}
app/strike/src/main/res/layout/activity_img.xml
@@ -3,11 +3,19 @@ @@ -3,11 +3,19 @@
3 android:layout_width="match_parent" 3 android:layout_width="match_parent"
4 android:layout_height="match_parent"> 4 android:layout_height="match_parent">
5 5
  6 +
  7 +
6 <LinearLayout 8 <LinearLayout
7 android:layout_width="match_parent" 9 android:layout_width="match_parent"
8 android:layout_height="match_parent" 10 android:layout_height="match_parent"
9 android:orientation="vertical"> 11 android:orientation="vertical">
10 12
  13 + <Button
  14 + android:id="@+id/simpla_see"
  15 + android:layout_width="wrap_content"
  16 + android:layout_height="wrap_content"
  17 + android:text="简单预览" />
  18 +
11 <TextView 19 <TextView
12 android:layout_width="wrap_content" 20 android:layout_width="wrap_content"
13 android:layout_height="wrap_content" 21 android:layout_height="wrap_content"
app/strike/src/main/res/layout/activity_simple_prev.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + xmlns:app="http://schemas.android.com/apk/res-auto"
  4 + xmlns:tools="http://schemas.android.com/tools"
  5 + android:layout_width="match_parent"
  6 + android:layout_height="match_parent"
  7 + tools:context="com.cnlive.strike.imgutil.SimplePrevActivity">
  8 +
  9 + <com.cnlive.core.gridview.AutoGridView
  10 + android:id="@+id/grid_view"
  11 + android:layout_width="match_parent"
  12 + android:layout_height="wrap_content"/>
  13 +
  14 + <com.cnlive.core.imagepreview.ImagePreView
  15 + android:id="@+id/image_pre"
  16 + android:layout_width="match_parent"
  17 + android:layout_height="match_parent"/>
  18 +</RelativeLayout>
core/database/src/main/java/com/cnlive/database/dao/DaoMaster.java
@@ -29,9 +29,11 @@ public class DaoMaster extends AbstractDaoMaster { @@ -29,9 +29,11 @@ public class DaoMaster extends AbstractDaoMaster {
29 ContactListDao.createTable(db, ifNotExists); 29 ContactListDao.createTable(db, ifNotExists);
30 ContanctDaRenEntityDao.createTable(db, ifNotExists); 30 ContanctDaRenEntityDao.createTable(db, ifNotExists);
31 ContanctGroupChatEntityDao.createTable(db, ifNotExists); 31 ContanctGroupChatEntityDao.createTable(db, ifNotExists);
32 - DBFriendCircleMessageDao.createTable(db, ifNotExists);  
33 DarenDetailMsgDao.createTable(db, ifNotExists); 32 DarenDetailMsgDao.createTable(db, ifNotExists);
34 DarenListMsgDao.createTable(db, ifNotExists); 33 DarenListMsgDao.createTable(db, ifNotExists);
  34 + DBFriendCircleMessageDao.createTable(db, ifNotExists);
  35 + DBMomentDetailDao.createTable(db, ifNotExists);
  36 + DBMomentItemDao.createTable(db, ifNotExists);
35 DownloadInfoDao.createTable(db, ifNotExists); 37 DownloadInfoDao.createTable(db, ifNotExists);
36 ExceptionInfoDao.createTable(db, ifNotExists); 38 ExceptionInfoDao.createTable(db, ifNotExists);
37 HolidayThemeInfoDao.createTable(db, ifNotExists); 39 HolidayThemeInfoDao.createTable(db, ifNotExists);
@@ -49,9 +51,6 @@ public class DaoMaster extends AbstractDaoMaster { @@ -49,9 +51,6 @@ public class DaoMaster extends AbstractDaoMaster {
49 SearchHistoryDao.createTable(db, ifNotExists); 51 SearchHistoryDao.createTable(db, ifNotExists);
50 SysNumReadableDao.createTable(db, ifNotExists); 52 SysNumReadableDao.createTable(db, ifNotExists);
51 WitnessDao.createTable(db, ifNotExists); 53 WitnessDao.createTable(db, ifNotExists);
52 - DBMomentDetailDao.createTable(db, ifNotExists);  
53 - DBMomentItemDao.createTable(db, ifNotExists);  
54 - TestInfoDao.createTable(db, ifNotExists);  
55 } 54 }
56 55
57 /** Drops underlying database table using DAOs. */ 56 /** Drops underlying database table using DAOs. */
@@ -64,9 +63,11 @@ public class DaoMaster extends AbstractDaoMaster { @@ -64,9 +63,11 @@ public class DaoMaster extends AbstractDaoMaster {
64 ContactListDao.dropTable(db, ifExists); 63 ContactListDao.dropTable(db, ifExists);
65 ContanctDaRenEntityDao.dropTable(db, ifExists); 64 ContanctDaRenEntityDao.dropTable(db, ifExists);
66 ContanctGroupChatEntityDao.dropTable(db, ifExists); 65 ContanctGroupChatEntityDao.dropTable(db, ifExists);
67 - DBFriendCircleMessageDao.dropTable(db, ifExists);  
68 DarenDetailMsgDao.dropTable(db, ifExists); 66 DarenDetailMsgDao.dropTable(db, ifExists);
69 DarenListMsgDao.dropTable(db, ifExists); 67 DarenListMsgDao.dropTable(db, ifExists);
  68 + DBFriendCircleMessageDao.dropTable(db, ifExists);
  69 + DBMomentDetailDao.dropTable(db, ifExists);
  70 + DBMomentItemDao.dropTable(db, ifExists);
70 DownloadInfoDao.dropTable(db, ifExists); 71 DownloadInfoDao.dropTable(db, ifExists);
71 ExceptionInfoDao.dropTable(db, ifExists); 72 ExceptionInfoDao.dropTable(db, ifExists);
72 HolidayThemeInfoDao.dropTable(db, ifExists); 73 HolidayThemeInfoDao.dropTable(db, ifExists);
@@ -84,9 +85,6 @@ public class DaoMaster extends AbstractDaoMaster { @@ -84,9 +85,6 @@ public class DaoMaster extends AbstractDaoMaster {
84 SearchHistoryDao.dropTable(db, ifExists); 85 SearchHistoryDao.dropTable(db, ifExists);
85 SysNumReadableDao.dropTable(db, ifExists); 86 SysNumReadableDao.dropTable(db, ifExists);
86 WitnessDao.dropTable(db, ifExists); 87 WitnessDao.dropTable(db, ifExists);
87 - DBMomentDetailDao.dropTable(db, ifExists);  
88 - DBMomentItemDao.dropTable(db, ifExists);  
89 - TestInfoDao.dropTable(db, ifExists);  
90 } 88 }
91 89
92 /** 90 /**
@@ -113,9 +111,11 @@ public class DaoMaster extends AbstractDaoMaster { @@ -113,9 +111,11 @@ public class DaoMaster extends AbstractDaoMaster {
113 registerDaoClass(ContactListDao.class); 111 registerDaoClass(ContactListDao.class);
114 registerDaoClass(ContanctDaRenEntityDao.class); 112 registerDaoClass(ContanctDaRenEntityDao.class);
115 registerDaoClass(ContanctGroupChatEntityDao.class); 113 registerDaoClass(ContanctGroupChatEntityDao.class);
116 - registerDaoClass(DBFriendCircleMessageDao.class);  
117 registerDaoClass(DarenDetailMsgDao.class); 114 registerDaoClass(DarenDetailMsgDao.class);
118 registerDaoClass(DarenListMsgDao.class); 115 registerDaoClass(DarenListMsgDao.class);
  116 + registerDaoClass(DBFriendCircleMessageDao.class);
  117 + registerDaoClass(DBMomentDetailDao.class);
  118 + registerDaoClass(DBMomentItemDao.class);
119 registerDaoClass(DownloadInfoDao.class); 119 registerDaoClass(DownloadInfoDao.class);
120 registerDaoClass(ExceptionInfoDao.class); 120 registerDaoClass(ExceptionInfoDao.class);
121 registerDaoClass(HolidayThemeInfoDao.class); 121 registerDaoClass(HolidayThemeInfoDao.class);
@@ -133,9 +133,6 @@ public class DaoMaster extends AbstractDaoMaster { @@ -133,9 +133,6 @@ public class DaoMaster extends AbstractDaoMaster {
133 registerDaoClass(SearchHistoryDao.class); 133 registerDaoClass(SearchHistoryDao.class);
134 registerDaoClass(SysNumReadableDao.class); 134 registerDaoClass(SysNumReadableDao.class);
135 registerDaoClass(WitnessDao.class); 135 registerDaoClass(WitnessDao.class);
136 - registerDaoClass(DBMomentDetailDao.class);  
137 - registerDaoClass(DBMomentItemDao.class);  
138 - registerDaoClass(TestInfoDao.class);  
139 } 136 }
140 137
141 public DaoSession newSession() { 138 public DaoSession newSession() {
core/database/src/main/java/com/cnlive/database/dao/DaoSession.java
@@ -16,9 +16,11 @@ import com.cnlive.database.bean.ChatMedia; @@ -16,9 +16,11 @@ import com.cnlive.database.bean.ChatMedia;
16 import com.cnlive.database.bean.ContactList; 16 import com.cnlive.database.bean.ContactList;
17 import com.cnlive.database.bean.ContanctDaRenEntity; 17 import com.cnlive.database.bean.ContanctDaRenEntity;
18 import com.cnlive.database.bean.ContanctGroupChatEntity; 18 import com.cnlive.database.bean.ContanctGroupChatEntity;
19 -import com.cnlive.database.bean.DBFriendCircleMessage;  
20 import com.cnlive.database.bean.DarenDetailMsg; 19 import com.cnlive.database.bean.DarenDetailMsg;
21 import com.cnlive.database.bean.DarenListMsg; 20 import com.cnlive.database.bean.DarenListMsg;
  21 +import com.cnlive.database.bean.DBFriendCircleMessage;
  22 +import com.cnlive.database.bean.DBMomentDetail;
  23 +import com.cnlive.database.bean.DBMomentItem;
22 import com.cnlive.database.bean.DownloadInfo; 24 import com.cnlive.database.bean.DownloadInfo;
23 import com.cnlive.database.bean.ExceptionInfo; 25 import com.cnlive.database.bean.ExceptionInfo;
24 import com.cnlive.database.bean.HolidayThemeInfo; 26 import com.cnlive.database.bean.HolidayThemeInfo;
@@ -36,8 +38,37 @@ import com.cnlive.database.bean.SearchContent; @@ -36,8 +38,37 @@ import com.cnlive.database.bean.SearchContent;
36 import com.cnlive.database.bean.SearchHistory; 38 import com.cnlive.database.bean.SearchHistory;
37 import com.cnlive.database.bean.SysNumReadable; 39 import com.cnlive.database.bean.SysNumReadable;
38 import com.cnlive.database.bean.Witness; 40 import com.cnlive.database.bean.Witness;
39 -import com.cnlive.database.bean.DBMomentDetail;  
40 -import com.cnlive.database.bean.DBMomentItem; 41 +
  42 +import com.cnlive.database.dao.AudioPlayHistoricalRecordDao;
  43 +import com.cnlive.database.dao.AudioPlayLastInfoDao;
  44 +import com.cnlive.database.dao.ChatFileMsgDao;
  45 +import com.cnlive.database.dao.ChatImageAndVideoMsgDao;
  46 +import com.cnlive.database.dao.ChatMediaDao;
  47 +import com.cnlive.database.dao.ContactListDao;
  48 +import com.cnlive.database.dao.ContanctDaRenEntityDao;
  49 +import com.cnlive.database.dao.ContanctGroupChatEntityDao;
  50 +import com.cnlive.database.dao.DarenDetailMsgDao;
  51 +import com.cnlive.database.dao.DarenListMsgDao;
  52 +import com.cnlive.database.dao.DBFriendCircleMessageDao;
  53 +import com.cnlive.database.dao.DBMomentDetailDao;
  54 +import com.cnlive.database.dao.DBMomentItemDao;
  55 +import com.cnlive.database.dao.DownloadInfoDao;
  56 +import com.cnlive.database.dao.ExceptionInfoDao;
  57 +import com.cnlive.database.dao.HolidayThemeInfoDao;
  58 +import com.cnlive.database.dao.IMConversationInfoDao;
  59 +import com.cnlive.database.dao.IMGroupFaceMemberIdsDao;
  60 +import com.cnlive.database.dao.IMGroupMembersDao;
  61 +import com.cnlive.database.dao.IMGroupMembersListDao;
  62 +import com.cnlive.database.dao.IMGroupMembersManagerListDao;
  63 +import com.cnlive.database.dao.IMUserInfoDao;
  64 +import com.cnlive.database.dao.LaunchAdInfoDao;
  65 +import com.cnlive.database.dao.NewContactFriendEntityDao;
  66 +import com.cnlive.database.dao.NewPhoneContactEntityDao;
  67 +import com.cnlive.database.dao.NewsNumberDao;
  68 +import com.cnlive.database.dao.SearchContentDao;
  69 +import com.cnlive.database.dao.SearchHistoryDao;
  70 +import com.cnlive.database.dao.SysNumReadableDao;
  71 +import com.cnlive.database.dao.WitnessDao;
41 72
42 // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. 73 // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
43 74
@@ -56,9 +87,11 @@ public class DaoSession extends AbstractDaoSession { @@ -56,9 +87,11 @@ public class DaoSession extends AbstractDaoSession {
56 private final DaoConfig contactListDaoConfig; 87 private final DaoConfig contactListDaoConfig;
57 private final DaoConfig contanctDaRenEntityDaoConfig; 88 private final DaoConfig contanctDaRenEntityDaoConfig;
58 private final DaoConfig contanctGroupChatEntityDaoConfig; 89 private final DaoConfig contanctGroupChatEntityDaoConfig;
59 - private final DaoConfig dBFriendCircleMessageDaoConfig;  
60 private final DaoConfig darenDetailMsgDaoConfig; 90 private final DaoConfig darenDetailMsgDaoConfig;
61 private final DaoConfig darenListMsgDaoConfig; 91 private final DaoConfig darenListMsgDaoConfig;
  92 + private final DaoConfig dBFriendCircleMessageDaoConfig;
  93 + private final DaoConfig dBMomentDetailDaoConfig;
  94 + private final DaoConfig dBMomentItemDaoConfig;
62 private final DaoConfig downloadInfoDaoConfig; 95 private final DaoConfig downloadInfoDaoConfig;
63 private final DaoConfig exceptionInfoDaoConfig; 96 private final DaoConfig exceptionInfoDaoConfig;
64 private final DaoConfig holidayThemeInfoDaoConfig; 97 private final DaoConfig holidayThemeInfoDaoConfig;
@@ -76,9 +109,6 @@ public class DaoSession extends AbstractDaoSession { @@ -76,9 +109,6 @@ public class DaoSession extends AbstractDaoSession {
76 private final DaoConfig searchHistoryDaoConfig; 109 private final DaoConfig searchHistoryDaoConfig;
77 private final DaoConfig sysNumReadableDaoConfig; 110 private final DaoConfig sysNumReadableDaoConfig;
78 private final DaoConfig witnessDaoConfig; 111 private final DaoConfig witnessDaoConfig;
79 - private final DaoConfig dBMomentDetailDaoConfig;  
80 - private final DaoConfig dBMomentItemDaoConfig;  
81 - private final DaoConfig testInfoDaoConfig;  
82 112
83 private final AudioPlayHistoricalRecordDao audioPlayHistoricalRecordDao; 113 private final AudioPlayHistoricalRecordDao audioPlayHistoricalRecordDao;
84 private final AudioPlayLastInfoDao audioPlayLastInfoDao; 114 private final AudioPlayLastInfoDao audioPlayLastInfoDao;
@@ -88,9 +118,11 @@ public class DaoSession extends AbstractDaoSession { @@ -88,9 +118,11 @@ public class DaoSession extends AbstractDaoSession {
88 private final ContactListDao contactListDao; 118 private final ContactListDao contactListDao;
89 private final ContanctDaRenEntityDao contanctDaRenEntityDao; 119 private final ContanctDaRenEntityDao contanctDaRenEntityDao;
90 private final ContanctGroupChatEntityDao contanctGroupChatEntityDao; 120 private final ContanctGroupChatEntityDao contanctGroupChatEntityDao;
91 - private final DBFriendCircleMessageDao dBFriendCircleMessageDao;  
92 private final DarenDetailMsgDao darenDetailMsgDao; 121 private final DarenDetailMsgDao darenDetailMsgDao;
93 private final DarenListMsgDao darenListMsgDao; 122 private final DarenListMsgDao darenListMsgDao;
  123 + private final DBFriendCircleMessageDao dBFriendCircleMessageDao;
  124 + private final DBMomentDetailDao dBMomentDetailDao;
  125 + private final DBMomentItemDao dBMomentItemDao;
94 private final DownloadInfoDao downloadInfoDao; 126 private final DownloadInfoDao downloadInfoDao;
95 private final ExceptionInfoDao exceptionInfoDao; 127 private final ExceptionInfoDao exceptionInfoDao;
96 private final HolidayThemeInfoDao holidayThemeInfoDao; 128 private final HolidayThemeInfoDao holidayThemeInfoDao;
@@ -108,9 +140,6 @@ public class DaoSession extends AbstractDaoSession { @@ -108,9 +140,6 @@ public class DaoSession extends AbstractDaoSession {
108 private final SearchHistoryDao searchHistoryDao; 140 private final SearchHistoryDao searchHistoryDao;
109 private final SysNumReadableDao sysNumReadableDao; 141 private final SysNumReadableDao sysNumReadableDao;
110 private final WitnessDao witnessDao; 142 private final WitnessDao witnessDao;
111 - private final DBMomentDetailDao dBMomentDetailDao;  
112 - private final DBMomentItemDao dBMomentItemDao;  
113 - private final TestInfoDao testInfoDao;  
114 143
115 public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig> 144 public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>
116 daoConfigMap) { 145 daoConfigMap) {
@@ -140,15 +169,21 @@ public class DaoSession extends AbstractDaoSession { @@ -140,15 +169,21 @@ public class DaoSession extends AbstractDaoSession {
140 contanctGroupChatEntityDaoConfig = daoConfigMap.get(ContanctGroupChatEntityDao.class).clone(); 169 contanctGroupChatEntityDaoConfig = daoConfigMap.get(ContanctGroupChatEntityDao.class).clone();
141 contanctGroupChatEntityDaoConfig.initIdentityScope(type); 170 contanctGroupChatEntityDaoConfig.initIdentityScope(type);
142 171
143 - dBFriendCircleMessageDaoConfig = daoConfigMap.get(DBFriendCircleMessageDao.class).clone();  
144 - dBFriendCircleMessageDaoConfig.initIdentityScope(type);  
145 -  
146 darenDetailMsgDaoConfig = daoConfigMap.get(DarenDetailMsgDao.class).clone(); 172 darenDetailMsgDaoConfig = daoConfigMap.get(DarenDetailMsgDao.class).clone();
147 darenDetailMsgDaoConfig.initIdentityScope(type); 173 darenDetailMsgDaoConfig.initIdentityScope(type);
148 174
149 darenListMsgDaoConfig = daoConfigMap.get(DarenListMsgDao.class).clone(); 175 darenListMsgDaoConfig = daoConfigMap.get(DarenListMsgDao.class).clone();
150 darenListMsgDaoConfig.initIdentityScope(type); 176 darenListMsgDaoConfig.initIdentityScope(type);
151 177
  178 + dBFriendCircleMessageDaoConfig = daoConfigMap.get(DBFriendCircleMessageDao.class).clone();
  179 + dBFriendCircleMessageDaoConfig.initIdentityScope(type);
  180 +
  181 + dBMomentDetailDaoConfig = daoConfigMap.get(DBMomentDetailDao.class).clone();
  182 + dBMomentDetailDaoConfig.initIdentityScope(type);
  183 +
  184 + dBMomentItemDaoConfig = daoConfigMap.get(DBMomentItemDao.class).clone();
  185 + dBMomentItemDaoConfig.initIdentityScope(type);
  186 +
152 downloadInfoDaoConfig = daoConfigMap.get(DownloadInfoDao.class).clone(); 187 downloadInfoDaoConfig = daoConfigMap.get(DownloadInfoDao.class).clone();
153 downloadInfoDaoConfig.initIdentityScope(type); 188 downloadInfoDaoConfig.initIdentityScope(type);
154 189
@@ -200,15 +235,6 @@ public class DaoSession extends AbstractDaoSession { @@ -200,15 +235,6 @@ public class DaoSession extends AbstractDaoSession {
200 witnessDaoConfig = daoConfigMap.get(WitnessDao.class).clone(); 235 witnessDaoConfig = daoConfigMap.get(WitnessDao.class).clone();
201 witnessDaoConfig.initIdentityScope(type); 236 witnessDaoConfig.initIdentityScope(type);
202 237
203 - dBMomentDetailDaoConfig = daoConfigMap.get(DBMomentDetailDao.class).clone();  
204 - dBMomentDetailDaoConfig.initIdentityScope(type);  
205 -  
206 - dBMomentItemDaoConfig = daoConfigMap.get(DBMomentItemDao.class).clone();  
207 - dBMomentItemDaoConfig.initIdentityScope(type);  
208 -  
209 - testInfoDaoConfig = daoConfigMap.get(TestInfoDao.class).clone();  
210 - testInfoDaoConfig.initIdentityScope(type);  
211 -  
212 audioPlayHistoricalRecordDao = new AudioPlayHistoricalRecordDao(audioPlayHistoricalRecordDaoConfig, this); 238 audioPlayHistoricalRecordDao = new AudioPlayHistoricalRecordDao(audioPlayHistoricalRecordDaoConfig, this);
213 audioPlayLastInfoDao = new AudioPlayLastInfoDao(audioPlayLastInfoDaoConfig, this); 239 audioPlayLastInfoDao = new AudioPlayLastInfoDao(audioPlayLastInfoDaoConfig, this);
214 chatFileMsgDao = new ChatFileMsgDao(chatFileMsgDaoConfig, this); 240 chatFileMsgDao = new ChatFileMsgDao(chatFileMsgDaoConfig, this);
@@ -217,9 +243,11 @@ public class DaoSession extends AbstractDaoSession { @@ -217,9 +243,11 @@ public class DaoSession extends AbstractDaoSession {
217 contactListDao = new ContactListDao(contactListDaoConfig, this); 243 contactListDao = new ContactListDao(contactListDaoConfig, this);
218 contanctDaRenEntityDao = new ContanctDaRenEntityDao(contanctDaRenEntityDaoConfig, this); 244 contanctDaRenEntityDao = new ContanctDaRenEntityDao(contanctDaRenEntityDaoConfig, this);
219 contanctGroupChatEntityDao = new ContanctGroupChatEntityDao(contanctGroupChatEntityDaoConfig, this); 245 contanctGroupChatEntityDao = new ContanctGroupChatEntityDao(contanctGroupChatEntityDaoConfig, this);
220 - dBFriendCircleMessageDao = new DBFriendCircleMessageDao(dBFriendCircleMessageDaoConfig, this);  
221 darenDetailMsgDao = new DarenDetailMsgDao(darenDetailMsgDaoConfig, this); 246 darenDetailMsgDao = new DarenDetailMsgDao(darenDetailMsgDaoConfig, this);
222 darenListMsgDao = new DarenListMsgDao(darenListMsgDaoConfig, this); 247 darenListMsgDao = new DarenListMsgDao(darenListMsgDaoConfig, this);
  248 + dBFriendCircleMessageDao = new DBFriendCircleMessageDao(dBFriendCircleMessageDaoConfig, this);
  249 + dBMomentDetailDao = new DBMomentDetailDao(dBMomentDetailDaoConfig, this);
  250 + dBMomentItemDao = new DBMomentItemDao(dBMomentItemDaoConfig, this);
223 downloadInfoDao = new DownloadInfoDao(downloadInfoDaoConfig, this); 251 downloadInfoDao = new DownloadInfoDao(downloadInfoDaoConfig, this);
224 exceptionInfoDao = new ExceptionInfoDao(exceptionInfoDaoConfig, this); 252 exceptionInfoDao = new ExceptionInfoDao(exceptionInfoDaoConfig, this);
225 holidayThemeInfoDao = new HolidayThemeInfoDao(holidayThemeInfoDaoConfig, this); 253 holidayThemeInfoDao = new HolidayThemeInfoDao(holidayThemeInfoDaoConfig, this);
@@ -237,9 +265,6 @@ public class DaoSession extends AbstractDaoSession { @@ -237,9 +265,6 @@ public class DaoSession extends AbstractDaoSession {
237 searchHistoryDao = new SearchHistoryDao(searchHistoryDaoConfig, this); 265 searchHistoryDao = new SearchHistoryDao(searchHistoryDaoConfig, this);
238 sysNumReadableDao = new SysNumReadableDao(sysNumReadableDaoConfig, this); 266 sysNumReadableDao = new SysNumReadableDao(sysNumReadableDaoConfig, this);
239 witnessDao = new WitnessDao(witnessDaoConfig, this); 267 witnessDao = new WitnessDao(witnessDaoConfig, this);
240 - dBMomentDetailDao = new DBMomentDetailDao(dBMomentDetailDaoConfig, this);  
241 - dBMomentItemDao = new DBMomentItemDao(dBMomentItemDaoConfig, this);  
242 - testInfoDao = new TestInfoDao(testInfoDaoConfig, this);  
243 268
244 registerDao(AudioPlayHistoricalRecord.class, audioPlayHistoricalRecordDao); 269 registerDao(AudioPlayHistoricalRecord.class, audioPlayHistoricalRecordDao);
245 registerDao(AudioPlayLastInfo.class, audioPlayLastInfoDao); 270 registerDao(AudioPlayLastInfo.class, audioPlayLastInfoDao);
@@ -249,9 +274,11 @@ public class DaoSession extends AbstractDaoSession { @@ -249,9 +274,11 @@ public class DaoSession extends AbstractDaoSession {
249 registerDao(ContactList.class, contactListDao); 274 registerDao(ContactList.class, contactListDao);
250 registerDao(ContanctDaRenEntity.class, contanctDaRenEntityDao); 275 registerDao(ContanctDaRenEntity.class, contanctDaRenEntityDao);
251 registerDao(ContanctGroupChatEntity.class, contanctGroupChatEntityDao); 276 registerDao(ContanctGroupChatEntity.class, contanctGroupChatEntityDao);
252 - registerDao(DBFriendCircleMessage.class, dBFriendCircleMessageDao);  
253 registerDao(DarenDetailMsg.class, darenDetailMsgDao); 277 registerDao(DarenDetailMsg.class, darenDetailMsgDao);
254 registerDao(DarenListMsg.class, darenListMsgDao); 278 registerDao(DarenListMsg.class, darenListMsgDao);
  279 + registerDao(DBFriendCircleMessage.class, dBFriendCircleMessageDao);
  280 + registerDao(DBMomentDetail.class, dBMomentDetailDao);
  281 + registerDao(DBMomentItem.class, dBMomentItemDao);
255 registerDao(DownloadInfo.class, downloadInfoDao); 282 registerDao(DownloadInfo.class, downloadInfoDao);
256 registerDao(ExceptionInfo.class, exceptionInfoDao); 283 registerDao(ExceptionInfo.class, exceptionInfoDao);
257 registerDao(HolidayThemeInfo.class, holidayThemeInfoDao); 284 registerDao(HolidayThemeInfo.class, holidayThemeInfoDao);
@@ -269,9 +296,6 @@ public class DaoSession extends AbstractDaoSession { @@ -269,9 +296,6 @@ public class DaoSession extends AbstractDaoSession {
269 registerDao(SearchHistory.class, searchHistoryDao); 296 registerDao(SearchHistory.class, searchHistoryDao);
270 registerDao(SysNumReadable.class, sysNumReadableDao); 297 registerDao(SysNumReadable.class, sysNumReadableDao);
271 registerDao(Witness.class, witnessDao); 298 registerDao(Witness.class, witnessDao);
272 - registerDao(DBMomentDetail.class, dBMomentDetailDao);  
273 - registerDao(DBMomentItem.class, dBMomentItemDao);  
274 - registerDao(TestInfo.class, testInfoDao);  
275 } 299 }
276 300
277 public void clear() { 301 public void clear() {
@@ -283,9 +307,11 @@ public class DaoSession extends AbstractDaoSession { @@ -283,9 +307,11 @@ public class DaoSession extends AbstractDaoSession {
283 contactListDaoConfig.clearIdentityScope(); 307 contactListDaoConfig.clearIdentityScope();
284 contanctDaRenEntityDaoConfig.clearIdentityScope(); 308 contanctDaRenEntityDaoConfig.clearIdentityScope();
285 contanctGroupChatEntityDaoConfig.clearIdentityScope(); 309 contanctGroupChatEntityDaoConfig.clearIdentityScope();
286 - dBFriendCircleMessageDaoConfig.clearIdentityScope();  
287 darenDetailMsgDaoConfig.clearIdentityScope(); 310 darenDetailMsgDaoConfig.clearIdentityScope();
288 darenListMsgDaoConfig.clearIdentityScope(); 311 darenListMsgDaoConfig.clearIdentityScope();
  312 + dBFriendCircleMessageDaoConfig.clearIdentityScope();
  313 + dBMomentDetailDaoConfig.clearIdentityScope();
  314 + dBMomentItemDaoConfig.clearIdentityScope();
289 downloadInfoDaoConfig.clearIdentityScope(); 315 downloadInfoDaoConfig.clearIdentityScope();
290 exceptionInfoDaoConfig.clearIdentityScope(); 316 exceptionInfoDaoConfig.clearIdentityScope();
291 holidayThemeInfoDaoConfig.clearIdentityScope(); 317 holidayThemeInfoDaoConfig.clearIdentityScope();
@@ -303,9 +329,6 @@ public class DaoSession extends AbstractDaoSession { @@ -303,9 +329,6 @@ public class DaoSession extends AbstractDaoSession {
303 searchHistoryDaoConfig.clearIdentityScope(); 329 searchHistoryDaoConfig.clearIdentityScope();
304 sysNumReadableDaoConfig.clearIdentityScope(); 330 sysNumReadableDaoConfig.clearIdentityScope();
305 witnessDaoConfig.clearIdentityScope(); 331 witnessDaoConfig.clearIdentityScope();
306 - dBMomentDetailDaoConfig.clearIdentityScope();  
307 - dBMomentItemDaoConfig.clearIdentityScope();  
308 - testInfoDaoConfig.clearIdentityScope();  
309 } 332 }
310 333
311 public AudioPlayHistoricalRecordDao getAudioPlayHistoricalRecordDao() { 334 public AudioPlayHistoricalRecordDao getAudioPlayHistoricalRecordDao() {
@@ -340,10 +363,6 @@ public class DaoSession extends AbstractDaoSession { @@ -340,10 +363,6 @@ public class DaoSession extends AbstractDaoSession {
340 return contanctGroupChatEntityDao; 363 return contanctGroupChatEntityDao;
341 } 364 }
342 365
343 - public DBFriendCircleMessageDao getDBFriendCircleMessageDao() {  
344 - return dBFriendCircleMessageDao;  
345 - }  
346 -  
347 public DarenDetailMsgDao getDarenDetailMsgDao() { 366 public DarenDetailMsgDao getDarenDetailMsgDao() {
348 return darenDetailMsgDao; 367 return darenDetailMsgDao;
349 } 368 }
@@ -352,6 +371,18 @@ public class DaoSession extends AbstractDaoSession { @@ -352,6 +371,18 @@ public class DaoSession extends AbstractDaoSession {
352 return darenListMsgDao; 371 return darenListMsgDao;
353 } 372 }
354 373
  374 + public DBFriendCircleMessageDao getDBFriendCircleMessageDao() {
  375 + return dBFriendCircleMessageDao;
  376 + }
  377 +
  378 + public DBMomentDetailDao getDBMomentDetailDao() {
  379 + return dBMomentDetailDao;
  380 + }
  381 +
  382 + public DBMomentItemDao getDBMomentItemDao() {
  383 + return dBMomentItemDao;
  384 + }
  385 +
355 public DownloadInfoDao getDownloadInfoDao() { 386 public DownloadInfoDao getDownloadInfoDao() {
356 return downloadInfoDao; 387 return downloadInfoDao;
357 } 388 }
@@ -420,16 +451,4 @@ public class DaoSession extends AbstractDaoSession { @@ -420,16 +451,4 @@ public class DaoSession extends AbstractDaoSession {
420 return witnessDao; 451 return witnessDao;
421 } 452 }
422 453
423 - public DBMomentDetailDao getDBMomentDetailDao() {  
424 - return dBMomentDetailDao;  
425 - }  
426 -  
427 - public DBMomentItemDao getDBMomentItemDao() {  
428 - return dBMomentItemDao;  
429 - }  
430 -  
431 - public TestInfoDao getTestInfoDao() {  
432 - return testInfoDao;  
433 - }  
434 -  
435 } 454 }
core/imageload/src/main/java/com/cnlive/core/gridview/AutoGridMode.java 0 → 100644
  1 +package com.cnlive.core.gridview;
  2 +
  3 +import java.lang.annotation.Retention;
  4 +import java.lang.annotation.RetentionPolicy;
  5 +
  6 +import androidx.annotation.IntDef;
  7 +
  8 +/**
  9 + * created by hanyayun
  10 + * on 2020/2/13
  11 + */
  12 +@IntDef({AutoGridMode.GRID_NINE,
  13 + AutoGridMode.GRID_NORMAL})
  14 +@Retention(RetentionPolicy.SOURCE)
  15 +public @interface AutoGridMode {
  16 + // 网格图的两种模式中的九宫格模式
  17 + int GRID_NINE = 0;
  18 + // 网格图的两种模式中的普通模式
  19 + int GRID_NORMAL = 1;
  20 +}
core/imageload/src/main/java/com/cnlive/core/gridview/AutoGridView.java 0 → 100644
  1 +package com.cnlive.core.gridview;
  2 +
  3 +import android.content.Context;
  4 +import android.content.res.TypedArray;
  5 +import android.database.DataSetObserver;
  6 +import android.util.AttributeSet;
  7 +import android.view.View;
  8 +import android.view.ViewGroup;
  9 +
  10 +import com.cnlive.core.gridview.adapter.BaseAutoGridAdapter;
  11 +import com.cnlive.core.gridview.model.SizeHelper;
  12 +import com.cnlive.core.gridview.model.SizeInfo;
  13 +import com.cnlive.core.gridview.model.SizeParam;
  14 +import com.cnlive.core.imageload.R;
  15 +
  16 +import java.lang.ref.SoftReference;
  17 +import java.util.ArrayList;
  18 +import java.util.HashMap;
  19 +import java.util.List;
  20 +
  21 +import androidx.annotation.FloatRange;
  22 +
  23 +/**
  24 + * created by hanyayun
  25 + * on 2020/2/13
  26 + */
  27 +public class AutoGridView extends ViewGroup {
  28 +
  29 + /**
  30 + * 默认值
  31 + */
  32 + // 无效的值
  33 + private static final int INVALID_VAL = -1;
  34 + // 默认网格图模式
  35 + private static final int DEF_MODE = AutoGridMode.GRID_NINE;
  36 + // 默认的 item 最大行数
  37 + private static final int DEF_ROW = 3;
  38 + // 默认的 item 最大列数
  39 + private static final int DEF_COLUMN = 3;
  40 + // 默认的 item 高度
  41 + public static final int DEF_ITEM_HEIGHT = INVALID_VAL;
  42 + // 默认的 item 横向间距
  43 + private static final int DEF_HORIZONTAL_SPACE = 10;
  44 + // 默认的 item 纵向间距
  45 + private static final int DEF_VERTICAL_SPACE = 10;
  46 + // 九宫格模式时,当只有一个 item 时,item 的宽与父容器可用总宽度(即去除左右 padding 后的 width )的比
  47 + // 此处默认 DEF_SINGLE_WIDTH_PERCENT 为无效值,即 item 的宽度自适应
  48 + private static final float DEF_SINGLE_WIDTH_PERCENT = INVALID_VAL;
  49 + // 九宫格模式时,当只有一个 item 时,item 的高与父容器可用总宽度(即去除左右 padding 后的 width )的比
  50 + private static final float DEF_SINGLE_HEIGHT_PERCENT = INVALID_VAL;
  51 +
  52 + /**
  53 + * 变量
  54 + */
  55 + // 网格图的模式
  56 + private int mMode;
  57 + // item 的行数
  58 + private int mRow;
  59 + // item 的列数
  60 + private int mColumn;
  61 + // item 的高度
  62 + private float mItemHeight;
  63 + // item 之间的横向间距
  64 + private float mHorizontalSpace;
  65 + // item 之间的纵向间距
  66 + private float mVerticalSpace;
  67 + // 九宫格模式时,当只有一个 item 时,item 的宽与父容器可用总宽度(即去除左右 padding 后的 width )的比
  68 + private float mNineSingleWidthPer;
  69 + // 九宫格模式时,当只有一个 item 时,item 的高与父容器可用总宽度(即去除左右 padding 后的 width )的比
  70 + private float mNineSingleHeightPer;
  71 +
  72 + // 网格数据计算辅助类
  73 + private SizeHelper mSizeHelper;
  74 + private SizeParam mSizeParam;
  75 + // SizeHelper 中计算结果后,返回的结果类
  76 + private SizeInfo mSizeInfo;
  77 + // 缓存 item 的 viewType
  78 + private ArrayList<String> mCacheTypeBin;
  79 + // 缓存器,存储 item,用于复用
  80 + private HashMap<String, List<SoftReference<View>>> mCacheBin;
  81 + private AdapterObserver mDataSetObserver;
  82 + private BaseAutoGridAdapter mAdapter;
  83 + private OnItemClickListener mItemClickListener;
  84 + private OnItemLongClickListener mItemLongClickListener;
  85 +
  86 + public AutoGridView(Context context) {
  87 + super(context);
  88 + init(context, null);
  89 + }
  90 +
  91 + public AutoGridView(Context context, AttributeSet attrs) {
  92 + super(context, attrs);
  93 + init(context, attrs);
  94 + }
  95 +
  96 + public AutoGridView(Context context, AttributeSet attrs, int defStyleAttr) {
  97 + super(context, attrs, defStyleAttr);
  98 + init(context, attrs);
  99 + }
  100 +
  101 + private void init(Context context, AttributeSet attrs) {
  102 + initData();
  103 + if (attrs != null) {
  104 + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoGridView);
  105 + if (a != null) {
  106 + mMode = a.getInt(R.styleable.AutoGridView_agv_mode, DEF_MODE);
  107 + mRow = a.getInt(R.styleable.AutoGridView_agv_row, DEF_ROW);
  108 + mColumn = a.getInt(R.styleable.AutoGridView_agv_column, DEF_COLUMN);
  109 + mItemHeight = a.getDimension(R.styleable.AutoGridView_agv_item_height, DEF_ITEM_HEIGHT);
  110 + mHorizontalSpace = a.getDimension(R.styleable.AutoGridView_agv_horizontal_space, DEF_HORIZONTAL_SPACE);
  111 + mVerticalSpace = a.getDimension(R.styleable.AutoGridView_agv_vertical_space, DEF_VERTICAL_SPACE);
  112 + mNineSingleWidthPer = a.getFloat(R.styleable.AutoGridView_agv_nines_widthper, DEF_SINGLE_WIDTH_PERCENT);
  113 + mNineSingleHeightPer = a.getFloat(R.styleable.AutoGridView_agv_nines_heightper, DEF_SINGLE_HEIGHT_PERCENT);
  114 + a.recycle();
  115 + }
  116 + }
  117 + }
  118 +
  119 + private void initData() {
  120 + mMode = DEF_MODE;
  121 + mRow = DEF_ROW;
  122 + mColumn = DEF_COLUMN;
  123 + mItemHeight = DEF_ITEM_HEIGHT;
  124 + mHorizontalSpace = DEF_HORIZONTAL_SPACE;
  125 + mVerticalSpace = DEF_VERTICAL_SPACE;
  126 + mNineSingleWidthPer = DEF_SINGLE_WIDTH_PERCENT;
  127 + mNineSingleHeightPer = DEF_SINGLE_HEIGHT_PERCENT;
  128 +
  129 + mSizeHelper = new SizeHelper();
  130 + }
  131 +
  132 + public void setAdapter(BaseAutoGridAdapter adapter) {
  133 + if (mAdapter != null && mDataSetObserver != null) {
  134 + // 删除已经存在的观察者
  135 + mAdapter.unregisterDataSetObserver(mDataSetObserver);
  136 + }
  137 + removeAllViews();
  138 + // 清空缓存器
  139 + if (mCacheTypeBin != null) {
  140 + mCacheTypeBin.clear();
  141 + }
  142 + if (mCacheBin != null) {
  143 + mCacheBin.clear();
  144 + }
  145 + // 重置 adapter
  146 + mAdapter = adapter;
  147 + if (mAdapter != null) {
  148 + mDataSetObserver = new AdapterObserver();
  149 + // 注册观察者
  150 + mAdapter.registerDataSetObserver(mDataSetObserver);
  151 + if (mAdapter.getItemCount() > 0) {
  152 + addItemViews();
  153 + }
  154 + }
  155 + }
  156 +
  157 + /**
  158 + * 通知刷新
  159 + */
  160 + private void notifyChanged() {
  161 + if (mAdapter != null) {
  162 + int newSize = mAdapter.getItemCount();
  163 + if (newSize == 0) {
  164 + if (mCacheTypeBin != null) {
  165 + mCacheTypeBin.clear();
  166 + }
  167 + if (mCacheBin != null) {
  168 + mCacheBin.clear();
  169 + }
  170 + } else {
  171 + if (mCacheBin == null) mCacheBin = new HashMap<>();
  172 + for (int i = 0, len = mCacheTypeBin.size(); i < len; i++) {
  173 + String key = mCacheTypeBin.get(i);
  174 + List<SoftReference<View>> views = mCacheBin.get(key);
  175 + views = (views != null ? views : new ArrayList<SoftReference<View>>());
  176 + views.add(new SoftReference<View>(getChildAt(i)));
  177 + mCacheBin.put(key, views);
  178 + }
  179 + }
  180 + removeAllViews();
  181 + if (mCacheTypeBin != null) {
  182 + mCacheTypeBin.clear();
  183 + }
  184 + for (int i = 0; i < newSize; i++) {
  185 + String key = mMode + "_" + mAdapter.getItemViewType(i);
  186 + mCacheTypeBin.add(key);
  187 + // 从缓存器中取出 key 类型的 view 列表
  188 + List<SoftReference<View>> views = mCacheBin.get(key);
  189 + /** 此处做简单的缓存复用处理 */
  190 + if (views != null && views.size() > 0) {
  191 + boolean isAddItem = false;
  192 + for (SoftReference<View> softReference : views) {
  193 + if (softReference != null && softReference.get() != null) {
  194 + View itemView = softReference.get();
  195 + // 如果列表中的 item 还没有父容器,则复用该 item
  196 + if (itemView.getParent() == null) {
  197 + addItemClickListener(itemView, i);
  198 + addItemLongClickListener(itemView, i);
  199 + addView(mAdapter.getView(i, itemView, this), new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
  200 + isAddItem = true;
  201 + views.remove(itemView);
  202 + mCacheBin.put(key, views);
  203 + break;
  204 + }
  205 + }
  206 + }
  207 + // 如果从 views 中未找到匹配的 item ,则新建 item
  208 + if (!isAddItem) {
  209 + View itemView = mAdapter.getView(i, null, this);
  210 + // 将新建的 item 存入列表中
  211 + views.add(new SoftReference<View>(itemView));
  212 + addItemClickListener(itemView, i);
  213 + addItemLongClickListener(itemView, i);
  214 + addView(itemView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
  215 + }
  216 + }
  217 + // 如果没有 key 类型的 view 存在,则新建 item
  218 + else {
  219 + View itemView = mAdapter.getView(i, null, this);
  220 + views = (views != null ? views : new ArrayList<SoftReference<View>>());
  221 + views.add(new SoftReference<View>(itemView));
  222 + addItemClickListener(itemView, i);
  223 + addItemLongClickListener(itemView, i);
  224 + addView(itemView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
  225 + }
  226 + }
  227 + if (mCacheBin != null && mCacheBin.size() > 0) {
  228 + mCacheBin.clear();
  229 + }
  230 + }
  231 + requestLayout();
  232 + invalidate();
  233 + }
  234 +
  235 + /**
  236 + * 添加 item
  237 + */
  238 + private void addItemViews() {
  239 + int totalCount = mAdapter.getItemCount();
  240 + int maxCount = mRow * mColumn;
  241 + int childCount = totalCount > maxCount ? maxCount : totalCount;
  242 + if (mCacheTypeBin == null) mCacheTypeBin = new ArrayList<>();
  243 + for (int i = 0; i < childCount; i++) {
  244 + View itemView = mAdapter.getView(i, null, this);
  245 + String key = mMode + "_" + mAdapter.getItemViewType(i);
  246 + mCacheTypeBin.add(key);
  247 + addItemClickListener(itemView, i);
  248 + addItemLongClickListener(itemView, i);
  249 + /** 一定要有 LayoutParams ,addView 的时候,item 在 xml 中的 width 和 height 设置的值,都是没效果的(变成 wrap_content ),
  250 + * 可能会出现控件的宽高显示偏差,所以必须设置此句)*/
  251 + addView(itemView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
  252 + }
  253 + }
  254 +
  255 + /**
  256 + * 设置 item 的点击监听事件
  257 + *
  258 + * @param view
  259 + * @param position
  260 + */
  261 + private void addItemClickListener(View view, final int position) {
  262 + view.setOnClickListener(new OnClickListener() {
  263 + @Override
  264 + public void onClick(View v) {
  265 + if (mItemClickListener != null) {
  266 + mItemClickListener.onItemClick(position, v);
  267 + }
  268 + }
  269 + });
  270 + }
  271 +
  272 + /**
  273 + * 设置 item 的长按监听事件
  274 + *
  275 + * @param view
  276 + * @param position
  277 + */
  278 + private void addItemLongClickListener(View view, final int position) {
  279 + view.setOnLongClickListener(new OnLongClickListener() {
  280 + @Override
  281 + public boolean onLongClick(View v) {
  282 + if (mItemLongClickListener != null) {
  283 + return mItemLongClickListener.onItemLongClick(position, v);
  284 + }
  285 + return false;
  286 + }
  287 + });
  288 + }
  289 +
  290 + @Override
  291 + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  292 + super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  293 + int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
  294 + int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
  295 + int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  296 + int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  297 + if (mAdapter == null || getChildCount() == 0) {
  298 + setMeasuredDimension(measureWidth, heightMode == MeasureSpec.EXACTLY ? measureHeight : getPaddingTop() + getPaddingBottom());
  299 + return;
  300 + }
  301 + int maxWidth = measureWidth - getPaddingLeft() - getPaddingRight();
  302 + int childCount = getChildCount();
  303 + mSizeParam = new SizeParam();
  304 + mSizeParam.setMode(mMode)
  305 + .setRow(mRow)
  306 + .setColumn(mColumn)
  307 + .setMaxWidth(maxWidth)
  308 + .setItemCount(childCount)
  309 + .setItemHeight(mItemHeight)
  310 + .setHorizontalSpace(mHorizontalSpace)
  311 + .setVerticalSpace(mVerticalSpace)
  312 + .setSingleWidthPer(mNineSingleWidthPer)
  313 + .setSingleHeightPer(mNineSingleHeightPer);
  314 + if (mSizeHelper == null) {
  315 + mSizeHelper = new SizeHelper();
  316 + }
  317 + mSizeInfo = mSizeHelper.calculateSize(mSizeParam);
  318 + // 如果只有一个 child ,且当前模式为九宫格模式
  319 + if (childCount == 1 && mMode == AutoGridMode.GRID_NINE) {
  320 + View child = getChildAt(0);
  321 + int childWms, childHms;
  322 + // 宽度自适应
  323 + if (mNineSingleWidthPer == INVALID_VAL) {
  324 + // child 的宽度介于 0 到 父容器的最大宽度之间
  325 + childWms = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST);
  326 + } else {
  327 + childWms = MeasureSpec.makeMeasureSpec((int) mSizeInfo.getChildWidth(), MeasureSpec.EXACTLY);
  328 + }
  329 + // 高度自适应
  330 + if (mNineSingleHeightPer == INVALID_VAL) {
  331 + // child 可以获取它想要的高度
  332 + childHms = MeasureSpec.makeMeasureSpec((int) mSizeInfo.getChildHeight(), MeasureSpec.UNSPECIFIED);
  333 + } else {
  334 + childHms = MeasureSpec.makeMeasureSpec((int) mSizeInfo.getChildHeight(), MeasureSpec.EXACTLY);
  335 + }
  336 + child.measure(childWms, childHms);
  337 + int cw = child.getMeasuredWidth() == 0 ? maxWidth : child.getMeasuredWidth();
  338 + int ch = child.getMeasuredHeight() == 0 ? (int) (0.6 * maxWidth) : child.getMeasuredHeight();
  339 + mSizeInfo.setChildWidth(cw);
  340 + mSizeInfo.setChildHeight(ch);
  341 + mSizeInfo.setParentWidth(cw);
  342 + mSizeInfo.setParentHeight(ch);
  343 + } else {
  344 + for (int i = 0; i < getChildCount(); i++) {
  345 + View child = getChildAt(i);
  346 + if (child != null) {
  347 + child.measure(MeasureSpec.makeMeasureSpec((int) mSizeInfo.getChildWidth(), MeasureSpec.EXACTLY),
  348 + MeasureSpec.makeMeasureSpec((int) mSizeInfo.getChildHeight(), MeasureSpec.EXACTLY));
  349 + }
  350 + }
  351 + }
  352 +
  353 + // 测量 AutoGridView 的大小
  354 + if (mSizeInfo != null) {
  355 + int widthMeasure = (int) (mSizeInfo.getParentWidth() + getPaddingLeft() + getPaddingRight());
  356 + int heightMeasure = (int) (mSizeInfo.getParentHeight() + getPaddingTop() + getPaddingBottom());
  357 + setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? measureWidth : widthMeasure, heightMode == MeasureSpec.EXACTLY ? measureHeight : heightMeasure);
  358 + } else {
  359 + setMeasuredDimension(measureWidth, heightMode == MeasureSpec.EXACTLY ? measureHeight : getPaddingTop() + getPaddingBottom());
  360 + }
  361 + }
  362 +
  363 + @Override
  364 + protected void onLayout(boolean changed, int l, int t, int r, int b) {
  365 + if (mAdapter == null || getChildCount() == 0 || mSizeInfo == null) {
  366 + return;
  367 + }
  368 + // 遍历 child,设置每个 child 所在的位置
  369 + int childCount = getChildCount();
  370 + for (int i = 0; i < childCount; i++) {
  371 + int[] position = mSizeHelper.findPosition(mSizeInfo, i);
  372 + int left = (int) (getPaddingLeft() + position[1] * (mSizeInfo.getChildWidth() + mHorizontalSpace));
  373 + int top = (int) (getPaddingTop() + position[0] * (mSizeInfo.getChildHeight() + mVerticalSpace));
  374 + int right = (int) (left + mSizeInfo.getChildWidth());
  375 + int bottom = (int) (top + mSizeInfo.getChildHeight());
  376 + View child = getChildAt(i);
  377 + child.layout(left, top, right, bottom);
  378 + }
  379 + }
  380 +
  381 + public interface OnItemClickListener {
  382 + void onItemClick(int position, View view);
  383 + }
  384 +
  385 + public interface OnItemLongClickListener {
  386 + boolean onItemLongClick(int position, View view);
  387 + }
  388 +
  389 + public void setOnItemClickListener(OnItemClickListener listener) {
  390 + this.mItemClickListener = listener;
  391 + }
  392 +
  393 + public void setOnItemLongClickListener(OnItemLongClickListener listener) {
  394 + this.mItemLongClickListener = listener;
  395 + }
  396 +
  397 + public void setMode(@AutoGridMode int mode) {
  398 + this.mMode = mode;
  399 + }
  400 +
  401 + @AutoGridMode
  402 + public int getMode() {
  403 + return mMode;
  404 + }
  405 +
  406 + public void setRow(int row) {
  407 + this.mRow = row;
  408 + }
  409 +
  410 + public int getRow() {
  411 + return mRow;
  412 + }
  413 +
  414 + public void setColumn(int column) {
  415 + this.mColumn = column;
  416 + }
  417 +
  418 + public int getColumn() {
  419 + return mColumn;
  420 + }
  421 +
  422 + public void setItemHeight(float itemHeight) {
  423 + this.mItemHeight = itemHeight;
  424 + }
  425 +
  426 + public float getItemHeight() {
  427 + return mItemHeight;
  428 + }
  429 +
  430 + public void setHorizontalSpace(float horizontalSpace) {
  431 + this.mHorizontalSpace = horizontalSpace;
  432 + }
  433 +
  434 + public float getHorizontalSpace() {
  435 + return mHorizontalSpace;
  436 + }
  437 +
  438 + public void setVerticalSpace(float verticalSpace) {
  439 + this.mVerticalSpace = verticalSpace;
  440 + }
  441 +
  442 + public float getVerticalSpace() {
  443 + return mVerticalSpace;
  444 + }
  445 +
  446 + public void setNineSingleWidthPercent(@FloatRange(from = 0f, to = 1f) float nineSingleWidthPercent) {
  447 + this.mNineSingleWidthPer = nineSingleWidthPercent;
  448 + }
  449 +
  450 + public float getNineSingleWidthPercent() {
  451 + return mNineSingleWidthPer;
  452 + }
  453 +
  454 + public void setNineSingleHeightPercent(@FloatRange(from = 0f, to = 1f) float nineSingleHeightPercent) {
  455 + this.mNineSingleHeightPer = nineSingleHeightPercent;
  456 + }
  457 +
  458 + public float getNineSingleHeightPercent() {
  459 + return mNineSingleHeightPer;
  460 + }
  461 +
  462 + private class AdapterObserver extends DataSetObserver {
  463 +
  464 + @Override
  465 + public void onChanged() {
  466 + super.onChanged();
  467 + notifyChanged();
  468 + }
  469 +
  470 + @Override
  471 + public void onInvalidated() {
  472 + super.onInvalidated();
  473 + }
  474 + }
  475 +
  476 + @Override
  477 + protected void onDetachedFromWindow() {
  478 + if (mAdapter != null) {
  479 + if (mDataSetObserver != null) {
  480 + mAdapter.unregisterDataSetObserver(mDataSetObserver);
  481 + }
  482 + mAdapter = null;
  483 + }
  484 + if (mCacheTypeBin != null) {
  485 + mCacheTypeBin.clear();
  486 + mCacheTypeBin = null;
  487 + }
  488 + if (mCacheBin != null) {
  489 + mCacheBin.clear();
  490 + mCacheBin = null;
  491 + }
  492 + mItemClickListener = null;
  493 + mItemLongClickListener = null;
  494 + super.onDetachedFromWindow();
  495 + }
  496 +}
  497 +
core/imageload/src/main/java/com/cnlive/core/gridview/GridImgUtil.java 0 → 100644
  1 +package com.cnlive.core.gridview;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.drawable.Drawable;
  5 +import android.widget.ImageView;
  6 +
  7 +import com.bumptech.glide.request.RequestListener;
  8 +import com.bumptech.glide.request.target.SimpleTarget;
  9 +import com.cnlive.core.imageload.R;
  10 +import com.cnlive.core.libs.base.application.GlideApp;
  11 +
  12 +/**
  13 + * created by hanyayun
  14 + * on 2020/2/13
  15 + */
  16 +public class GridImgUtil {
  17 + public static void loadImage(Context context, final Object src, final ImageView view) {
  18 + GlideApp.with(context)
  19 + .load(src)
  20 +// .placeholder(R.drawable.img_placeholder)
  21 +// .error(R.drawable.img_placeholder)
  22 + .into(view);
  23 + }
  24 +
  25 + public static void loadImage(Context context, final Object src, final ImageView view, RequestListener<Drawable> listener) {
  26 + GlideApp.with(context)
  27 + .load(src)
  28 +// .placeholder(R.drawable.img_placeholder)
  29 +// .error(R.drawable.img_placeholder)
  30 + .listener(listener)
  31 + .into(view);
  32 + }
  33 +
  34 + public static void loadImage(Context context, final Object src, final SimpleTarget<Drawable> target) {
  35 + GlideApp.with(context)
  36 + .load(src)
  37 + .thumbnail(0.1f)
  38 +// .placeholder(R.drawable.img_placeholder)
  39 +// .error(R.drawable.img_placeholder)
  40 + .into(target);
  41 + }
  42 +}
  43 +
core/imageload/src/main/java/com/cnlive/core/gridview/adapter/BaseAutoGridAdapter.java 0 → 100644
  1 +package com.cnlive.core.gridview.adapter;
  2 +
  3 +import android.database.DataSetObservable;
  4 +import android.database.DataSetObserver;
  5 +import android.view.View;
  6 +import android.view.ViewGroup;
  7 +
  8 +/**
  9 + * created by hanyayun
  10 + * on 2020/2/13
  11 + */
  12 +public abstract class BaseAutoGridAdapter<VH extends BaseAutoGridHolder> {
  13 +// 被观察者,用来注册观察者
  14 +private final DataSetObservable mDataSetObservable = new DataSetObservable();
  15 +
  16 +/**
  17 + * 创建 ViewHolder
  18 + */
  19 +public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
  20 +
  21 +/**
  22 + * 绑定 item 的 ViewHolder
  23 + */
  24 +public abstract void onBindViewHolder(VH holder, int position);
  25 +
  26 +/**
  27 + * 获取 item 的数量
  28 + */
  29 +public abstract int getItemCount();
  30 +
  31 +public int getItemViewType(int position) {
  32 + return 0;
  33 + }
  34 +
  35 +public View getView(int position, View convertView, ViewGroup parent) {
  36 + int viewType = getItemViewType(position);
  37 + VH holder = null;
  38 + if (convertView == null) {
  39 + holder = onCreateViewHolder(parent, viewType);
  40 + convertView = holder.getConvertView();
  41 + convertView.setTag(holder);
  42 + } else {
  43 + holder = (VH) convertView.getTag();
  44 + }
  45 + holder.setViewType(viewType);
  46 + onBindViewHolder(holder, position);
  47 + return convertView;
  48 + }
  49 +
  50 +
  51 +/**
  52 + * 注册观察者
  53 + *
  54 + * @param observer
  55 + */
  56 +public void registerDataSetObserver(DataSetObserver observer) {
  57 + mDataSetObservable.registerObserver(observer);
  58 + }
  59 +
  60 +/**
  61 + * 删除已经注册过的观察者
  62 + *
  63 + * @param observer
  64 + */
  65 +public void unregisterDataSetObserver(DataSetObserver observer) {
  66 + mDataSetObservable.unregisterObserver(observer);
  67 + }
  68 +
  69 +/**
  70 + * 通知刷新
  71 + */
  72 +public void notifyDataSetChanged() {
  73 + mDataSetObservable.notifyChanged();
  74 + }
  75 + }
core/imageload/src/main/java/com/cnlive/core/gridview/adapter/BaseAutoGridHolder.java 0 → 100644
  1 +package com.cnlive.core.gridview.adapter;
  2 +
  3 +import android.view.View;
  4 +import android.widget.ImageView;
  5 +import android.widget.TextView;
  6 +
  7 +import androidx.annotation.IdRes;
  8 +
  9 +/**
  10 + * created by hanyayun
  11 + * on 2020/2/13
  12 + */
  13 +public class BaseAutoGridHolder {
  14 + private View convertView;
  15 + private int mViewType;
  16 +
  17 + public BaseAutoGridHolder(final View convertView) {
  18 + this.convertView = convertView;
  19 + }
  20 +
  21 + public View getConvertView() {
  22 + return convertView;
  23 + }
  24 +
  25 + public <T extends View> T findViewById(@IdRes int viewId) {
  26 + T view = (T) convertView.findViewById(viewId);
  27 + return view;
  28 + }
  29 +
  30 + public ImageView getImageView(@IdRes int viewId) {
  31 + return findViewById(viewId);
  32 + }
  33 +
  34 + public TextView getTextView(@IdRes int viewId) {
  35 + return findViewById(viewId);
  36 + }
  37 +
  38 + public int getViewType() {
  39 + return mViewType;
  40 + }
  41 +
  42 + public void setViewType(int viewType) {
  43 + this.mViewType = viewType;
  44 + }
  45 +}
core/imageload/src/main/java/com/cnlive/core/gridview/adapter/QuickAutoGridAdapter.java 0 → 100644
  1 +package com.cnlive.core.gridview.adapter;
  2 +
  3 +import android.util.SparseIntArray;
  4 +import android.view.LayoutInflater;
  5 +import android.view.View;
  6 +import android.view.ViewGroup;
  7 +
  8 +import java.lang.reflect.Constructor;
  9 +import java.lang.reflect.InvocationTargetException;
  10 +import java.lang.reflect.Modifier;
  11 +import java.lang.reflect.ParameterizedType;
  12 +import java.lang.reflect.Type;
  13 +import java.util.List;
  14 +
  15 +import androidx.annotation.LayoutRes;
  16 +
  17 +/**
  18 + * created by hanyayun
  19 + * on 2020/2/13
  20 + */
  21 +public abstract class QuickAutoGridAdapter<T, VH extends BaseAutoGridHolder> extends BaseAutoGridAdapter<VH> {
  22 + private static final int LAYOUT_NOT_FOUND = -404;
  23 +
  24 + private LayoutInflater mLayoutInflater;
  25 + private SparseIntArray mLayoutTypes;
  26 + protected List<T> mData;
  27 +
  28 + public QuickAutoGridAdapter() {
  29 +
  30 + }
  31 +
  32 + public void setData(List<T> list) {
  33 + this.mData = list;
  34 + }
  35 +
  36 + public List<T> getData() {
  37 + return mData;
  38 + }
  39 +
  40 + public void updateData(List<T> list) {
  41 + mData = list;
  42 + notifyDataSetChanged();
  43 + }
  44 +
  45 + protected void addItemType(int type, @LayoutRes int layoutId) {
  46 + if (mLayoutTypes == null) {
  47 + mLayoutTypes = new SparseIntArray();
  48 + }
  49 + mLayoutTypes.put(type, layoutId);
  50 + }
  51 +
  52 + @Override
  53 + public int getItemViewType(int position) {
  54 + return onHandleViewType(position);
  55 + }
  56 +
  57 + @Override
  58 + public VH onCreateViewHolder(ViewGroup parent, int viewType) {
  59 + if (mLayoutInflater == null) mLayoutInflater = LayoutInflater.from(parent.getContext());
  60 + View convertView = getItemView(getLayoutId(viewType), parent);
  61 + VH holder = createBaseViewHolder(convertView);
  62 + return holder;
  63 + }
  64 +
  65 + @Override
  66 + public void onBindViewHolder(VH holder, int position) {
  67 + onHandleViewHolder(holder, position, mData.get(position));
  68 + }
  69 +
  70 + @Override
  71 + public int getItemCount() {
  72 + return mData != null ? mData.size() : 0;
  73 + }
  74 +
  75 + public abstract int onHandleViewType(int position);
  76 +
  77 + public abstract void onHandleViewHolder(VH holder, int position, T item);
  78 +
  79 + protected View getItemView(int layoutResId, ViewGroup parent) {
  80 + if (layoutResId != LAYOUT_NOT_FOUND) {
  81 + return mLayoutInflater.inflate(layoutResId, parent, false);
  82 + }
  83 + return null;
  84 + }
  85 +
  86 + private int getLayoutId(int vieType) {
  87 + return mLayoutTypes.get(vieType, LAYOUT_NOT_FOUND);
  88 + }
  89 +
  90 + protected VH createBaseViewHolder(View view) {
  91 + Class temp = getClass();
  92 + Class z = null;
  93 + while (z == null && null != temp) {
  94 + z = getInstancedGenericKClass(temp);
  95 + temp = temp.getSuperclass();
  96 + }
  97 + VH k;
  98 + // 泛型擦除会导致 z 为 null
  99 + if (z == null) {
  100 + k = (VH) new BaseAutoGridHolder(view);
  101 + } else {
  102 + k = createGenericKInstance(z, view);
  103 + }
  104 + return k != null ? k : (VH) new BaseAutoGridHolder(view);
  105 + }
  106 +
  107 + @SuppressWarnings("unchecked")
  108 + private VH createGenericKInstance(Class z, View view) {
  109 + try {
  110 + Constructor constructor;
  111 + // inner and unstatic class
  112 + if (z.isMemberClass() && !Modifier.isStatic(z.getModifiers())) {
  113 + constructor = z.getDeclaredConstructor(getClass(), View.class);
  114 + constructor.setAccessible(true);
  115 + return (VH) constructor.newInstance(this, view);
  116 + } else {
  117 + constructor = z.getDeclaredConstructor(View.class);
  118 + constructor.setAccessible(true);
  119 + return (VH) constructor.newInstance(view);
  120 + }
  121 + } catch (NoSuchMethodException e) {
  122 + e.printStackTrace();
  123 + } catch (IllegalAccessException e) {
  124 + e.printStackTrace();
  125 + } catch (InstantiationException e) {
  126 + e.printStackTrace();
  127 + } catch (InvocationTargetException e) {
  128 + e.printStackTrace();
  129 + }
  130 + return null;
  131 + }
  132 +
  133 + private Class getInstancedGenericKClass(Class z) {
  134 + Type type = z.getGenericSuperclass();
  135 + if (type instanceof ParameterizedType) {
  136 + Type[] types = ((ParameterizedType) type).getActualTypeArguments();
  137 + for (Type temp : types) {
  138 + if (temp instanceof Class) {
  139 + Class tempClass = (Class) temp;
  140 + if (BaseAutoGridHolder.class.isAssignableFrom(tempClass)) {
  141 + return tempClass;
  142 + }
  143 + } else if (temp instanceof ParameterizedType) {
  144 + Type rawType = ((ParameterizedType) temp).getRawType();
  145 + if (rawType instanceof Class && BaseAutoGridHolder.class.isAssignableFrom((Class<?>) rawType)) {
  146 + return (Class<?>) rawType;
  147 + }
  148 + }
  149 + }
  150 + }
  151 + return null;
  152 + }
  153 +}
core/imageload/src/main/java/com/cnlive/core/gridview/adapter/SimpleAutoGridAdapter.java 0 → 100644
  1 +package com.cnlive.core.gridview.adapter;
  2 +
  3 +import android.widget.ImageView;
  4 +
  5 +import com.cnlive.core.gridview.AutoGridMode;
  6 +import com.cnlive.core.imageload.R;
  7 +
  8 +import java.util.List;
  9 +
  10 +/**
  11 + * created by hanyayun
  12 + * on 2020/2/13
  13 + */
  14 +public class SimpleAutoGridAdapter<T, VH extends BaseAutoGridHolder> extends QuickAutoGridAdapter<T, VH> {
  15 + // item 类型
  16 + private final int ITEM_TYPE_SINGLE = 0;
  17 + private final int ITEM_TYPE_NORMAL = 1;
  18 +
  19 + private int mGridMode;
  20 + private ImageLoader mImageLoader;
  21 +
  22 + public SimpleAutoGridAdapter() {
  23 + init();
  24 + }
  25 +
  26 + public SimpleAutoGridAdapter(List<T> list) {
  27 + setData(list);
  28 + init();
  29 + }
  30 +
  31 + private void init() {
  32 + addItemType(ITEM_TYPE_SINGLE, R.layout.auto_grid_item_simple_pic_single);
  33 + addItemType(ITEM_TYPE_NORMAL, R.layout.auto_grid_item_simple_pic);
  34 + mGridMode = AutoGridMode.GRID_NINE;
  35 + }
  36 +
  37 + public void setMode(@AutoGridMode int mode) {
  38 + this.mGridMode = mode;
  39 + }
  40 +
  41 + public void setImageLoader(ImageLoader loader) {
  42 + this.mImageLoader = loader;
  43 + }
  44 +
  45 + @Override
  46 + public int onHandleViewType(int position) {
  47 + int viewType;
  48 + if (mGridMode == AutoGridMode.GRID_NINE) {
  49 + if (getItemCount() == 1) {
  50 + viewType = ITEM_TYPE_SINGLE;
  51 + } else {
  52 + viewType = ITEM_TYPE_NORMAL;
  53 + }
  54 + } else {
  55 + viewType = ITEM_TYPE_NORMAL;
  56 + }
  57 + return viewType;
  58 + }
  59 +
  60 + @Override
  61 + public void onHandleViewHolder(VH holder, int position, T item) {
  62 + if (mImageLoader != null) {
  63 + mImageLoader.onLoadImage(position, item, holder.getImageView(R.id.iv_auto_grid_item_simple_pic));
  64 + }
  65 + }
  66 +
  67 + public interface ImageLoader<T> {
  68 + /**
  69 + * 加载图片
  70 + */
  71 + void onLoadImage(int position, T item, ImageView imageView);
  72 + }
  73 +}
core/imageload/src/main/java/com/cnlive/core/gridview/model/SizeHelper.java 0 → 100644
  1 +package com.cnlive.core.gridview.model;
  2 +
  3 +import com.cnlive.core.gridview.AutoGridMode;
  4 +import com.cnlive.core.gridview.AutoGridView;
  5 +
  6 +/**
  7 + * 网格数据计算辅助类
  8 + * created by hanyayun
  9 + * on 2020/2/13
  10 + */
  11 +public class SizeHelper {
  12 + /**
  13 + * 计算 item 和 parent 的宽高
  14 + *
  15 + * @param param
  16 + * @return
  17 + */
  18 + public SizeInfo calculateSize(SizeParam param) {
  19 + if (param != null) {
  20 + float childWidth, childHeight;
  21 + float parentWidth, parentHeight;
  22 + int childRow, childColumn;
  23 +
  24 + int parentRow = param.getRow();
  25 + int parentColumn = param.getColumn();
  26 + float parentMaxWidth = param.getMaxWidth();
  27 + int totalCount = param.getItemCount();
  28 + float totalHorizontalSpace = (parentColumn - 1) * param.getHorizontalSpace();
  29 + childWidth = (parentMaxWidth - totalHorizontalSpace) / parentColumn;
  30 + childHeight = param.getItemHeight() != AutoGridView.DEF_ITEM_HEIGHT ? param.getItemHeight() : childWidth;
  31 + // 判断当前网格是九宫格模式还是普通模式
  32 + // 当前模式为九宫格模式时
  33 + if (param.getMode() == AutoGridMode.GRID_NINE) {
  34 + // 只有一个 item 时
  35 + if (totalCount == 1) {
  36 + float widthPer = param.getSingleWidthPer();
  37 + float heightPer = param.getSingleHeightPer();
  38 + childRow = 1;
  39 + childColumn = 1;
  40 + if (widthPer <= 0) {
  41 + childWidth = 0;
  42 + } else {
  43 + if (widthPer > 1) {
  44 + widthPer = 1;
  45 + }
  46 + childWidth = widthPer * parentMaxWidth;
  47 + }
  48 + if (heightPer <= 0) {
  49 + childHeight = 0;
  50 + } else {
  51 + childHeight = heightPer * parentMaxWidth;
  52 + }
  53 + parentWidth = childWidth;
  54 + parentHeight = childHeight;
  55 + return new SizeInfo(childRow, childColumn, childWidth, childHeight, parentWidth, parentHeight);
  56 + } else {
  57 + // 如果 item 的个数大于可以显示的最大个数
  58 + if (parentRow * parentColumn < totalCount) {
  59 + childRow = parentRow;
  60 + childColumn = parentColumn;
  61 + } else {
  62 + // 判断 item 的个数是否可以开平方(即判断是否可以将 itemView 拼成正方形放置)
  63 + int temp = (int) Math.sqrt(totalCount);
  64 + if (temp * temp == totalCount) {
  65 + // 如果 item 的个数不满一行,则不做正方形放置,否则做正方形放置
  66 + if (totalCount <= parentColumn) {
  67 + childRow = 1;
  68 + childColumn = totalCount;
  69 + } else {
  70 + childRow = temp;
  71 + childColumn = temp;
  72 + }
  73 + } else {
  74 + childRow = totalCount / parentColumn + (totalCount % parentColumn == 0 ? 0 : 1);
  75 + childColumn = param.getColumn();
  76 + }
  77 + }
  78 + }
  79 + }
  80 + // 当前模式为普通网格模式时
  81 + else {
  82 + if (parentRow * parentColumn < totalCount) {
  83 + childRow = parentRow;
  84 + childColumn = parentColumn;
  85 + } else {
  86 + childRow = totalCount / parentColumn + (totalCount % parentColumn == 0 ? 0 : 1);
  87 + childColumn = parentColumn;
  88 + }
  89 + }
  90 + parentWidth = childColumn * childWidth + (childColumn - 1) * param.getHorizontalSpace();
  91 + parentHeight = childRow * childHeight + (childRow - 1) * param.getVerticalSpace();
  92 + // 当只有一个 child 的时候,parent 的总宽度与 item 的宽度一致
  93 + if (totalCount == 1) {
  94 + parentWidth = childWidth;
  95 + }
  96 + return new SizeInfo(childRow, childColumn, childWidth, childHeight, parentWidth, parentHeight);
  97 + }
  98 + return null;
  99 + }
  100 +
  101 + /**
  102 + * 找到 item 在网格中的位置
  103 + *
  104 + * @param bean
  105 + * @param index
  106 + * @return
  107 + */
  108 + public int[] findPosition(SizeInfo bean, int index) {
  109 + if (bean == null) {
  110 + return null;
  111 + }
  112 + int[] position = new int[2];
  113 + position[0] = index / bean.getChildColumn();
  114 + position[1] = index - position[0] * bean.getChildColumn();
  115 + return position;
  116 + }
  117 +}
core/imageload/src/main/java/com/cnlive/core/gridview/model/SizeInfo.java 0 → 100644
  1 +package com.cnlive.core.gridview.model;
  2 +
  3 +/**
  4 + * created by hanyayun
  5 + * on 2020/2/13
  6 + */
  7 +public class SizeInfo {
  8 + private int childRow;
  9 + private int childColumn;
  10 + private float childWidth;
  11 + private float childHeight;
  12 + private float parentWidth;
  13 + private float parentHeight;
  14 +
  15 + public SizeInfo() {
  16 + super();
  17 + }
  18 +
  19 + public SizeInfo(int childRow, int childColumn, float childWidth, float childHeight, float parentWidth, float parentHeight) {
  20 + this.childRow = childRow;
  21 + this.childColumn = childColumn;
  22 + this.childWidth = childWidth;
  23 + this.childHeight = childHeight;
  24 + this.parentWidth = parentWidth;
  25 + this.parentHeight = parentHeight;
  26 + }
  27 +
  28 + public int getChildRow() {
  29 + return childRow;
  30 + }
  31 +
  32 + public void setChildRow(int childRow) {
  33 + this.childRow = childRow;
  34 + }
  35 +
  36 + public int getChildColumn() {
  37 + return childColumn;
  38 + }
  39 +
  40 + public void setChildColumn(int childColumn) {
  41 + this.childColumn = childColumn;
  42 + }
  43 +
  44 + public float getChildWidth() {
  45 + return childWidth;
  46 + }
  47 +
  48 + public void setChildWidth(float childWidth) {
  49 + this.childWidth = childWidth;
  50 + }
  51 +
  52 + public float getChildHeight() {
  53 + return childHeight;
  54 + }
  55 +
  56 + public void setChildHeight(float childHeight) {
  57 + this.childHeight = childHeight;
  58 + }
  59 +
  60 + public float getParentWidth() {
  61 + return parentWidth;
  62 + }
  63 +
  64 + public void setParentWidth(float parentWidth) {
  65 + this.parentWidth = parentWidth;
  66 + }
  67 +
  68 + public float getParentHeight() {
  69 + return parentHeight;
  70 + }
  71 +
  72 + public void setParentHeight(float parentHeight) {
  73 + this.parentHeight = parentHeight;
  74 + }
  75 +}
0 \ No newline at end of file 76 \ No newline at end of file
core/imageload/src/main/java/com/cnlive/core/gridview/model/SizeParam.java 0 → 100644
  1 +package com.cnlive.core.gridview.model;
  2 +
  3 +/**
  4 + * created by hanyayun
  5 + * on 2020/2/13
  6 + */
  7 +public class SizeParam {
  8 + private int mode;
  9 + private int row;
  10 + private int column;
  11 + private int maxWidth;
  12 + private int itemCount;
  13 + private float itemWidth;
  14 + private float itemHeight;
  15 + private float horizontalSpace;
  16 + private float verticalSpace;
  17 + private float singleWidthPer;
  18 + private float singleHeightPer;
  19 +
  20 + public SizeParam() {
  21 + }
  22 +
  23 + public SizeParam(int mode, int row, int column, int maxWidth, int itemCount,
  24 + float itemWidth, float itemHeight, float horizontalSpace, float verticalSpace,
  25 + float singleWidthPer, float singleHeightPer) {
  26 + this.mode = mode;
  27 + this.row = row;
  28 + this.column = column;
  29 + this.maxWidth = maxWidth;
  30 + this.itemCount = itemCount;
  31 + this.itemWidth = itemWidth;
  32 + this.itemHeight = itemHeight;
  33 + this.horizontalSpace = horizontalSpace;
  34 + this.verticalSpace = verticalSpace;
  35 + this.singleWidthPer = singleWidthPer;
  36 + this.singleHeightPer = singleHeightPer;
  37 + }
  38 +
  39 + public int getMode() {
  40 + return mode;
  41 + }
  42 +
  43 + public SizeParam setMode(int mode) {
  44 + this.mode = mode;
  45 + return this;
  46 + }
  47 +
  48 + public int getRow() {
  49 + return row;
  50 + }
  51 +
  52 + public SizeParam setRow(int row) {
  53 + this.row = row;
  54 + return this;
  55 + }
  56 +
  57 + public int getColumn() {
  58 + return column;
  59 + }
  60 +
  61 + public SizeParam setColumn(int column) {
  62 + this.column = column;
  63 + return this;
  64 + }
  65 +
  66 + public int getMaxWidth() {
  67 + return maxWidth;
  68 + }
  69 +
  70 + public SizeParam setMaxWidth(int maxWidth) {
  71 + this.maxWidth = maxWidth;
  72 + return this;
  73 + }
  74 +
  75 + public int getItemCount() {
  76 + return itemCount;
  77 + }
  78 +
  79 + public SizeParam setItemCount(int itemCount) {
  80 + this.itemCount = itemCount;
  81 + return this;
  82 + }
  83 +
  84 + public float getItemWidth() {
  85 + return itemWidth;
  86 + }
  87 +
  88 + public SizeParam setItemWidth(float itemWidth) {
  89 + this.itemWidth = itemWidth;
  90 + return this;
  91 + }
  92 +
  93 + public float getItemHeight() {
  94 + return itemHeight;
  95 + }
  96 +
  97 + public SizeParam setItemHeight(float itemHeight) {
  98 + this.itemHeight = itemHeight;
  99 + return this;
  100 + }
  101 +
  102 + public float getHorizontalSpace() {
  103 + return horizontalSpace;
  104 + }
  105 +
  106 + public SizeParam setHorizontalSpace(float horizontalSpace) {
  107 + this.horizontalSpace = horizontalSpace;
  108 + return this;
  109 + }
  110 +
  111 + public float getVerticalSpace() {
  112 + return verticalSpace;
  113 + }
  114 +
  115 + public SizeParam setVerticalSpace(float verticalSpace) {
  116 + this.verticalSpace = verticalSpace;
  117 + return this;
  118 + }
  119 +
  120 + public float getSingleWidthPer() {
  121 + return singleWidthPer;
  122 + }
  123 +
  124 + public SizeParam setSingleWidthPer(float singleWidthPer) {
  125 + this.singleWidthPer = singleWidthPer;
  126 + return this;
  127 + }
  128 +
  129 + public float getSingleHeightPer() {
  130 + return singleHeightPer;
  131 + }
  132 +
  133 + public SizeParam setSingleHeightPer(float singleHeightPer) {
  134 + this.singleHeightPer = singleHeightPer;
  135 + return this;
  136 + }
  137 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/ImageDrawee.java 0 → 100644
  1 +package com.cnlive.core.imagepreview;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.Bitmap;
  5 +import android.graphics.drawable.Drawable;
  6 +import android.util.Log;
  7 +import android.widget.FrameLayout;
  8 +import android.widget.ImageView;
  9 +
  10 +import com.cnlive.core.imagepreview.indexui.ProgressUI;
  11 +
  12 +import androidx.annotation.NonNull;
  13 +import uk.co.senab.photoview.PhotoView;
  14 +
  15 +/**
  16 + * created by hanyayun
  17 + * on 2020/1/20
  18 + */
  19 +public class ImageDrawee extends FrameLayout {
  20 + private PhotoView imageView;
  21 + private ProgressUI progressUI;
  22 +
  23 + public ImageDrawee(@NonNull Context context) {
  24 + super(context);
  25 + init();
  26 + }
  27 +
  28 + private void init() {
  29 + // 添加 imageView
  30 + imageView = new PhotoView(getContext());
  31 + addView(imageView);
  32 + }
  33 +
  34 + public void setProgressUI(ProgressUI progressUI) {
  35 + this.progressUI = progressUI;
  36 + if (progressUI != null) {
  37 + progressUI.init(this);
  38 + }
  39 + }
  40 +
  41 + /**
  42 + * 更新加载进度
  43 + */
  44 + public void handleProgress(float progress) {
  45 + if (progressUI != null && progressUI.getProgressView() != null) {
  46 + if (progress == 0) {
  47 + progressUI.start();
  48 + } else if (progress == 1f) {
  49 + progressUI.stop();
  50 + }
  51 + progressUI.handleProgress(progress);
  52 + }
  53 + }
  54 +
  55 + public void hideProgressUI() {
  56 + if (progressUI != null && progressUI.getProgressView() != null
  57 + && progressUI.getProgressView().getVisibility() == VISIBLE) {
  58 + progressUI.stop();
  59 + }
  60 + }
  61 +
  62 + /**
  63 + * 释放 imageView 占据的内存
  64 + * <p>
  65 + * Bitmap 的存储分为两部分,一部分是 Bitmap 的数据,一部分是 Bitmap 的引用。
  66 + * 在 Android2.3 时代,Bitmap 的引用是放在堆中的,而 Bitmap 的数据部分是放在栈中的,需要用户调用 recycle 方法手动进行内存回收;
  67 + * 在 Android2.3 之后,整个 Bitmap(包括数据和引用)都放在了堆中,整个 Bitmap 的回收就全部交给GC了,不用在手动调用 recycle 方法回收内存。
  68 + */
  69 + public void recycle() {
  70 +// Drawable drawable = imageView.getDrawable();
  71 +// if (drawable != null && drawable instanceof BitmapDrawable) {
  72 +// Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
  73 +// if (bitmap != null && !bitmap.isRecycled()) {
  74 +// /**
  75 +// * 当如果图片加载框架设置了缓存且 bitmap 已经被回收,
  76 +// * 但是 canvas 在 draw 时,继续使用被回收的 bitmap,会抛出异常:
  77 +// * a BitmapDrawable: Canvas: trying to use a recycled bitmap.
  78 +// * 故此处不使用 bitmap.recycle() 方法(或者图片加载框架去除缓存设置)。
  79 +// */
  80 +// bitmap.recycle();
  81 +// bitmap = null;
  82 +// }
  83 +// }
  84 + // 调用 setImageDrawable(null) 方法,然后 GC 会完成图片的回收
  85 + imageView.setImageDrawable(null);
  86 + // 手动调用 GC(但是 GC 并不一定是马上执行的,只能说是加速 GC 回收)
  87 +// System.gc();
  88 + }
  89 +
  90 + public ImageView getImageView() {
  91 + return imageView;
  92 + }
  93 +
  94 + public void setImage(Object obj) {
  95 + if (obj == null) {
  96 + return;
  97 + }
  98 + if (obj instanceof Drawable) {
  99 + imageView.setImageDrawable((Drawable) obj);
  100 + } else if (obj instanceof Bitmap) {
  101 + imageView.setImageBitmap((Bitmap) obj);
  102 + } else if (obj instanceof Integer) {
  103 + imageView.setImageResource((Integer) obj);
  104 + } else {
  105 + Log.e("ImageDrawee", "Unable to identify picture resources.");
  106 + }
  107 + }
  108 +
  109 + public float getScale() {
  110 + return imageView.getScale();
  111 + }
  112 +
  113 + public void setScale(float scale) {
  114 + imageView.setScale(scale);
  115 + }
  116 +
  117 + public float getMaxScale() {
  118 + return imageView.getMaximumScale();
  119 + }
  120 +
  121 + public void setMaxScale(float scale) {
  122 + this.imageView.setMaximumScale(scale);
  123 + }
  124 +
  125 + public float getMinScale() {
  126 + return imageView.getMinimumScale();
  127 + }
  128 +
  129 + public void setMinScale(float scale) {
  130 + imageView.setMinimumScale(scale);
  131 + }
  132 +}
0 \ No newline at end of file 133 \ No newline at end of file
core/imageload/src/main/java/com/cnlive/core/imagepreview/ImagePreView.java 0 → 100644
  1 +package com.cnlive.core.imagepreview;
  2 +
  3 +import android.content.Context;
  4 +import android.content.res.TypedArray;
  5 +import android.graphics.Color;
  6 +import android.graphics.drawable.Drawable;
  7 +import android.util.AttributeSet;
  8 +import android.util.Log;
  9 +import android.view.KeyEvent;
  10 +import android.view.MotionEvent;
  11 +import android.view.View;
  12 +import android.view.ViewGroup;
  13 +import android.widget.FrameLayout;
  14 +
  15 +import com.cnlive.core.imageload.R;
  16 +import com.cnlive.core.imagepreview.dragger.DragHandler;
  17 +import com.cnlive.core.imagepreview.dragger.DragMode;
  18 +import com.cnlive.core.imagepreview.dragger.DragStatus;
  19 +import com.cnlive.core.imagepreview.indexui.DefaultIndexUI;
  20 +import com.cnlive.core.imagepreview.indexui.DefaultProgressUI;
  21 +import com.cnlive.core.imagepreview.indexui.IndexUI;
  22 +import com.cnlive.core.imagepreview.indexui.ProgressUI;
  23 +import com.cnlive.core.imagepreview.listener.OnBrowseStatusListener;
  24 +import com.cnlive.core.imagepreview.listener.OnDragStatusListener;
  25 +import com.cnlive.core.imagepreview.listener.OnItemChangedListener;
  26 +import com.cnlive.core.imagepreview.listener.OnItemClickListener;
  27 +import com.cnlive.core.imagepreview.listener.OnItemLongPressListener;
  28 +import com.cnlive.core.imagepreview.viewpager.ImagePagerAdapter;
  29 +import com.cnlive.core.imagepreview.viewpager.ImageViewPager;
  30 +
  31 +import java.util.ArrayList;
  32 +import java.util.List;
  33 +
  34 +import androidx.annotation.IntRange;
  35 +import androidx.annotation.NonNull;
  36 +import androidx.viewpager.widget.ViewPager;
  37 +
  38 +/**
  39 + * created by hanyayun
  40 + * on 2020/1/21
  41 + */
  42 +public class ImagePreView extends FrameLayout implements ViewPager.OnPageChangeListener {
  43 + private final String TAG = getClass().getSimpleName();
  44 +
  45 + // 索引视图
  46 + private IndexUI indexUI;
  47 + // 加载进度视图
  48 + private ProgressUI progressUI;
  49 + private ImageViewPager viewPager;
  50 + private ImagePagerAdapter mAdapter;
  51 + private LoadImage mLoader;
  52 + private DragHandler mDragHandler;
  53 +
  54 + // 是否执行进场动画
  55 + private boolean playEnterAnim = true;
  56 + // 是否执行退场动画
  57 + private boolean playExitAnim = true;
  58 + // 动画执行时间
  59 + private long mDuration = 300;
  60 + // 是否显示图片索引
  61 + private boolean showIndex = true;
  62 + // 是否可拖拽图片
  63 + private boolean draggable = true;
  64 + // 拖拽模式
  65 + private int mDragMode = DragMode.MODE_AGILE;
  66 +
  67 + private List<ViewData> mSourceList;
  68 + // ImageViewer 是否会占据 StatusBar 的空间
  69 + private boolean overlayStatusBar = false;
  70 + private float mMaxScale;
  71 + private float mMinScale;
  72 +
  73 + // 上一次的触摸点坐标
  74 + private float mLastX, mLastY;
  75 + // 是否正在进行拖拽
  76 + private boolean isDragging;
  77 + // 是否有动画正在执行
  78 + private boolean hasAnimRunning;
  79 + // 是否已经执行了进场动画
  80 + private boolean hasPlayEnterAnim = false;
  81 + // ImageViewer 的当前状态
  82 + private int mViewStatus = ViewerStatus.STATUS_SILENCE;
  83 + // 缓存 item,用于复用
  84 + private ArrayList<ImageDrawee> mViewBox = new ArrayList<ImageDrawee>();
  85 +
  86 + private OnItemClickListener mItemClickListener;
  87 + private OnItemLongPressListener mItemLongPressListener;
  88 + private OnItemChangedListener mItemChangedListener;
  89 + private OnDragStatusListener mDragStatusListener;
  90 + private OnBrowseStatusListener mBrowseStatusListener;
  91 +
  92 + public ImagePreView(@NonNull Context context) {
  93 + super(context);
  94 + init(context, null);
  95 + }
  96 +
  97 + public ImagePreView(Context context, AttributeSet attrs) {
  98 + super(context, attrs);
  99 + init(context, attrs);
  100 + }
  101 +
  102 + public ImagePreView(Context context, AttributeSet attrs, int defStyleAttr) {
  103 + super(context, attrs, defStyleAttr);
  104 + init(context, attrs);
  105 + }
  106 +
  107 + private void init(Context context, AttributeSet attrs) {
  108 + if (attrs != null) {
  109 + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ImagePreView);
  110 + if (a != null) {
  111 + playEnterAnim = a.getBoolean(R.styleable.ImagePreView_ivr_playEnterAnim, true);
  112 + playExitAnim = a.getBoolean(R.styleable.ImagePreView_ivr_playExitAnim, true);
  113 + mDuration = a.getInteger(R.styleable.ImagePreView_ivr_duration, 300);
  114 + showIndex = a.getBoolean(R.styleable.ImagePreView_ivr_showIndex, true);
  115 + draggable = a.getBoolean(R.styleable.ImagePreView_ivr_draggable, true);
  116 + mDragMode = a.getInteger(R.styleable.ImagePreView_ivr_dragMode, DragMode.MODE_AGILE);
  117 + a.recycle();
  118 + }
  119 + }
  120 + initView();
  121 + }
  122 +
  123 + private void initView() {
  124 + if (getBackground() == null) {
  125 + setBackgroundColor(Color.BLACK);
  126 + }
  127 +
  128 + // 添加 ViewPager
  129 + viewPager = new ImageViewPager(getContext());
  130 + viewPager.setOffscreenPageLimit(1);
  131 + viewPager.addOnPageChangeListener(this);
  132 + addView(viewPager, new FrameLayout.LayoutParams(
  133 + FrameLayout.LayoutParams.MATCH_PARENT,
  134 + FrameLayout.LayoutParams.MATCH_PARENT));
  135 +
  136 + setVisibility(View.INVISIBLE);
  137 +
  138 + progressUI = new DefaultProgressUI();
  139 + }
  140 +
  141 +
  142 + @Override
  143 + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
  144 +
  145 + }
  146 +
  147 + @Override
  148 + public void onPageSelected(int position) {
  149 + if (showIndex && indexUI != null && mSourceList != null) {
  150 + indexUI.handleItemChanged(position, mSourceList.size());
  151 + }
  152 + if (mItemChangedListener != null) {
  153 + mItemChangedListener.onItemChanged(position, getCurrentItem());
  154 + }
  155 + }
  156 +
  157 + @Override
  158 + public void onPageScrollStateChanged(int state) {
  159 +
  160 + }
  161 +
  162 + public ImagePreView imageData(@NonNull List list) {
  163 + if (mSourceList == null) {
  164 + mSourceList = new ArrayList<ViewData>();
  165 + } else {
  166 + mSourceList.clear();
  167 + }
  168 + for (int i = 0, len = list.size(); i < len; i++) {
  169 + ViewData vd = new ViewData(list.get(i));
  170 + mSourceList.add(vd);
  171 + }
  172 + return this;
  173 + }
  174 +
  175 + public ImagePreView overlayStatusBar(boolean overlayStatusBar) {
  176 + this.overlayStatusBar = overlayStatusBar;
  177 + return this;
  178 + }
  179 +
  180 + public ImagePreView bindViewGroup(@NonNull ViewGroup viewGroup) {
  181 + for (int i = 0, len = viewGroup.getChildCount(); i < len; i++) {
  182 + View child = viewGroup.getChildAt(i);
  183 + int[] location = new int[2];
  184 + // 获取 child 在屏幕中的坐标,其中 getLocationOnScreen() 方法获取的 y 轴坐标包含状态栏的高度
  185 + child.getLocationOnScreen(location);
  186 + mSourceList.get(i).setTargetX(location[0]);
  187 + mSourceList.get(i).setTargetY(overlayStatusBar ? location[1] : location[1] - Utils.getStatusBarHeight(getContext()));
  188 + mSourceList.get(i).setTargetWidth(child.getMeasuredWidth());
  189 + mSourceList.get(i).setTargetHeight(child.getMeasuredHeight());
  190 + }
  191 + return this;
  192 + }
  193 +
  194 + public ImagePreView viewData(@NonNull List<ViewData> list) {
  195 + this.mSourceList = list;
  196 + return this;
  197 + }
  198 +
  199 + public ImagePreView imageLoader(@NonNull LoadImage loader) {
  200 + this.mLoader = loader;
  201 + return this;
  202 + }
  203 +
  204 + public ImagePreView playEnterAnim(boolean play) {
  205 + this.playEnterAnim = play;
  206 + return this;
  207 + }
  208 +
  209 + public ImagePreView playExitAnim(boolean play) {
  210 + this.playExitAnim = play;
  211 + return this;
  212 + }
  213 +
  214 + public ImagePreView duration(long duration) {
  215 + this.mDuration = duration;
  216 + return this;
  217 + }
  218 +
  219 + public ImagePreView showIndex(boolean showIndex) {
  220 + this.showIndex = showIndex;
  221 + return this;
  222 + }
  223 +
  224 + public ImagePreView loadIndexUI(@NonNull IndexUI indexUI) {
  225 + this.indexUI = indexUI;
  226 + return this;
  227 + }
  228 +
  229 + public ImagePreView loadProgressUI(@NonNull ProgressUI progressUI) {
  230 + this.progressUI = progressUI;
  231 + return this;
  232 + }
  233 +
  234 + public ImagePreView draggable(boolean draggable) {
  235 + this.draggable = draggable;
  236 + return this;
  237 + }
  238 +
  239 + public ImagePreView dragMode(int mode) {
  240 + this.mDragMode = mode;
  241 + return this;
  242 + }
  243 +
  244 + public ImagePreView setMaxScale(float scale) {
  245 + this.mMaxScale = scale;
  246 + return this;
  247 + }
  248 +
  249 + public ImagePreView setMinScale(float scale) {
  250 + this.mMinScale = scale;
  251 + return this;
  252 + }
  253 +
  254 + public ImagePreView setOnItemClickListener(OnItemClickListener listener) {
  255 + this.mItemClickListener = listener;
  256 + return this;
  257 + }
  258 +
  259 + public ImagePreView setOnItemLongPressListener(OnItemLongPressListener listener) {
  260 + this.mItemLongPressListener = listener;
  261 + return this;
  262 + }
  263 +
  264 + public ImagePreView setOnItemChangedListener(OnItemChangedListener listener) {
  265 + this.mItemChangedListener = listener;
  266 + return this;
  267 + }
  268 +
  269 + public ImagePreView setOnDragStatusListener(OnDragStatusListener listener) {
  270 + this.mDragStatusListener = listener;
  271 + return this;
  272 + }
  273 +
  274 + public ImagePreView setOnBrowseStatusListener(OnBrowseStatusListener listener) {
  275 + this.mBrowseStatusListener = listener;
  276 + return this;
  277 + }
  278 +
  279 + /**
  280 + * 开启浏览
  281 + *
  282 + * @param startPosition 开始位置,即点击的 ImageView 的位置
  283 + */
  284 + public void watch(@IntRange(from = 0) int startPosition) {
  285 + watch(startPosition, 0, 0, null);
  286 + }
  287 +
  288 + /**
  289 + * 开启浏览
  290 + *
  291 + * @param startPosition 开始位置,即点击的 ImageView 的位置
  292 + * @param callback 进场动画执行回调
  293 + */
  294 + public void watch(@IntRange(from = 0) int startPosition, ImageTransfer.OnTransCallback callback) {
  295 + watch(startPosition, 0, 0, callback);
  296 + }
  297 +
  298 + /**
  299 + * 开启浏览
  300 + *
  301 + * @param startPosition 开始位置,即点击的 ImageView 的位置
  302 + * @param startImageWidth 被点击的 ImageView 加载的资源图片的实际宽度
  303 + * @param startImageHeight 被点击的 ImageView 加载的资源图片的实际高度
  304 + */
  305 + public void watch(@IntRange(from = 0) int startPosition, int startImageWidth, int startImageHeight) {
  306 + watch(startPosition, startImageWidth, startImageHeight, null);
  307 + }
  308 +
  309 + /**
  310 + * 开启浏览
  311 + *
  312 + * @param startPosition 开始位置,即点击的 ImageView 的位置
  313 + * @param startImageWidth 被点击的 ImageView 加载的资源图片的实际宽度
  314 + * @param startImageHeight 被点击的 ImageView 加载的资源图片的实际高度
  315 + * @param callback 进场动画执行回调
  316 + */
  317 + public void watch(@IntRange(from = 0) final int startPosition, int startImageWidth, int startImageHeight, final ImageTransfer.OnTransCallback callback) {
  318 + if (mSourceList == null || startPosition >= mSourceList.size()) {
  319 + Log.e(TAG, "SourceList is null or StartPosition greater than or equal to the length of Sourcelist.");
  320 + return;
  321 + }
  322 + if (startImageWidth != 0 && startImageHeight != 0
  323 + && (mSourceList.get(startPosition).getImageWidth() == 0 ||
  324 + mSourceList.get(startPosition).getImageHeight() == 0)) {
  325 + mSourceList.get(startPosition).setImageWidth(startImageWidth);
  326 + mSourceList.get(startPosition).setImageHeight(startImageHeight);
  327 + }
  328 + viewPager.setScrollable(true);
  329 + mAdapter = new ImagePagerAdapter(mSourceList.size()) {
  330 + @NonNull
  331 + @Override
  332 + public Object instantiateItem(@NonNull ViewGroup container, int position) {
  333 + return ImagePreView.this.instantiateItem(container, position, startPosition, callback);
  334 + }
  335 + };
  336 + viewPager.setAdapter(mAdapter);
  337 + viewPager.setCurrentItem(startPosition);
  338 + setVisibility(VISIBLE);
  339 + if (!playEnterAnim) {
  340 + noteBrowseStatus(ViewerStatus.STATUS_WATCHING);
  341 + handleIndexUI(startPosition);
  342 + }
  343 + }
  344 +
  345 + /**
  346 + * 取消浏览
  347 + */
  348 + public void cancel() {
  349 + cancel(null);
  350 + }
  351 +
  352 + /**
  353 + * 取消浏览
  354 + *
  355 + * @param callback 退场动画执行回调
  356 + */
  357 + public void cancel(final ImageTransfer.OnTransCallback callback) {
  358 + if (indexUI != null) {
  359 + indexUI.hide();
  360 + }
  361 + if (playExitAnim) {
  362 + int position = getCurrentPosition();
  363 + new ImageTransfer(getWidth(), getHeight())
  364 + .with(getCurrentItem().getImageView())
  365 + .background(getBackground())
  366 + .duration(mDuration)
  367 + .loadExitData(mSourceList.get(position))
  368 + .callback(new ImageTransfer.OnTransCallback() {
  369 + @Override
  370 + public void onStart() {
  371 + noteBrowseStatus(ViewerStatus.STATUS_BEGIN_CLOSE);
  372 + if (callback != null) {
  373 + callback.onStart();
  374 + }
  375 + }
  376 +
  377 + @Override
  378 + public void onRunning(float progress) {
  379 + noteBrowseStatus(ViewerStatus.STATUS_CLOSING);
  380 + if (callback != null) {
  381 + callback.onRunning(progress);
  382 + }
  383 + }
  384 +
  385 + @Override
  386 + public void onEnd() {
  387 + noteBrowseStatus(ViewerStatus.STATUS_SILENCE);
  388 + if (callback != null) {
  389 + callback.onEnd();
  390 + }
  391 + shutComplete();
  392 + }
  393 + })
  394 + .play();
  395 + } else {
  396 + noteBrowseStatus(ViewerStatus.STATUS_SILENCE);
  397 + shutComplete();
  398 + }
  399 + }
  400 +
  401 + /**
  402 + * 实例化 item
  403 + */
  404 + private ImageDrawee instantiateItem(ViewGroup container, int position, final int startPosition, final ImageTransfer.OnTransCallback callback) {
  405 + ImageDrawee drawee = null;
  406 + if (mViewBox.size() > 0) {
  407 + for (ImageDrawee item : mViewBox) {
  408 + if (item.getParent() == null) {
  409 + drawee = item;
  410 + break;
  411 + }
  412 + }
  413 + }
  414 + if (drawee == null) {
  415 + drawee = new ImageDrawee(container.getContext());
  416 + drawee.setProgressUI(progressUI);
  417 + mViewBox.add(drawee);
  418 + }
  419 + container.addView(drawee);
  420 + configureItem(position, drawee);
  421 + if (playEnterAnim && !hasPlayEnterAnim && startPosition == position) {
  422 + hasPlayEnterAnim = true;
  423 + new ImageTransfer(getWidth(), getHeight())
  424 + .with(drawee.getImageView())
  425 + .loadEnterData(mSourceList.get(position))
  426 + .background(getBackground())
  427 + .duration(mDuration)
  428 + .callback(new ImageTransfer.OnTransCallback() {
  429 + @Override
  430 + public void onStart() {
  431 + noteBrowseStatus(ViewerStatus.STATUS_BEGIN_OPEN);
  432 + if (callback != null) {
  433 + callback.onStart();
  434 + }
  435 + }
  436 +
  437 + @Override
  438 + public void onRunning(float progress) {
  439 + noteBrowseStatus(ViewerStatus.STATUS_OPENING);
  440 + if (callback != null) {
  441 + callback.onRunning(progress);
  442 + }
  443 + }
  444 +
  445 + @Override
  446 + public void onEnd() {
  447 + handleIndexUI(startPosition);
  448 + noteBrowseStatus(ViewerStatus.STATUS_WATCHING);
  449 + if (callback != null) {
  450 + callback.onEnd();
  451 + }
  452 + }
  453 + })
  454 + .play();
  455 + }
  456 + return drawee;
  457 + }
  458 +
  459 + /**
  460 + * 配置 item
  461 + */
  462 + private void configureItem(final int position, final ImageDrawee drawee) {
  463 + drawee.setTag(position);
  464 + if (mMaxScale > 0) {
  465 + drawee.setMaxScale(mMaxScale);
  466 + }
  467 + if (mMinScale > 0) {
  468 + drawee.setMinScale(mMinScale);
  469 + }
  470 + mLoader.displayImage(mSourceList.get(position).getImageSrc(), drawee.getImageView(), new LoadImage.LoadCallback() {
  471 + @Override
  472 + public void onLoadStarted(Object placeholder) {
  473 + drawee.setImage(placeholder);
  474 + }
  475 +
  476 + @Override
  477 + public void onLoading(float progress) {
  478 + drawee.handleProgress(progress);
  479 + }
  480 +
  481 + @Override
  482 + public void onLoadSucceed(Object source) {
  483 + drawee.hideProgressUI();
  484 + drawee.setImage(source);
  485 + if (mSourceList.get(position).getImageWidth() == 0 ||
  486 + mSourceList.get(position).getImageHeight() == 0) {
  487 + Drawable drawable = drawee.getImageView().getDrawable();
  488 + if (drawable != null) {
  489 + mSourceList.get(position).setImageWidth(drawable.getIntrinsicWidth());
  490 + mSourceList.get(position).setImageHeight(drawable.getIntrinsicHeight());
  491 + }
  492 + }
  493 + }
  494 +
  495 + @Override
  496 + public void onLoadFailed(Object error) {
  497 + drawee.hideProgressUI();
  498 + drawee.setImage(error);
  499 + }
  500 + });
  501 + // 单击事件
  502 + drawee.getImageView().setOnClickListener(new View.OnClickListener() {
  503 + @Override
  504 + public void onClick(View v) {
  505 + if (!hasAnimRunning && mItemClickListener != null) {
  506 + final boolean result = mItemClickListener.onItemClick(position, drawee.getImageView());
  507 + // 判断是否消费了单击事件,如果消费了,则单击事件的后续方法不执行
  508 + if (result) {
  509 + return;
  510 + }
  511 + }
  512 + cancel();
  513 + }
  514 + });
  515 + // 长按事件
  516 + drawee.getImageView().setOnLongClickListener(new View.OnLongClickListener() {
  517 + @Override
  518 + public boolean onLongClick(View v) {
  519 + if (!hasAnimRunning && mItemLongPressListener != null) {
  520 + return mItemLongPressListener.onItemLongPress(position, drawee.getImageView());
  521 + }
  522 + return false;
  523 + }
  524 + });
  525 + }
  526 +
  527 + private void noteDragStatus(int status) {
  528 + switch (status) {
  529 + case DragStatus.STATUS_BEGIN_RESTORE:
  530 + case DragStatus.STATUS_BEGIN_EXIT:
  531 + hasAnimRunning = true;
  532 + break;
  533 + case DragStatus.STATUS_COMPLETE_RESTORE:
  534 + case DragStatus.STATUS_COMPLETE_EXIT:
  535 + hasAnimRunning = false;
  536 + break;
  537 + }
  538 + if (mDragStatusListener != null) {
  539 + mDragStatusListener.onDragStatusChanged(status);
  540 + }
  541 + }
  542 +
  543 + private void noteBrowseStatus(int status) {
  544 + mViewStatus = status;
  545 + switch (status) {
  546 + case ViewerStatus.STATUS_BEGIN_OPEN:
  547 + hasAnimRunning = true;
  548 + break;
  549 + case ViewerStatus.STATUS_BEGIN_CLOSE:
  550 + viewPager.setScrollable(false);
  551 + hasAnimRunning = true;
  552 + break;
  553 + case ViewerStatus.STATUS_WATCHING:
  554 + hasAnimRunning = false;
  555 + break;
  556 + case ViewerStatus.STATUS_SILENCE:
  557 + viewPager.setScrollable(true);
  558 + hasAnimRunning = false;
  559 + break;
  560 + }
  561 + if (mBrowseStatusListener != null) {
  562 + mBrowseStatusListener.onBrowseStatus(mViewStatus);
  563 + }
  564 + }
  565 +
  566 + /**
  567 + * 处理索引 UI
  568 + */
  569 + private void handleIndexUI(int startPosition) {
  570 + if (indexUI == null) {
  571 + indexUI = new DefaultIndexUI(overlayStatusBar);
  572 + }
  573 + if (showIndex) {
  574 + if (mSourceList.size() > 1) {
  575 + indexUI.setup(this, startPosition, mSourceList.size());
  576 + } else {
  577 + indexUI.hide();
  578 + }
  579 + } else {
  580 + indexUI.hide();
  581 + }
  582 + }
  583 +
  584 + private void shutComplete() {
  585 + setVisibility(GONE);
  586 + reset();
  587 + }
  588 +
  589 + private void reset() {
  590 + if (mViewBox.size() > 0) {
  591 + mViewBox.clear();
  592 + }
  593 + if (mDragHandler != null) {
  594 + mDragHandler.clear();
  595 + mDragHandler = null;
  596 + }
  597 + mAdapter = null;
  598 + hasAnimRunning = false;
  599 + hasPlayEnterAnim = false;
  600 + }
  601 +
  602 + public List<ViewData> getViewData() {
  603 + return mSourceList;
  604 + }
  605 +
  606 + public ImageDrawee getCurrentItem() {
  607 + if (mViewBox != null) {
  608 + for (ImageDrawee drawee : mViewBox) {
  609 + if ((int) drawee.getTag() == getCurrentPosition()) {
  610 + return drawee;
  611 + }
  612 + }
  613 + }
  614 + return (ImageDrawee) viewPager.findViewWithTag(getCurrentPosition());
  615 + }
  616 +
  617 + public int getCurrentPosition() {
  618 + return viewPager != null ? viewPager.getCurrentItem() : 0;
  619 + }
  620 +
  621 + public int getViewStatus() {
  622 + return mViewStatus;
  623 + }
  624 +
  625 + ////////////////////////////////////////////////////////////////////////////////////////////////
  626 + //// 拖拽相关
  627 + ////////////////////////////////////////////////////////////////////////////////////////////////
  628 +
  629 + @Override
  630 + public boolean onInterceptTouchEvent(MotionEvent ev) {
  631 + boolean isIntercept = super.onInterceptTouchEvent(ev);
  632 + if (!hasAnimRunning && draggable) {
  633 + // 是否拦截触摸事件?
  634 + // 若拦截,则 ImageViewer 自己处理触摸事件;
  635 + // 若不拦截,则 ImageView 处理触摸事件
  636 + int action = ev.getAction() & ev.getActionMasked();
  637 + if (action == MotionEvent.ACTION_DOWN) {
  638 + mLastX = ev.getX();
  639 + mLastY = ev.getY();
  640 + } else if (action == MotionEvent.ACTION_MOVE) {
  641 + /**
  642 + * 拖拽触发条件:
  643 + * 1.允许拖拽
  644 + * 2.仅有一个触摸点
  645 + * 3.图片的缩放等级 = 1f
  646 + * 4.拖拽处理类不为空
  647 + * 5.手势为上下滑动手势,左右滑动不触发
  648 + */
  649 + if (ev.getPointerCount() == 1 && getCurrentItem().getScale() <= 1f) {
  650 + float disX = ev.getX() - mLastX;
  651 + float disY = ev.getY() - mLastY;
  652 + // 上下滑动手势
  653 + if (Math.abs(disX) < Math.abs(disY)) {
  654 + if (mDragMode == DragMode.MODE_AGILE && disY < 0) {
  655 + return isIntercept;
  656 + }
  657 + isDragging = true;
  658 + if (mDragHandler == null) {
  659 + mDragHandler = new DragHandler(getWidth(), getHeight());
  660 + }
  661 + mDragHandler.onReay(mDragMode, getBackground());
  662 + noteDragStatus(DragStatus.STATUS_READY);
  663 + isIntercept = true;
  664 + }
  665 + }
  666 + }
  667 + }
  668 + return isIntercept;
  669 + }
  670 +
  671 + @Override
  672 + public boolean onTouchEvent(MotionEvent event) {
  673 + int action = event.getAction() & event.getActionMasked();
  674 + if (action == MotionEvent.ACTION_MOVE) {
  675 + if (draggable && isDragging && mDragHandler != null) {
  676 + mDragHandler.onDrag(mLastX, mLastY, event, getCurrentItem().getImageView());
  677 + noteDragStatus(DragStatus.STATUS_DRAGGING);
  678 + }
  679 + mLastX = event.getX();
  680 + mLastY = event.getY();
  681 + } else if (action == MotionEvent.ACTION_UP) {
  682 + if (draggable && isDragging && mDragHandler != null) {
  683 + isDragging = false;
  684 + // 释放图片
  685 + mDragHandler.onUp(getCurrentItem().getImageView(),
  686 + mSourceList.get(getCurrentPosition()), new ImageTransfer.OnTransCallback() {
  687 + @Override
  688 + public void onStart() {
  689 + handleDragResultStatus("start");
  690 + }
  691 +
  692 + @Override
  693 + public void onRunning(float progress) {
  694 + handleDragResultStatus("running");
  695 + }
  696 +
  697 + @Override
  698 + public void onEnd() {
  699 + handleDragResultStatus("end");
  700 + }
  701 + });
  702 + }
  703 + mLastX = 0;
  704 + mLastY = 0;
  705 + }
  706 + return super.onTouchEvent(event);
  707 + }
  708 +
  709 + private void handleDragResultStatus(String proceed) {
  710 + if (mDragHandler.getAction() == ImageTransfer.ACTION_DRAG_RESTORE) {
  711 + int status = proceed.equals("start") ? DragStatus.STATUS_BEGIN_RESTORE :
  712 + (proceed.equals("running") ? DragStatus.STATUS_RESTORING :
  713 + DragStatus.STATUS_COMPLETE_RESTORE);
  714 + if (status == DragStatus.STATUS_BEGIN_RESTORE) {
  715 + viewPager.setScrollable(false);
  716 + hasAnimRunning = true;
  717 + } else if (status == DragStatus.STATUS_COMPLETE_RESTORE) {
  718 + viewPager.setScrollable(true);
  719 + hasAnimRunning = false;
  720 + }
  721 + noteDragStatus(status);
  722 + } else if (mDragHandler.getAction() == ImageTransfer.ACTION_DRAG_EXIT_AGILE
  723 + || mDragHandler.getAction() == ImageTransfer.ACTION_DRAG_EXIT_SIMPLE) {
  724 + int status = proceed.equals("start") ? DragStatus.STATUS_BEGIN_EXIT :
  725 + (proceed.equals("running") ? DragStatus.STATUS_EXITTING :
  726 + DragStatus.STATUS_COMPLETE_EXIT);
  727 + if (status == DragStatus.STATUS_BEGIN_EXIT) {
  728 + viewPager.setScrollable(false);
  729 + hasAnimRunning = true;
  730 + } else if (status == DragStatus.STATUS_COMPLETE_EXIT) {
  731 + viewPager.setScrollable(true);
  732 + hasAnimRunning = false;
  733 + }
  734 + noteDragStatus(status);
  735 + if (proceed.equals("end")) {
  736 + noteBrowseStatus(ViewerStatus.STATUS_SILENCE);
  737 + shutComplete();
  738 + }
  739 + }
  740 + }
  741 +
  742 + /**
  743 + * 如果本方法未执行,则是因为图片浏览器为获取到焦点,可在外部手动获取焦点
  744 + * 建议在外部手动调动本方法
  745 + *
  746 + * @param keyCode
  747 + * @param event
  748 + * @return
  749 + */
  750 + @Override
  751 + public boolean onKeyDown(int keyCode, KeyEvent event) {
  752 + if (keyCode == KeyEvent.KEYCODE_BACK) {
  753 + if (!hasAnimRunning) {
  754 + if (mViewStatus == ViewerStatus.STATUS_WATCHING) {
  755 + cancel();
  756 + // 消费返回键点击事件,不传递出去
  757 + return true;
  758 + }
  759 + }
  760 + }
  761 + return super.onKeyDown(keyCode, event);
  762 + }
  763 +
  764 + @Override
  765 + protected void onDetachedFromWindow() {
  766 + super.onDetachedFromWindow();
  767 + mSourceList = null;
  768 + mLoader = null;
  769 + reset();
  770 + }
  771 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/ImageTransfer.java 0 → 100644
  1 +package com.cnlive.core.imagepreview;
  2 +
  3 +import android.animation.Animator;
  4 +import android.animation.AnimatorListenerAdapter;
  5 +import android.animation.ValueAnimator;
  6 +import android.graphics.drawable.Drawable;
  7 +import android.widget.FrameLayout;
  8 +import android.widget.ImageView;
  9 +
  10 +import androidx.annotation.NonNull;
  11 +
  12 +/**
  13 + * 图片进退场动画处理类
  14 + * created by hanyayun
  15 + * on 2020/1/20
  16 + */
  17 +public class ImageTransfer {
  18 + // 没有需要执行的动画
  19 + public static final int ACTION_IDEL = -1;
  20 + // 执行进场动画
  21 + public static final int ACTION_ENTER = 0;
  22 + // 执行退场动画
  23 + public static final int ACTION_EXIT = 1;
  24 + // 拖拽后,执行复原动画
  25 + public static final int ACTION_DRAG_RESTORE = 2;
  26 + // 在灵巧模式下,拖拽后,执行退场动画
  27 + public static final int ACTION_DRAG_EXIT_AGILE = 3;
  28 + // 在简单模式下,拖拽后,执行退场动画
  29 + public static final int ACTION_DRAG_EXIT_SIMPLE = 4;
  30 +
  31 +
  32 + private int interfaceWidth, interfaceHeight;
  33 + private int startWidth, startHeight;
  34 + private int endWidth, endHeight;
  35 + private float startX, startY;
  36 + private float endX, endY;
  37 + private long duration;
  38 + private Drawable background;
  39 + private int startAlpha, endAlpha;
  40 +
  41 + private int animAction;
  42 + // 是否设置了图片的原始尺寸
  43 + private boolean hasSetImageOriginalSize;
  44 + private ImageView imageView;
  45 + private OnTransCallback mTransCallback;
  46 +
  47 +
  48 + public ImageTransfer(int interfaceWidth, int interfaceHeight) {
  49 + this.interfaceWidth = interfaceWidth;
  50 + this.interfaceHeight = interfaceHeight;
  51 + }
  52 +
  53 + public ImageTransfer with(@NonNull ImageView target) {
  54 + this.imageView = target;
  55 + return this;
  56 + }
  57 +
  58 + /**
  59 + * 加载进场动画数据
  60 + */
  61 + public ImageTransfer loadEnterData(@NonNull ViewData viewData) {
  62 + startX = viewData.getTargetX();
  63 + startY = viewData.getTargetY();
  64 + startWidth = viewData.getTargetWidth();
  65 + startHeight = viewData.getTargetHeight();
  66 + int imageWidth, imageHeight;
  67 + if (viewData.getImageWidth() == 0 || viewData.getImageHeight() == 0) {
  68 + imageWidth = interfaceWidth;
  69 + imageHeight = interfaceHeight;
  70 + hasSetImageOriginalSize = false;
  71 + } else {
  72 + imageWidth = viewData.getImageWidth();
  73 + imageHeight = viewData.getImageHeight();
  74 + hasSetImageOriginalSize = true;
  75 + }
  76 + float scale = Math.min(interfaceWidth * 1f / imageWidth, interfaceHeight * 1f / imageHeight);
  77 + endWidth = (int) (imageWidth * scale);
  78 + endHeight = (int) (imageHeight * scale);
  79 + endX = (interfaceWidth - endWidth) * 1f / 2;
  80 + endY = (interfaceHeight - endHeight) * 1f / 2;
  81 + startAlpha = 0;
  82 + endAlpha = 255;
  83 + animAction = ACTION_ENTER;
  84 + return this;
  85 + }
  86 +
  87 + /**
  88 + * 加载退场动画数据
  89 + */
  90 + public ImageTransfer loadExitData(@NonNull ViewData viewData) {
  91 + endX = viewData.getTargetX();
  92 + endY = viewData.getTargetY();
  93 + endWidth = viewData.getTargetWidth();
  94 + endHeight = viewData.getTargetHeight();
  95 + int imageWidth, imageHeight;
  96 + if (viewData.getImageWidth() == 0 || viewData.getImageHeight() == 0) {
  97 + Drawable thumb = imageView.getDrawable();
  98 + if (thumb != null) {
  99 + imageWidth = thumb.getIntrinsicWidth();
  100 + imageHeight = thumb.getIntrinsicHeight();
  101 + hasSetImageOriginalSize = true;
  102 + } else {
  103 + imageWidth = interfaceWidth;
  104 + imageHeight = interfaceHeight;
  105 + hasSetImageOriginalSize = false;
  106 + }
  107 + } else {
  108 + imageWidth = viewData.getImageWidth();
  109 + imageHeight = viewData.getImageHeight();
  110 + hasSetImageOriginalSize = true;
  111 + }
  112 + float scale = Math.min(interfaceWidth * 1f / imageWidth, interfaceHeight * 1f / imageHeight);
  113 + startWidth = (int) (imageWidth * scale);
  114 + startHeight = (int) (imageHeight * scale);
  115 + startX = (interfaceWidth - startWidth) * 1f / 2;
  116 + startY = (interfaceHeight - startHeight) * 1f / 2;
  117 + startAlpha = background.getAlpha();
  118 + endAlpha = 0;
  119 + animAction = ACTION_EXIT;
  120 + return this;
  121 + }
  122 +
  123 + /**
  124 + * 加载拖拽复原动画数据
  125 + */
  126 + public ImageTransfer loadDragRestoreData() {
  127 + startX = imageView.getTranslationX();
  128 + startY = imageView.getTranslationY();
  129 + startWidth = imageView.getWidth();
  130 + startHeight = imageView.getHeight();
  131 + endX = 0;
  132 + endY = 0;
  133 + endWidth = interfaceWidth;
  134 + endHeight = interfaceHeight;
  135 + startAlpha = background.getAlpha();
  136 + endAlpha = 255;
  137 + animAction = ACTION_DRAG_RESTORE;
  138 + return this;
  139 + }
  140 +
  141 +
  142 + /**
  143 + * 灵巧拖拽模式下,加载拖拽退场动画数据
  144 + */
  145 + public ImageTransfer loadDragExitDataInAgile(@NonNull ViewData viewData) {
  146 + int imageWidth, imageHeight;
  147 + if (viewData.getImageWidth() == 0 || viewData.getImageHeight() == 0) {
  148 + Drawable thumb = imageView.getDrawable();
  149 + if (thumb != null) {
  150 + imageWidth = thumb.getIntrinsicWidth();
  151 + imageHeight = thumb.getIntrinsicHeight();
  152 + hasSetImageOriginalSize = true;
  153 + } else {
  154 + imageWidth = interfaceWidth;
  155 + imageHeight = interfaceHeight;
  156 + hasSetImageOriginalSize = false;
  157 + }
  158 + } else {
  159 + imageWidth = viewData.getImageWidth();
  160 + imageHeight = viewData.getImageHeight();
  161 + hasSetImageOriginalSize = true;
  162 + }
  163 + float adjustScale = Math.min(interfaceWidth * 1f / imageWidth, interfaceHeight * 1f / imageHeight);
  164 + float dragScale = imageView.getWidth() * 1f / interfaceWidth;
  165 + startWidth = (int) (imageWidth * adjustScale * dragScale);
  166 + startHeight = (int) (imageHeight * adjustScale * dragScale);
  167 + startX = imageView.getTranslationX() + (imageView.getWidth() - startWidth) * 1f / 2;
  168 + startY = imageView.getTranslationY() + (imageView.getHeight() - startHeight) * 1f / 2;
  169 + // 图片是否已经滑出预览界面
  170 + if (
  171 + // imageView 已经从左边滑出预览界面
  172 + (startX + startWidth) <= 0
  173 + // imageView 已经从右边滑出预览界面
  174 + || startX >= interfaceWidth
  175 + // imageView 已经从底部滑出图片预览界面
  176 + || startY >= interfaceHeight) {
  177 + endX = startX;
  178 + endY = startY;
  179 + endWidth = startWidth;
  180 + endHeight = startHeight;
  181 + } else {
  182 + endX = viewData.getTargetX();
  183 + endY = viewData.getTargetY();
  184 + endWidth = viewData.getTargetWidth();
  185 + endHeight = viewData.getTargetHeight();
  186 + }
  187 + startAlpha = background.getAlpha();
  188 + endAlpha = 0;
  189 + animAction = ACTION_DRAG_EXIT_AGILE;
  190 + return this;
  191 + }
  192 +
  193 + /**
  194 + * 简单拖拽模式下,加载拖拽退场动画数据
  195 + */
  196 + public ImageTransfer loadDragExitDataInSimple(@NonNull ViewData viewData) {
  197 + startX = endX = 0;
  198 + startY = imageView.getTranslationY();
  199 + startWidth = endWidth = imageView.getWidth();
  200 + startHeight = endHeight = imageView.getHeight();
  201 +
  202 + // 计算 endY
  203 + int imageWidth, imageHeight;
  204 + if (viewData.getImageWidth() == 0 || viewData.getImageHeight() == 0) {
  205 + Drawable thumb = imageView.getDrawable();
  206 + if (thumb != null) {
  207 + imageWidth = thumb.getIntrinsicWidth();
  208 + imageHeight = thumb.getIntrinsicHeight();
  209 + hasSetImageOriginalSize = true;
  210 + } else {
  211 + imageWidth = interfaceWidth;
  212 + imageHeight = interfaceHeight;
  213 + hasSetImageOriginalSize = false;
  214 + }
  215 + } else {
  216 + imageWidth = viewData.getImageWidth();
  217 + imageHeight = viewData.getImageHeight();
  218 + hasSetImageOriginalSize = true;
  219 + }
  220 + float scale = Math.min(interfaceWidth * 1f / imageWidth, interfaceHeight * 1f / imageHeight);
  221 + // 图片的缩放等级为 1f 时,图片的高度
  222 + int adjustImageHeight = (int) (imageHeight * scale);
  223 + // 图片的缩放等级为 1f 且居中时时,在预览界面中的距离容器顶部的距离
  224 + float disOnYFromTop = (interfaceHeight - adjustImageHeight) / 2;
  225 + // 图片在预览界面中的当前 Y 轴坐标
  226 + float currentImageY = startY + disOnYFromTop;
  227 + // 图片是否已经滑出浏览界面
  228 + if (
  229 + // 图片已经从顶部滑出预览界面
  230 + (currentImageY + adjustImageHeight) <= 0
  231 + // 图片已经从底部滑出预览界面
  232 + || currentImageY >= interfaceHeight) {
  233 + endY = startY;
  234 + } else {
  235 + // 此处加 20 ,是为了减少误差,防止影响动画美观
  236 + endY = currentImageY > disOnYFromTop ?
  237 + // 向下滑动
  238 + startY + (interfaceHeight - currentImageY) + 20
  239 + // 向上滑动
  240 + : startY - (currentImageY + adjustImageHeight) - 20;
  241 + }
  242 +
  243 + startAlpha = background.getAlpha();
  244 + endAlpha = 0;
  245 + animAction = ACTION_DRAG_EXIT_SIMPLE;
  246 + return this;
  247 + }
  248 +
  249 + public ImageTransfer background(Drawable background) {
  250 + this.background = background;
  251 + return this;
  252 + }
  253 +
  254 + public ImageTransfer duration(long duration) {
  255 + this.duration = duration;
  256 + return this;
  257 + }
  258 +
  259 + public ImageTransfer callback(OnTransCallback callback) {
  260 + this.mTransCallback = callback;
  261 + return this;
  262 + }
  263 +
  264 + public void play() {
  265 + ValueAnimator animator = ValueAnimator.ofFloat(0, 1f);
  266 + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  267 +
  268 + @Override
  269 + public void onAnimationUpdate(ValueAnimator animation) {
  270 + final float progress = (float) animation.getAnimatedValue();
  271 + if (startX != endX) {
  272 + imageView.setTranslationX(calculateByProgress(progress, startX, endX));
  273 + }
  274 + if (startY != endY) {
  275 + imageView.setTranslationY(calculateByProgress(progress, startY, endY));
  276 + }
  277 + if (startWidth != endWidth || startHeight != endHeight) {
  278 + imageView.getLayoutParams().width = (int) calculateByProgress(progress, startWidth, endWidth);
  279 + imageView.getLayoutParams().height = (int) calculateByProgress(progress, startHeight, endHeight);
  280 + imageView.requestLayout();
  281 + }
  282 + if (startAlpha != endAlpha) {
  283 + background.setAlpha((int) calculateByProgress(progress, startAlpha, endAlpha));
  284 + }
  285 + if (mTransCallback != null) {
  286 + mTransCallback.onRunning(progress);
  287 + }
  288 + }
  289 + });
  290 + animator.addListener(new AnimatorListenerAdapter() {
  291 + @Override
  292 + public void onAnimationStart(Animator animation) {
  293 + super.onAnimationStart(animation);
  294 + if (animAction == ACTION_ENTER
  295 + || animAction == ACTION_EXIT
  296 + || animAction == ACTION_DRAG_EXIT_AGILE) {
  297 + if (hasSetImageOriginalSize) {
  298 + imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
  299 + }
  300 + }
  301 + if (mTransCallback != null) {
  302 + mTransCallback.onStart();
  303 + }
  304 + }
  305 +
  306 + @Override
  307 + public void onAnimationEnd(Animator animation) {
  308 + super.onAnimationEnd(animation);
  309 + if (animAction == ACTION_ENTER && hasSetImageOriginalSize) {
  310 + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
  311 + imageView.setTranslationX(0);
  312 + imageView.setTranslationY(0);
  313 + imageView.getLayoutParams().width = FrameLayout.LayoutParams.MATCH_PARENT;
  314 + imageView.getLayoutParams().height = FrameLayout.LayoutParams.MATCH_PARENT;
  315 + imageView.requestLayout();
  316 + }
  317 + imageView = null;
  318 + background = null;
  319 + animAction = ACTION_IDEL;
  320 + if (mTransCallback != null) {
  321 + mTransCallback.onEnd();
  322 + }
  323 + }
  324 + });
  325 + animator.setDuration(duration);
  326 + animator.start();
  327 + }
  328 +
  329 + /**
  330 + * 根据进度,计算过渡值
  331 + */
  332 + private float calculateByProgress(float progress, float startVal, float endVal) {
  333 + return startVal + progress * (endVal - startVal);
  334 + }
  335 +
  336 + public interface OnTransCallback {
  337 + void onStart();
  338 +
  339 + void onRunning(float progress);
  340 +
  341 + void onEnd();
  342 + }
  343 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/LoadImage.java 0 → 100644
  1 +package com.cnlive.core.imagepreview;
  2 +
  3 +import android.widget.ImageView;
  4 +
  5 +/**
  6 + * created by hanyayun
  7 + * on 2020/1/21
  8 + */
  9 +public abstract class LoadImage {
  10 + /**
  11 + * 加载图片
  12 + */
  13 + public abstract void displayImage(Object src, ImageView imageView, LoadCallback callback);
  14 +
  15 + public interface LoadCallback {
  16 + void onLoadStarted(Object placeholder);
  17 +
  18 + void onLoading(float progress);
  19 +
  20 + void onLoadSucceed(Object source);
  21 +
  22 + void onLoadFailed(Object error);
  23 + }
  24 +}
  25 +
core/imageload/src/main/java/com/cnlive/core/imagepreview/PhotoLoader.java 0 → 100644
  1 +package com.cnlive.core.imagepreview;
  2 +
  3 +import android.graphics.drawable.Drawable;
  4 +import android.widget.ImageView;
  5 +
  6 +import com.bumptech.glide.request.target.CustomViewTarget;
  7 +import com.bumptech.glide.request.transition.Transition;
  8 +import com.cnlive.core.imageload.config.ScaleMode;
  9 +import com.cnlive.core.imageload.loader.ImageLoader;
  10 +import com.cnlive.core.libs.base.application.GlideApp;
  11 +
  12 +import androidx.annotation.NonNull;
  13 +import androidx.annotation.Nullable;
  14 +
  15 +
  16 +/**
  17 + * created by hanyayun
  18 + * on 2020/2/12
  19 + */
  20 +public class PhotoLoader extends LoadImage {
  21 + @Override
  22 + public void displayImage(Object src, ImageView imageView, LoadCallback callback) {
  23 + GlideApp.with(imageView.getContext())
  24 + .load(src)
  25 + .into(new CustomViewTarget<ImageView, Drawable>(imageView) {
  26 + @Override
  27 + public void onLoadFailed(@Nullable Drawable errorDrawable) {
  28 + if(callback!=null) {
  29 + callback.onLoadFailed(errorDrawable);
  30 + }
  31 + }
  32 +
  33 + @Override
  34 + public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
  35 + if(callback!=null) {
  36 + callback.onLoadSucceed(resource);
  37 + }
  38 + }
  39 +
  40 + @Override
  41 + protected void onResourceLoading(@Nullable Drawable placeholder) {
  42 + super.onResourceLoading(placeholder);
  43 + if(callback!=null){
  44 + callback.onLoadStarted(placeholder);
  45 + }
  46 + }
  47 +
  48 + @Override
  49 + protected void onResourceCleared(@Nullable Drawable placeholder) {
  50 +
  51 + }
  52 + });
  53 + }
  54 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/Utils.java 0 → 100644
  1 +package com.cnlive.core.imagepreview;
  2 +
  3 +import android.content.Context;
  4 +import android.os.Handler;
  5 +import android.os.Message;
  6 +
  7 +/**
  8 + * created by hanyayun
  9 + * on 2020/1/20
  10 + */
  11 +public class Utils {
  12 +
  13 + public static int dp2px(Context context, float dpVal) {
  14 + final float scale = context.getResources().getDisplayMetrics().density;
  15 + return (int) (dpVal * scale + 0.5f);
  16 + }
  17 +
  18 + public static int getStatusBarHeight(Context context) {
  19 + int result = 0;
  20 + int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
  21 + if (resourceId > 0) {
  22 + result = context.getResources().getDimensionPixelSize(resourceId);
  23 + }
  24 + return result;
  25 + }
  26 +
  27 + public static Handler sHandler = new Handler() {
  28 + @Override
  29 + public void handleMessage(Message msg) {
  30 + super.handleMessage(msg);
  31 +
  32 + }
  33 + };
  34 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/ViewData.java 0 → 100644
  1 +package com.cnlive.core.imagepreview;
  2 +
  3 +/**
  4 + * created by hanyayun
  5 + * on 2020/1/20
  6 + */
  7 +public class ViewData {
  8 + // 图片资源
  9 + private Object imageSrc;
  10 + // 图片的原始宽度
  11 + private int imageWidth;
  12 + // 图片的原始高度
  13 + private int imageHeight;
  14 + // 目标 view 的 x 轴坐标
  15 + private float targetX;
  16 + // 目标 view 的 y 轴坐标
  17 + private float targetY;
  18 + // 目标 view 的宽度
  19 + private int targetWidth;
  20 + // 目标 view 的高度
  21 + private int targetHeight;
  22 +
  23 + public ViewData() {
  24 +
  25 + }
  26 +
  27 + public ViewData(Object imageSrc) {
  28 + this.imageSrc = imageSrc;
  29 + }
  30 +
  31 + public ViewData(float targetX, float targetY, int targetWidth, int targetHeight) {
  32 + this.targetX = targetX;
  33 + this.targetY = targetY;
  34 + this.targetWidth = targetWidth;
  35 + this.targetHeight = targetHeight;
  36 + }
  37 +
  38 + public ViewData(Object imageSrc, float targetX, float targetY, int targetWidth, int targetHeight) {
  39 + this.imageSrc = imageSrc;
  40 + this.targetX = targetX;
  41 + this.targetY = targetY;
  42 + this.targetWidth = targetWidth;
  43 + this.targetHeight = targetHeight;
  44 + }
  45 +
  46 + public ViewData(Object imageSrc, int imageWidth, int imageHeight, float targetX, float targetY, int targetWidth, int targetHeight) {
  47 + this.imageSrc = imageSrc;
  48 + this.imageWidth = imageWidth;
  49 + this.imageHeight = imageHeight;
  50 + this.targetX = targetX;
  51 + this.targetY = targetY;
  52 + this.targetWidth = targetWidth;
  53 + this.targetHeight = targetHeight;
  54 + }
  55 +
  56 + public Object getImageSrc() {
  57 + return imageSrc;
  58 + }
  59 +
  60 + public void setImageSrc(Object imageSrc) {
  61 + this.imageSrc = imageSrc;
  62 + }
  63 +
  64 + public int getImageWidth() {
  65 + return imageWidth;
  66 + }
  67 +
  68 + public void setImageWidth(int imageWidth) {
  69 + this.imageWidth = imageWidth;
  70 + }
  71 +
  72 + public int getImageHeight() {
  73 + return imageHeight;
  74 + }
  75 +
  76 + public void setImageHeight(int imageHeight) {
  77 + this.imageHeight = imageHeight;
  78 + }
  79 +
  80 + public float getTargetX() {
  81 + return targetX;
  82 + }
  83 +
  84 + public void setTargetX(float targetX) {
  85 + this.targetX = targetX;
  86 + }
  87 +
  88 + public float getTargetY() {
  89 + return targetY;
  90 + }
  91 +
  92 + public void setTargetY(float targetY) {
  93 + this.targetY = targetY;
  94 + }
  95 +
  96 + public int getTargetWidth() {
  97 + return targetWidth;
  98 + }
  99 +
  100 + public void setTargetWidth(int targetWidth) {
  101 + this.targetWidth = targetWidth;
  102 + }
  103 +
  104 + public int getTargetHeight() {
  105 + return targetHeight;
  106 + }
  107 +
  108 + public void setTargetHeight(int targetHeight) {
  109 + this.targetHeight = targetHeight;
  110 + }
  111 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/ViewerStatus.java 0 → 100644
  1 +package com.cnlive.core.imagepreview;
  2 +
  3 +/**
  4 + * created by hanyayun
  5 + * on 2020/1/21
  6 + */
  7 +public final class ViewerStatus {
  8 + /**
  9 + * 图片浏览器处于未开启状态
  10 + */
  11 + public static final int STATUS_SILENCE = 0;
  12 + /**
  13 + * 图片浏览器开始执行进场动画
  14 + */
  15 + public static final int STATUS_BEGIN_OPEN = 1;
  16 + /**
  17 + * 图片浏览器正在执行进场动画
  18 + */
  19 + public static final int STATUS_OPENING = 2;
  20 + /**
  21 + * 图片正在被浏览中
  22 + */
  23 + public static final int STATUS_WATCHING = 3;
  24 + /**
  25 + * 图片浏览器开始执行退场动画
  26 + */
  27 + public static final int STATUS_BEGIN_CLOSE = 4;
  28 + /**
  29 + * 图片浏览器正在执行退场动画
  30 + */
  31 + public static final int STATUS_CLOSING = 5;
  32 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/dragger/DragHandler.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.dragger;
  2 +
  3 +import android.graphics.drawable.Drawable;
  4 +import android.view.MotionEvent;
  5 +import android.widget.ImageView;
  6 +
  7 +import com.cnlive.core.imagepreview.ImageTransfer;
  8 +import com.cnlive.core.imagepreview.ViewData;
  9 +
  10 +/**
  11 + * 拖拽工具类
  12 + * created by hanyayun
  13 + * on 2020/1/20
  14 + */
  15 +public class DragHandler {
  16 + // 完全不透明的透明度值
  17 + private final int FULL_ALPHA = 255;
  18 + // 动画执行时间
  19 + private final int ANIM_DURATION = 300;
  20 + // 最小缩放比例
  21 + private final float MIN_SCALE = 0.2f;
  22 + // 在不退出浏览的情况下, 图片在 Y 轴上的最大可移动距离
  23 + private final float MAX_MOVABLE_DIS_ON_Y;
  24 + // 背景透明度的变换基数
  25 + private final float ALPHA_BASE;
  26 +
  27 + // 拖拽模式
  28 + private int mMode;
  29 + // 浏览界面的宽高
  30 + private int mIfWidth, mIfHeight;
  31 + private Drawable mBackground;
  32 + private ImageTransfer mTransfer;
  33 + private int mAction;
  34 +
  35 + public DragHandler(int ifWidth, int ifHeight) {
  36 + this.mIfWidth = ifWidth;
  37 + this.mIfHeight = ifHeight;
  38 + this.MAX_MOVABLE_DIS_ON_Y = ifHeight / 5f;
  39 + this.ALPHA_BASE = MAX_MOVABLE_DIS_ON_Y * 2;
  40 + this.mTransfer = new ImageTransfer(ifWidth, ifHeight);
  41 + }
  42 +
  43 + /**
  44 + * 准备拖拽
  45 + */
  46 + public void onReay(int mode, Drawable bg) {
  47 + this.mMode = mode;
  48 + this.mBackground = bg;
  49 + mAction = ImageTransfer.ACTION_IDEL;
  50 + }
  51 +
  52 + /**
  53 + * 拖拽中
  54 + *
  55 + * @param lastX 上一次触摸点的 x 轴坐标
  56 + * @param lastY 上一次触摸点的 y 轴坐标
  57 + * @param event 本次触摸点的手势事件
  58 + * @param imageView
  59 + */
  60 + public void onDrag(float lastX, float lastY, MotionEvent event, ImageView imageView) {
  61 + if (mMode == DragMode.MODE_SIMPLE) {
  62 + dragBySimple(lastY, event, imageView);
  63 + } else if (mMode == DragMode.MODE_AGILE) {
  64 + dragByAgile(lastX, lastY, event, imageView);
  65 + }
  66 + }
  67 +
  68 + /**
  69 + * 手指抬起
  70 + */
  71 + public void onUp(ImageView imageView, ViewData viewData, ImageTransfer.OnTransCallback callback) {
  72 + final float transY = imageView.getTranslationY();
  73 + mTransfer.with(imageView)
  74 + .background(mBackground)
  75 + .duration(ANIM_DURATION);
  76 + // 执行复原动画
  77 + if (Math.abs(transY) <= MAX_MOVABLE_DIS_ON_Y) {
  78 + mAction = ImageTransfer.ACTION_DRAG_RESTORE;
  79 + mTransfer.loadDragRestoreData()
  80 + .callback(callback);
  81 + }
  82 + // 执行退场动画
  83 + else {
  84 + if (mMode == DragMode.MODE_AGILE) {
  85 + if (transY < 0) {
  86 + mAction = ImageTransfer.ACTION_DRAG_RESTORE;
  87 + mTransfer.loadDragRestoreData()
  88 + .callback(callback);
  89 + } else {
  90 + mAction = ImageTransfer.ACTION_DRAG_EXIT_AGILE;
  91 + mTransfer.loadDragExitDataInAgile(viewData)
  92 + .callback(callback);
  93 + }
  94 + } else {
  95 + mAction = ImageTransfer.ACTION_DRAG_EXIT_SIMPLE;
  96 + mTransfer.loadDragExitDataInSimple(viewData)
  97 + .callback(callback);
  98 + }
  99 + }
  100 + mTransfer.play();
  101 + }
  102 +
  103 + public int getAction() {
  104 + return mAction;
  105 + }
  106 +
  107 + public void clear() {
  108 + if (mTransfer != null) {
  109 + mTransfer = null;
  110 + }
  111 + }
  112 +
  113 + /**
  114 + * 简单模式拖拽(类似今日头条)
  115 + */
  116 + private void dragBySimple(float lastY, MotionEvent event, ImageView imageView) {
  117 + final float disY = event.getY() - lastY;
  118 + final float nextY = imageView.getTranslationY() + disY;
  119 + imageView.setTranslationY(nextY);
  120 + // 计算背景透明度
  121 + final float value = Math.abs(nextY) / ALPHA_BASE;
  122 + transformBgAlpha((int) ((value < 0.8f ? 1 - value : 0.2f) * FULL_ALPHA));
  123 + }
  124 +
  125 +
  126 + /**
  127 + * 灵巧模式拖拽(类似微信朋友圈)
  128 + */
  129 + private void dragByAgile(float lastX, float lastY, MotionEvent event, ImageView imageView) {
  130 + // 手指的移动距离
  131 + final float disX = event.getX() - lastX;
  132 + final float disY = event.getY() - lastY;
  133 + // imageView 被拖拽后的坐标
  134 + final float nextX = imageView.getTranslationX() + disX;
  135 + final float nextY = imageView.getTranslationY() + disY;
  136 + // 向上移动
  137 + if (nextY <= 0) {
  138 + if (imageView.getLayoutParams().width != mIfWidth ||
  139 + imageView.getLayoutParams().height != mIfHeight) {
  140 + imageView.getLayoutParams().width = mIfWidth;
  141 + imageView.getLayoutParams().height = mIfHeight;
  142 + imageView.requestLayout();
  143 + }
  144 + transformBgAlpha(FULL_ALPHA);
  145 + }
  146 + // 向下移动
  147 + else {
  148 + // 计算缩放比例
  149 + final float scale = Math.min(Math.max(1f - nextY / mIfHeight, MIN_SCALE), 1f);
  150 + imageView.getLayoutParams().width = (int) (mIfWidth * scale);
  151 + imageView.getLayoutParams().height = (int) (mIfHeight * scale);
  152 + imageView.requestLayout();
  153 + // 变换背景透明度
  154 + transformBgAlpha((int) (scale * FULL_ALPHA));
  155 + }
  156 + imageView.setTranslationX(nextX);
  157 + imageView.setTranslationY(nextY);
  158 + }
  159 +
  160 + /**
  161 + * 变换背景透明度
  162 + */
  163 + private void transformBgAlpha(int alpha) {
  164 + if (mBackground != null && mBackground.getAlpha() != alpha) {
  165 + mBackground.setAlpha(alpha);
  166 + }
  167 + }
  168 +
  169 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/dragger/DragMode.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.dragger;
  2 +
  3 +/**
  4 + * created by hanyayun
  5 + * on 2020/1/20
  6 + */
  7 +public class DragMode {
  8 + // 简单拖拽模式
  9 + public final static int MODE_SIMPLE = 1;
  10 + // 灵巧的拖拽模式
  11 + public final static int MODE_AGILE = 2;
  12 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/dragger/DragStatus.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.dragger;
  2 +
  3 +/**
  4 + * created by hanyayun
  5 + * on 2020/1/20
  6 + */
  7 +public class DragStatus {
  8 + /**
  9 + * 准备开始拖拽
  10 + */
  11 + public static final int STATUS_READY = 1;
  12 + /**
  13 + * 正在拖拽中
  14 + */
  15 + public static final int STATUS_DRAGGING = 2;
  16 + /**
  17 + * 开始执行复原动画
  18 + */
  19 + public static final int STATUS_BEGIN_RESTORE = 3;
  20 + /**
  21 + * 复原动画执行中
  22 + */
  23 + public static final int STATUS_RESTORING = 4;
  24 + /**
  25 + * 复原动画执行完毕
  26 + */
  27 + public static final int STATUS_COMPLETE_RESTORE = 5;
  28 + /**
  29 + * 开始执行退出浏览动画
  30 + */
  31 + public static final int STATUS_BEGIN_EXIT = 6;
  32 + /**
  33 + * 退出浏览动画执行中
  34 + */
  35 + public static final int STATUS_EXITTING = 7;
  36 + /**
  37 + * 退出浏览动画执行完毕
  38 + */
  39 + public static final int STATUS_COMPLETE_EXIT = 8;
  40 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/indexui/DefaultIndexUI.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.indexui;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.Color;
  5 +import android.util.TypedValue;
  6 +import android.view.Gravity;
  7 +import android.view.View;
  8 +import android.widget.FrameLayout;
  9 +import android.widget.TextView;
  10 +
  11 +import com.cnlive.core.imagepreview.Utils;
  12 +
  13 +/**
  14 + * 默认的索引视图
  15 + * created by hanyayun
  16 + * on 2020/1/20
  17 + */
  18 +public class DefaultIndexUI extends IndexUI {
  19 + private boolean overlayStatusBar;
  20 +
  21 + public DefaultIndexUI(boolean overlayStatusBar) {
  22 + this.overlayStatusBar = overlayStatusBar;
  23 + }
  24 +
  25 + @Override
  26 + public View createView(Context context) {
  27 + TextView indexView = new TextView(context);
  28 + FrameLayout.LayoutParams textParams = new FrameLayout.LayoutParams(
  29 + FrameLayout.LayoutParams.WRAP_CONTENT,
  30 + FrameLayout.LayoutParams.WRAP_CONTENT);
  31 + textParams.setMargins(0,
  32 + Utils.dp2px(context, overlayStatusBar ? Utils.getStatusBarHeight(context) + 5 : 5),
  33 + 0, 0);
  34 + textParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
  35 + indexView.setLayoutParams(textParams);
  36 + indexView.setIncludeFontPadding(false);
  37 + indexView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
  38 + indexView.setTextColor(Color.WHITE);
  39 + return indexView;
  40 + }
  41 +
  42 + @Override
  43 + public void init(int position, int length) {
  44 + ((TextView) getIndexView()).setText((position + 1) + "/" + length);
  45 + }
  46 +
  47 + @Override
  48 + public void handleItemChanged(int position, int length) {
  49 + ((TextView) getIndexView()).setText((position + 1) + "/" + length);
  50 + }
  51 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/indexui/DefaultProgressUI.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.indexui;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.Color;
  5 +import android.view.Gravity;
  6 +import android.view.View;
  7 +import android.widget.FrameLayout;
  8 +
  9 +import com.cnlive.core.imagepreview.Utils;
  10 +import com.cnlive.core.imagepreview.uti.ProgressWheel;
  11 +
  12 +import java.text.DecimalFormat;
  13 +
  14 +import static android.view.View.VISIBLE;
  15 +
  16 +/**
  17 + * 默认的加载进度视图
  18 + * created by hanyayun
  19 + * on 2020/1/20
  20 + */
  21 +public class DefaultProgressUI extends ProgressUI{
  22 + private DecimalFormat mProgressFormat;
  23 +
  24 + public DefaultProgressUI() {
  25 + mProgressFormat = new DecimalFormat("#%");
  26 + }
  27 + @Override
  28 + public View createView(Context context) {
  29 + // 添加进度条
  30 + ProgressWheel progressView = new ProgressWheel(context);
  31 + final int size = Utils.dp2px(context, 60);
  32 + FrameLayout.LayoutParams barLp = new FrameLayout.LayoutParams(size, size);
  33 + barLp.gravity = Gravity.CENTER;
  34 + progressView.setLayoutParams(barLp);
  35 + final int barWidth = Utils.dp2px(context, 3);
  36 + progressView.setBarColor(Color.parseColor("#CCFFFFFF"));
  37 + progressView.setBarWidth(barWidth);
  38 + progressView.setBarLength(Utils.dp2px(context, 50));
  39 + progressView.setRimColor(Color.parseColor("#22FFFFFF"));
  40 + progressView.setRimWidth(barWidth);
  41 + progressView.setContourColor(Color.parseColor("#10000000"));
  42 + progressView.setSpinSpeed(3.5f);
  43 + progressView.setText("");
  44 + progressView.setTextColor(Color.parseColor("#CCFFFFFF"));
  45 + progressView.setTextSize(Utils.dp2px(context, 14));
  46 + return progressView;
  47 + }
  48 +
  49 + @Override
  50 + public void handleProgress(float progress) {
  51 + if (getProgressView().getVisibility() == VISIBLE) {
  52 + ((ProgressWheel) getProgressView()).setText(mProgressFormat.format(progress));
  53 + ((ProgressWheel) getProgressView()).setProgress((int) (progress * 360));
  54 + if (progress == 1f) {
  55 + stop();
  56 + }
  57 + }
  58 + }
  59 +
  60 + @Override
  61 + public void start() {
  62 + super.start();
  63 + ((ProgressWheel) getProgressView()).startSpinning();
  64 + }
  65 +
  66 + @Override
  67 + public void stop() {
  68 + super.stop();
  69 + ((ProgressWheel) getProgressView()).stopSpinning();
  70 + }
  71 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/indexui/IndexUI.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.indexui;
  2 +
  3 +import android.content.Context;
  4 +import android.view.View;
  5 +import android.view.ViewGroup;
  6 +
  7 +import androidx.annotation.NonNull;
  8 +
  9 +/**
  10 + * 索引视图基类
  11 + * created by hanyayun
  12 + * on 2020/1/20
  13 + */
  14 +public abstract class IndexUI {
  15 + private View indexView;
  16 +
  17 + /**
  18 + * 创建索引视图
  19 + */
  20 + public abstract View createView(Context context);
  21 +
  22 + /**
  23 + * 初始设置
  24 + */
  25 + public abstract void init(int position, int length);
  26 +
  27 + /**
  28 + * 处理 item 切换事件
  29 + */
  30 + public abstract void handleItemChanged(int position, int length);
  31 +
  32 + public void setup(@NonNull ViewGroup parent, int startPosition, int length) {
  33 + if (indexView == null) {
  34 + indexView = createView(parent.getContext());
  35 + }
  36 + if (indexView.getParent() == null) {
  37 + parent.addView(indexView);
  38 + }
  39 + init(startPosition, length);
  40 + show();
  41 + }
  42 +
  43 + /**
  44 + * 显示索引
  45 + */
  46 + public void show() {
  47 + if (indexView != null) {
  48 + indexView.setVisibility(View.VISIBLE);
  49 + }
  50 + }
  51 +
  52 + /**
  53 + * 隐藏索引
  54 + */
  55 + public void hide() {
  56 + if (indexView != null) {
  57 + indexView.setVisibility(View.GONE);
  58 + }
  59 + }
  60 +
  61 + public View getIndexView() {
  62 + return indexView;
  63 + }
  64 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/indexui/ProgressUI.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.indexui;
  2 +
  3 +import android.content.Context;
  4 +import android.view.View;
  5 +import android.view.ViewGroup;
  6 +
  7 +/**
  8 + * created by hanyayun
  9 + * on 2020/1/20
  10 + */
  11 +public abstract class ProgressUI {
  12 + private View progressView;
  13 +
  14 + /**
  15 + * 创建加载进度视图
  16 + */
  17 + public abstract View createView(Context context);
  18 +
  19 + /**
  20 + * 处理进度
  21 + *
  22 + * @param progress 范围: 0-1
  23 + */
  24 + public abstract void handleProgress(float progress);
  25 +
  26 + public void init(ViewGroup parent) {
  27 + if (progressView == null) {
  28 + progressView = createView(parent.getContext());
  29 + }
  30 + if (progressView.getParent() == null) {
  31 + parent.addView(progressView);
  32 + }
  33 + }
  34 +
  35 + public void start() {
  36 + if (progressView != null) {
  37 + progressView.setVisibility(View.VISIBLE);
  38 + }
  39 + }
  40 +
  41 + public void stop() {
  42 + if (progressView != null) {
  43 + progressView.setVisibility(View.GONE);
  44 + }
  45 + }
  46 +
  47 + public View getProgressView() {
  48 + return progressView;
  49 + }
  50 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/listener/OnBrowseStatusListener.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.listener;
  2 +
  3 +/**
  4 + * 图片状态的监听事件
  5 + * created by hanyayun
  6 + * on 2020/1/20
  7 + */
  8 +public interface OnBrowseStatusListener {
  9 +
  10 + /**
  11 + * 监听图片预览的当前状态
  12 + */
  13 + void onBrowseStatus(int status);
  14 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/listener/OnDragStatusListener.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.listener;
  2 +
  3 +/**
  4 + * 监听图片被拖拽时的状态
  5 + * created by hanyayun
  6 + * on 2020/1/20
  7 + */
  8 +public interface OnDragStatusListener {
  9 + /**
  10 + * 监听图片拖拽的状态
  11 + */
  12 + void onDragStatusChanged(int status);
  13 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/listener/OnItemChangedListener.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.listener;
  2 +
  3 +import com.cnlive.core.imagepreview.ImageDrawee;
  4 +
  5 +/**
  6 + * 图片item 的切换事件
  7 + * created by hanyayun
  8 + * on 2020/1/20
  9 + */
  10 +public interface OnItemChangedListener {
  11 +
  12 + void onItemChanged(int position, ImageDrawee drawee);
  13 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/listener/OnItemClickListener.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.listener;
  2 +
  3 +import android.widget.ImageView;
  4 +
  5 +/**
  6 + * 图片单击事件
  7 + * created by hanyayun
  8 + * on 2020/1/20
  9 + */
  10 +public interface OnItemClickListener {
  11 + /**
  12 + * @param position
  13 + * @param imageView
  14 + * @return {@code true}: 消费了点击事件,后续方法不再执行 {@code false}: 没有消费点击事件,后续方法继续执行
  15 + */
  16 + boolean onItemClick(int position, ImageView imageView);
  17 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/listener/OnItemLongPressListener.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.listener;
  2 +
  3 +import android.widget.ImageView;
  4 +
  5 +/**
  6 + * 图片长按
  7 + * created by hanyayun
  8 + * on 2020/1/20
  9 + */
  10 +public interface OnItemLongPressListener {
  11 +
  12 + boolean onItemLongPress(int position, ImageView imageView);
  13 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/uti/ProgressWheel.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.uti;
  2 +
  3 +import android.content.Context;
  4 +import android.content.res.TypedArray;
  5 +import android.graphics.Canvas;
  6 +import android.graphics.Paint;
  7 +import android.graphics.RectF;
  8 +import android.graphics.Shader;
  9 +import android.util.AttributeSet;
  10 +import android.view.View;
  11 +
  12 +import com.cnlive.core.imageload.R;
  13 +
  14 +/**
  15 + * created by hanyayun
  16 + * on 2020/1/20
  17 + */
  18 +public class ProgressWheel extends View {
  19 + // Sizes (with defaults)
  20 + private int layoutHeight = 0;
  21 + private int layoutWidth = 0;
  22 + private int fullRadius = 100;
  23 + private int circleRadius = 80;
  24 + private int barLength = 60;
  25 + private int barWidth = 20;
  26 + private int rimWidth = 20;
  27 + private int textSize = 20;
  28 + private float contourSize = 0;
  29 +
  30 + // Padding (with defaults)
  31 + private int paddingTop = 5;
  32 + private int paddingBottom = 5;
  33 + private int paddingLeft = 5;
  34 + private int paddingRight = 5;
  35 +
  36 + // Colors (with defaults)
  37 + private int barColor = 0xAA000000;
  38 + private int contourColor = 0xAA000000;
  39 + private int circleColor = 0x00000000;
  40 + private int rimColor = 0xAADDDDDD;
  41 + private int textColor = 0xFF000000;
  42 +
  43 + // Paints
  44 + private Paint barPaint = new Paint();
  45 + private Paint circlePaint = new Paint();
  46 + private Paint rimPaint = new Paint();
  47 + private Paint textPaint = new Paint();
  48 + private Paint contourPaint = new Paint();
  49 +
  50 + // Rectangles
  51 + private RectF innerCircleBounds = new RectF();
  52 + private RectF circleBounds = new RectF();
  53 + private RectF circleOuterContour = new RectF();
  54 + private RectF circleInnerContour = new RectF();
  55 +
  56 + // Animation
  57 + // The amount of pixels to move the bar by on each draw
  58 + private float spinSpeed = 2f;
  59 + // The number of milliseconds to wait in between each draw
  60 + private int delayMillis = 10;
  61 + private float progress = 0;
  62 + boolean isSpinning = false;
  63 +
  64 + // Other
  65 + private String text = "";
  66 + private String[] splitText = {};
  67 +
  68 + public ProgressWheel(Context context){
  69 + super(context);
  70 + }
  71 +
  72 + /**
  73 + * The constructor for the ProgressWheel
  74 + *
  75 + * @param context
  76 + * @param attrs
  77 + */
  78 + public ProgressWheel(Context context, AttributeSet attrs) {
  79 + super(context, attrs);
  80 + parseAttributes(context.obtainStyledAttributes(attrs, R.styleable.ivr_ProgressWheel));
  81 + }
  82 +
  83 + /*
  84 + * When this is called, make the view square.
  85 + * From: http://www.jayway.com/2012/12/12/creating-custom-android-views-part-4-measuring-and-how-to-force-a-view-to-be-square/
  86 + *
  87 + */
  88 + @Override
  89 + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  90 + // The first thing that happen is that we call the superclass
  91 + // implementation of onMeasure. The reason for that is that measuring
  92 + // can be quite a complex process and calling the super method is a
  93 + // convenient way to get most of this complexity handled.
  94 + super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  95 +
  96 + // We can’t use getWidth() or getHight() here. During the measuring
  97 + // pass the view has not gotten its final size yet (this happens first
  98 + // at the watch of the layout pass) so we have to use getMeasuredWidth()
  99 + // and getMeasuredHeight().
  100 + int size = 0;
  101 + int width = getMeasuredWidth();
  102 + int height = getMeasuredHeight();
  103 + int widthWithoutPadding = width - getPaddingLeft() - getPaddingRight();
  104 + int heightWithoutPadding = height - getPaddingTop() - getPaddingBottom();
  105 +
  106 + // Finally we have some simple logic that calculates the size of the view
  107 + // and calls setMeasuredDimension() to set that size.
  108 + // Before we compare the width and height of the view, we remove the padding,
  109 + // and when we set the dimension we add it back again. Now the actual content
  110 + // of the view will be square, but, depending on the padding, the total dimensions
  111 + // of the view might not be.
  112 + int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  113 + int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  114 + if (heightMode != MeasureSpec.UNSPECIFIED && widthMode != MeasureSpec.UNSPECIFIED) {
  115 + if (widthWithoutPadding > heightWithoutPadding) {
  116 + size = heightWithoutPadding;
  117 + } else {
  118 + size = widthWithoutPadding;
  119 + }
  120 + } else {
  121 + size = Math.max(heightWithoutPadding, widthWithoutPadding);
  122 + }
  123 +
  124 +
  125 + // If you override onMeasure() you have to call setMeasuredDimension().
  126 + // This is how you report back the measured size. If you don’t call
  127 + // setMeasuredDimension() the parent will throw an exception and your
  128 + // application will crash.
  129 + // We are calling the onMeasure() method of the superclass so we don’t
  130 + // actually need to call setMeasuredDimension() since that takes care
  131 + // of that. However, the purpose with overriding onMeasure() was to
  132 + // change the default behaviour and to do that we need to call
  133 + // setMeasuredDimension() with our own values.
  134 + setMeasuredDimension(
  135 + size + getPaddingLeft() + getPaddingRight(),
  136 + size + getPaddingTop() + getPaddingBottom());
  137 + }
  138 +
  139 + /**
  140 + * Use onSizeChanged instead of onAttachedToWindow to get the dimensions of the view,
  141 + * because this method is called after measuring the dimensions of MATCH_PARENT & WRAP_CONTENT.
  142 + * Use this dimensions to setup the bounds and paints.
  143 + */
  144 + @Override
  145 + protected void onSizeChanged(int newWidth, int newHeight, int oldWidth, int oldHeight) {
  146 + super.onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
  147 + layoutWidth = newWidth;
  148 + layoutHeight = newHeight;
  149 + setupBounds();
  150 + setupPaints();
  151 + invalidate();
  152 + }
  153 +
  154 + /**
  155 + * Set the properties of the paints we're using to
  156 + * draw the progress wheel
  157 + */
  158 + private void setupPaints() {
  159 + barPaint.setColor(barColor);
  160 + barPaint.setAntiAlias(true);
  161 + barPaint.setStyle(Paint.Style.STROKE);
  162 + barPaint.setStrokeWidth(barWidth);
  163 +
  164 + rimPaint.setColor(rimColor);
  165 + rimPaint.setAntiAlias(true);
  166 + rimPaint.setStyle(Paint.Style.STROKE);
  167 + rimPaint.setStrokeWidth(rimWidth);
  168 +
  169 + circlePaint.setColor(circleColor);
  170 + circlePaint.setAntiAlias(true);
  171 + circlePaint.setStyle(Paint.Style.FILL);
  172 +
  173 + textPaint.setColor(textColor);
  174 + textPaint.setStyle(Paint.Style.FILL);
  175 + textPaint.setAntiAlias(true);
  176 + textPaint.setTextSize(textSize);
  177 +
  178 + contourPaint.setColor(contourColor);
  179 + contourPaint.setAntiAlias(true);
  180 + contourPaint.setStyle(Paint.Style.STROKE);
  181 + contourPaint.setStrokeWidth(contourSize);
  182 + }
  183 +
  184 + /**
  185 + * Set the bounds of the component
  186 + */
  187 + private void setupBounds() {
  188 + // Width should equal to Height, find the min value to setup the circle
  189 + int minValue = Math.min(layoutWidth, layoutHeight);
  190 +
  191 + // Calc the Offset if needed
  192 + int xOffset = layoutWidth - minValue;
  193 + int yOffset = layoutHeight - minValue;
  194 +
  195 + // Add the offset
  196 + paddingTop = this.getPaddingTop() + (yOffset / 2);
  197 + paddingBottom = this.getPaddingBottom() + (yOffset / 2);
  198 + paddingLeft = this.getPaddingLeft() + (xOffset / 2);
  199 + paddingRight = this.getPaddingRight() + (xOffset / 2);
  200 +
  201 + int width = getWidth();
  202 + int height = getHeight();
  203 +
  204 + innerCircleBounds = new RectF(
  205 + paddingLeft + (1.5f * barWidth),
  206 + paddingTop + (1.5f * barWidth),
  207 + width - paddingRight - (1.5f * barWidth),
  208 + height - paddingBottom - (1.5f * barWidth));
  209 + circleBounds = new RectF(
  210 + paddingLeft + barWidth,
  211 + paddingTop + barWidth,
  212 + width - paddingRight - barWidth,
  213 + height - paddingBottom - barWidth);
  214 + circleInnerContour = new RectF(
  215 + circleBounds.left + (rimWidth / 2.0f) + (contourSize / 2.0f),
  216 + circleBounds.top + (rimWidth / 2.0f) + (contourSize / 2.0f),
  217 + circleBounds.right - (rimWidth / 2.0f) - (contourSize / 2.0f),
  218 + circleBounds.bottom - (rimWidth / 2.0f) - (contourSize / 2.0f));
  219 + circleOuterContour = new RectF(
  220 + circleBounds.left - (rimWidth / 2.0f) - (contourSize / 2.0f),
  221 + circleBounds.top - (rimWidth / 2.0f) - (contourSize / 2.0f),
  222 + circleBounds.right + (rimWidth / 2.0f) + (contourSize / 2.0f),
  223 + circleBounds.bottom + (rimWidth / 2.0f) + (contourSize / 2.0f));
  224 +
  225 + fullRadius = (width - paddingRight - barWidth) / 2;
  226 + circleRadius = (fullRadius - barWidth) + 1;
  227 + }
  228 +
  229 + /**
  230 + * Parse the attributes passed to the view from the XML
  231 + *
  232 + * @param a the attributes to parse
  233 + */
  234 + private void parseAttributes(TypedArray a) {
  235 + barColor = a.getColor(R.styleable.ivr_ProgressWheel_pwBarColor, barColor);
  236 + barWidth = (int) a.getDimension(R.styleable.ivr_ProgressWheel_pwBarWidth, barWidth);
  237 + barLength = (int) a.getDimension(R.styleable.ivr_ProgressWheel_pwBarLength, barLength);
  238 + rimColor = a.getColor(R.styleable.ivr_ProgressWheel_pwRimColor, rimColor);
  239 + rimWidth = (int) a.getDimension(R.styleable.ivr_ProgressWheel_pwRimWidth, rimWidth);
  240 + contourColor = a.getColor(R.styleable.ivr_ProgressWheel_pwContourColor, contourColor);
  241 + contourSize = a.getDimension(R.styleable.ivr_ProgressWheel_pwContourSize, contourSize);
  242 + circleColor = a.getColor(R.styleable.ivr_ProgressWheel_pwCircleColor, circleColor);
  243 +
  244 + // Only set the text if it is explicitly defined
  245 + if (a.hasValue(R.styleable.ivr_ProgressWheel_pwText)) {
  246 + setText(a.getString(R.styleable.ivr_ProgressWheel_pwText));
  247 + }
  248 + textColor = a.getColor(R.styleable.ivr_ProgressWheel_pwTextColor, textColor);
  249 + textSize = (int) a.getDimension(R.styleable.ivr_ProgressWheel_pwTextSize, textSize);
  250 +
  251 + spinSpeed = a.getFloat(R.styleable.ivr_ProgressWheel_pwSpinSpeed, spinSpeed);
  252 + delayMillis = a.getInteger(R.styleable.ivr_ProgressWheel_pwDelayMillis, delayMillis);
  253 + if (delayMillis < 0) {
  254 + delayMillis = 10;
  255 + }
  256 + a.recycle();
  257 + }
  258 +
  259 + //----------------------------------
  260 + //Animation stuff
  261 + //----------------------------------
  262 +
  263 + protected void onDraw(Canvas canvas) {
  264 + super.onDraw(canvas);
  265 + //Draw the inner circle
  266 + canvas.drawArc(innerCircleBounds, 360, 360, false, circlePaint);
  267 + //Draw the rim
  268 + canvas.drawArc(circleBounds, 360, 360, false, rimPaint);
  269 + canvas.drawArc(circleOuterContour, 360, 360, false, contourPaint);
  270 + //canvas.drawArc(circleInnerContour, 360, 360, false, contourPaint);
  271 + //Draw the bar
  272 + if (isSpinning) {
  273 + canvas.drawArc(circleBounds, progress - 90, barLength, false, barPaint);
  274 + } else {
  275 + canvas.drawArc(circleBounds, -90, progress, false, barPaint);
  276 + }
  277 + //Draw the text (attempts to center it horizontally and vertically)
  278 + float textHeight = textPaint.descent() - textPaint.ascent();
  279 + float verticalTextOffset = (textHeight / 2) - textPaint.descent();
  280 +
  281 + for (String line : splitText) {
  282 + float horizontalTextOffset = textPaint.measureText(line) / 2;
  283 + canvas.drawText(
  284 + line,
  285 + this.getWidth() / 2 - horizontalTextOffset,
  286 + this.getHeight() / 2 + verticalTextOffset,
  287 + textPaint);
  288 + }
  289 + if (isSpinning) {
  290 + scheduleRedraw();
  291 + }
  292 + }
  293 +
  294 + private void scheduleRedraw() {
  295 + progress += spinSpeed;
  296 + if (progress > 360) {
  297 + progress = 0;
  298 + }
  299 + postInvalidateDelayed(delayMillis);
  300 + }
  301 +
  302 + /**
  303 + * Check if the wheel is currently spinning
  304 + */
  305 + public boolean isSpinning() {
  306 + return isSpinning;
  307 + }
  308 +
  309 + /**
  310 + * Reset the count (in increment mode)
  311 + */
  312 + public void resetCount() {
  313 + progress = 0;
  314 + setText("0%");
  315 + invalidate();
  316 + }
  317 +
  318 + /**
  319 + * Turn off startSpinning mode
  320 + */
  321 + public void stopSpinning() {
  322 + isSpinning = false;
  323 + progress = 0;
  324 + postInvalidate();
  325 + }
  326 +
  327 +
  328 + /**
  329 + * Puts the view on spin mode
  330 + */
  331 + public void startSpinning() {
  332 + isSpinning = true;
  333 + postInvalidate();
  334 + }
  335 +
  336 + /**
  337 + * Increment the progress by 1 (of 360)
  338 + */
  339 + public void incrementProgress() {
  340 + incrementProgress(1);
  341 + }
  342 +
  343 + public void incrementProgress(int amount) {
  344 + isSpinning = false;
  345 + progress += amount;
  346 + if (progress > 360)
  347 + progress %= 360;
  348 + postInvalidate();
  349 + }
  350 +
  351 +
  352 + /**
  353 + * Set the progress to a specific value
  354 + */
  355 + public void setProgress(int i) {
  356 + isSpinning = false;
  357 + progress = i;
  358 + postInvalidate();
  359 + }
  360 +
  361 + //----------------------------------
  362 + //Getters + setters
  363 + //----------------------------------
  364 +
  365 + /**
  366 + * Set the text in the progress bar
  367 + * Doesn't invalidate the view
  368 + *
  369 + * @param text the text to show ('\n' constitutes a new line)
  370 + */
  371 + public void setText(String text) {
  372 + this.text = text;
  373 + splitText = this.text.split("\n");
  374 + }
  375 +
  376 + public int getCircleRadius() {
  377 + return circleRadius;
  378 + }
  379 +
  380 + public void setCircleRadius(int circleRadius) {
  381 + this.circleRadius = circleRadius;
  382 + }
  383 +
  384 + public int getBarLength() {
  385 + return barLength;
  386 + }
  387 +
  388 + public void setBarLength(int barLength) {
  389 + this.barLength = barLength;
  390 + }
  391 +
  392 + public int getBarWidth() {
  393 + return barWidth;
  394 + }
  395 +
  396 + public void setBarWidth(int barWidth) {
  397 + this.barWidth = barWidth;
  398 +
  399 + if (this.barPaint != null) {
  400 + this.barPaint.setStrokeWidth(this.barWidth);
  401 + }
  402 + }
  403 +
  404 + public int getTextSize() {
  405 + return textSize;
  406 + }
  407 +
  408 + public void setTextSize(int textSize) {
  409 + this.textSize = textSize;
  410 +
  411 + if (this.textPaint != null) {
  412 + this.textPaint.setTextSize(this.textSize);
  413 + }
  414 + }
  415 +
  416 + public int getPaddingTop() {
  417 + return paddingTop;
  418 + }
  419 +
  420 + public void setPaddingTop(int paddingTop) {
  421 + this.paddingTop = paddingTop;
  422 + }
  423 +
  424 + public int getPaddingBottom() {
  425 + return paddingBottom;
  426 + }
  427 +
  428 + public void setPaddingBottom(int paddingBottom) {
  429 + this.paddingBottom = paddingBottom;
  430 + }
  431 +
  432 + public int getPaddingLeft() {
  433 + return paddingLeft;
  434 + }
  435 +
  436 + public void setPaddingLeft(int paddingLeft) {
  437 + this.paddingLeft = paddingLeft;
  438 + }
  439 +
  440 + public int getPaddingRight() {
  441 + return paddingRight;
  442 + }
  443 +
  444 + public void setPaddingRight(int paddingRight) {
  445 + this.paddingRight = paddingRight;
  446 + }
  447 +
  448 + public int getBarColor() {
  449 + return barColor;
  450 + }
  451 +
  452 + public void setBarColor(int barColor) {
  453 + this.barColor = barColor;
  454 +
  455 + if (this.barPaint != null) {
  456 + this.barPaint.setColor(this.barColor);
  457 + }
  458 + }
  459 +
  460 + public int getCircleColor() {
  461 + return circleColor;
  462 + }
  463 +
  464 + public void setCircleColor(int circleColor) {
  465 + this.circleColor = circleColor;
  466 +
  467 + if (this.circlePaint != null) {
  468 + this.circlePaint.setColor(this.circleColor);
  469 + }
  470 + }
  471 +
  472 + public int getRimColor() {
  473 + return rimColor;
  474 + }
  475 +
  476 + public void setRimColor(int rimColor) {
  477 + this.rimColor = rimColor;
  478 +
  479 + if (this.rimPaint != null) {
  480 + this.rimPaint.setColor(this.rimColor);
  481 + }
  482 + }
  483 +
  484 + public Shader getRimShader() {
  485 + return rimPaint.getShader();
  486 + }
  487 +
  488 + public void setRimShader(Shader shader) {
  489 + this.rimPaint.setShader(shader);
  490 + }
  491 +
  492 + public int getTextColor() {
  493 + return textColor;
  494 + }
  495 +
  496 + public void setTextColor(int textColor) {
  497 + this.textColor = textColor;
  498 +
  499 + if (this.textPaint != null) {
  500 + this.textPaint.setColor(this.textColor);
  501 + }
  502 + }
  503 +
  504 + public float getSpinSpeed() {
  505 + return spinSpeed;
  506 + }
  507 +
  508 + public void setSpinSpeed(float spinSpeed) {
  509 + this.spinSpeed = spinSpeed;
  510 + }
  511 +
  512 + public int getRimWidth() {
  513 + return rimWidth;
  514 + }
  515 +
  516 + public void setRimWidth(int rimWidth) {
  517 + this.rimWidth = rimWidth;
  518 +
  519 + if (this.rimPaint != null) {
  520 + this.rimPaint.setStrokeWidth(this.rimWidth);
  521 + }
  522 + }
  523 +
  524 + public int getDelayMillis() {
  525 + return delayMillis;
  526 + }
  527 +
  528 + public void setDelayMillis(int delayMillis) {
  529 + this.delayMillis = delayMillis;
  530 + }
  531 +
  532 + public int getContourColor() {
  533 + return contourColor;
  534 + }
  535 +
  536 + public void setContourColor(int contourColor) {
  537 + this.contourColor = contourColor;
  538 +
  539 + if (contourPaint != null) {
  540 + this.contourPaint.setColor(this.contourColor);
  541 + }
  542 + }
  543 +
  544 + public float getContourSize() {
  545 + return this.contourSize;
  546 + }
  547 +
  548 + public void setContourSize(float contourSize) {
  549 + this.contourSize = contourSize;
  550 +
  551 + if (contourPaint != null) {
  552 + this.contourPaint.setStrokeWidth(this.contourSize);
  553 + }
  554 + }
  555 +
  556 + public int getProgress() {
  557 + return (int) progress;
  558 + }
  559 +}
core/imageload/src/main/java/com/cnlive/core/imagepreview/viewpager/ImagePagerAdapter.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.viewpager;
  2 +
  3 +import android.view.View;
  4 +import android.view.ViewGroup;
  5 +
  6 +import com.cnlive.core.imagepreview.ImageDrawee;
  7 +
  8 +import androidx.annotation.NonNull;
  9 +import androidx.viewpager.widget.PagerAdapter;
  10 +
  11 +/**
  12 + * created by hanyayun
  13 + * on 2020/1/20
  14 + */
  15 +public class ImagePagerAdapter extends PagerAdapter {
  16 + private int mItemCount;
  17 +
  18 + public ImagePagerAdapter(int count) {
  19 + this.mItemCount = count;
  20 + }
  21 +
  22 + @Override
  23 + public int getCount() {
  24 + return mItemCount;
  25 + }
  26 +
  27 + @NonNull
  28 + @Override
  29 + public Object instantiateItem(@NonNull ViewGroup container, int position) {
  30 + return null;
  31 + }
  32 +
  33 + @Override
  34 + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
  35 + if (object != null) {
  36 + ((ImageDrawee) object).recycle();
  37 + // 移除页面
  38 + container.removeView((View) object);
  39 + }
  40 + }
  41 +
  42 + @Override
  43 + public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
  44 + return view == object;
  45 + }
  46 +}
  47 +
core/imageload/src/main/java/com/cnlive/core/imagepreview/viewpager/ImageViewPager.java 0 → 100644
  1 +package com.cnlive.core.imagepreview.viewpager;
  2 +
  3 +import android.content.Context;
  4 +import android.util.AttributeSet;
  5 +import android.view.MotionEvent;
  6 +
  7 +import androidx.viewpager.widget.ViewPager;
  8 +
  9 +/**
  10 + * 预览器 ViewPager
  11 + * created by hanyayun
  12 + * on 2020/1/20
  13 + */
  14 +public class ImageViewPager extends ViewPager {
  15 + // 是否可滑动
  16 + private boolean isScrollable = true;
  17 +
  18 + public ImageViewPager(Context context) {
  19 + super(context);
  20 + }
  21 +
  22 + public ImageViewPager(Context context, AttributeSet attrs) {
  23 + super(context, attrs);
  24 + }
  25 +
  26 + @Override
  27 + public void scrollTo(int x, int y) {
  28 + if (isScrollable) {
  29 + super.scrollTo(x, y);
  30 + }
  31 + }
  32 +
  33 + /**
  34 + * 设置是否可滑动
  35 + *
  36 + * @param isScrollable
  37 + */
  38 + public void setScrollable(boolean isScrollable) {
  39 + this.isScrollable = isScrollable;
  40 + }
  41 +
  42 + /**
  43 + * 重写 onInterceptTouchEvent 和 onTouchEvent 方法是为了解决
  44 + * PhotoView + Viewpager 双指缩放的时候出现 pointerIndex out of range 问题
  45 + */
  46 +
  47 + @Override
  48 + public boolean onInterceptTouchEvent(MotionEvent ev) {
  49 + try {
  50 + return super.onInterceptTouchEvent(ev);
  51 + } catch (IllegalArgumentException ex) {
  52 + ex.printStackTrace();
  53 + }
  54 + return false;
  55 + }
  56 +
  57 + @Override
  58 + public boolean onTouchEvent(MotionEvent ev) {
  59 + try {
  60 + return super.onTouchEvent(ev);
  61 + } catch (IllegalArgumentException ex) {
  62 + ex.printStackTrace();
  63 + }
  64 + return false;
  65 + }
  66 +}
0 \ No newline at end of file 67 \ No newline at end of file
core/imageload/src/main/res/layout/auto_grid_item_simple_pic.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:orientation="vertical">
  6 +
  7 + <ImageView
  8 + android:id="@+id/iv_auto_grid_item_simple_pic"
  9 + android:layout_width="match_parent"
  10 + android:layout_height="match_parent"
  11 + android:scaleType="centerCrop" />
  12 +</LinearLayout>
0 \ No newline at end of file 13 \ No newline at end of file
core/imageload/src/main/res/layout/auto_grid_item_simple_pic_single.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:orientation="vertical">
  6 +
  7 + <ImageView
  8 + android:id="@+id/iv_auto_grid_item_simple_pic"
  9 + android:layout_width="200dp"
  10 + android:layout_height="wrap_content"
  11 + android:adjustViewBounds="true" />
  12 +</LinearLayout>
0 \ No newline at end of file 13 \ No newline at end of file
core/imageload/src/main/res/values/auto_grid_view_attrs.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <!--网格控件-->
  4 + <declare-styleable name="AutoGridView">
  5 + <!--网格图的类型-->
  6 + <attr name="agv_mode">
  7 + <!--类似QQ空间、微信朋友圈的九宫格类型网格图-->
  8 + <enum name="nine" value="0" />
  9 + <!--依次显示网格的普通类型网格图-->
  10 + <enum name="normal" value="1" />
  11 + </attr>
  12 + <!--网格的行数-->
  13 + <attr name="agv_row" format="integer" />
  14 + <!--网格的列数-->
  15 + <attr name="agv_column" format="integer" />
  16 + <!--item 的高度-->
  17 + <attr name="agv_item_height" format="dimension" />
  18 + <!--item 之间的横向间距-->
  19 + <attr name="agv_horizontal_space" format="dimension" />
  20 + <!--item 之间的纵向间距-->
  21 + <attr name="agv_vertical_space" format="dimension" />
  22 + <!--九宫格模式下,单个 item 时,item 的宽与 parent 的可用总宽的比-->
  23 + <attr name="agv_nines_widthper" format="float" />
  24 + <!--九宫格模式下,单个 item 时,item 的高与 parent 的可用总宽的比-->
  25 + <attr name="agv_nines_heightper" format="float" />
  26 + </declare-styleable>
  27 +</resources>
core/imageload/src/main/res/values/grid_attrs.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <declare-styleable name="ImagePreView">
  4 + <!--是否开启进场动画-->
  5 + <attr name="ivr_playEnterAnim" format="boolean" />
  6 + <!--是否开启退场动画-->
  7 + <attr name="ivr_playExitAnim" format="boolean" />
  8 + <!--进场与退场动画的执行时间-->
  9 + <attr name="ivr_duration" format="integer" />
  10 + <!--是否显示图片位置-->
  11 + <attr name="ivr_showIndex" format="boolean" />
  12 + <!--是否允许图片拖拽-->
  13 + <attr name="ivr_draggable" format="boolean" />
  14 + <!--拖拽模式-->
  15 + <attr name="ivr_dragMode">
  16 + <enum name="simple" value="1" />
  17 + <enum name="agile" value="2" />
  18 + </attr>
  19 + </declare-styleable>
  20 +</resources>
0 \ No newline at end of file 21 \ No newline at end of file
core/imageload/src/main/res/values/ivr_progrv_attrs.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <declare-styleable name="ivr_ProgressWheel">
  4 + <attr name="pwText" format="string" />
  5 + <attr name="pwTextColor" format="color" />
  6 + <attr name="pwTextSize" format="dimension" />
  7 + <attr name="pwBarColor" format="color" />
  8 + <attr name="pwBarWidth" format="dimension" />
  9 + <attr name="pwBarLength" format="dimension" />
  10 + <attr name="pwRimColor" format="color" />
  11 + <attr name="pwRimWidth" format="dimension" />
  12 + <attr name="pwContourColor" format="color" />
  13 + <attr name="pwContourSize" format="dimension" />
  14 + <attr name="pwRadius" format="dimension" />
  15 + <attr name="pwCircleColor" format="color" />
  16 + <attr name="pwSpinSpeed" format="float" />
  17 + <attr name="pwDelayMillis" format="integer" />
  18 + </declare-styleable>
  19 +</resources>
0 \ No newline at end of file 20 \ No newline at end of file