Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
android_vedio
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
android
android_vedio
Commits
8f9a78d5
Commit
8f9a78d5
authored
Jun 30, 2023
by
mengcuiguang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
代码优化
parent
1af1a0f7
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
0 additions
and
4046 deletions
+0
-4046
ItemRecyclerViewAdapter.java
...mints/wisdomclean/ui/adapter/ItemRecyclerViewAdapter.java
+0
-381
SectionRecyclerViewAdapter.java
...ts/wisdomclean/ui/adapter/SectionRecyclerViewAdapter.java
+0
-98
BgChooseView.kt
...ain/java/com/mints/wisdomclean/ui/widgets/BgChooseView.kt
+0
-142
ButtonView.java
...ain/java/com/mints/wisdomclean/ui/widgets/ButtonView.java
+0
-287
CustomProgressDialog.java
...om/mints/wisdomclean/ui/widgets/CustomProgressDialog.java
+0
-26
DashboradView.kt
...in/java/com/mints/wisdomclean/ui/widgets/DashboradView.kt
+0
-450
DrawHookView.java
...n/java/com/mints/wisdomclean/ui/widgets/DrawHookView.java
+0
-111
ExpandableGridView.java
.../com/mints/wisdomclean/ui/widgets/ExpandableGridView.java
+0
-43
GifView.kt
...src/main/java/com/mints/wisdomclean/ui/widgets/GifView.kt
+0
-247
InterceptFrameLayout.java
...om/mints/wisdomclean/ui/widgets/InterceptFrameLayout.java
+0
-36
MilliCountDownTimer.java
...com/mints/wisdomclean/ui/widgets/MilliCountDownTimer.java
+0
-121
PhotoDialog.kt
...main/java/com/mints/wisdomclean/ui/widgets/PhotoDialog.kt
+0
-63
PhotoWrpView.kt
...ain/java/com/mints/wisdomclean/ui/widgets/PhotoWrpView.kt
+0
-272
ProgressButton.java
...java/com/mints/wisdomclean/ui/widgets/ProgressButton.java
+0
-150
RoundAngleImageView.java
...com/mints/wisdomclean/ui/widgets/RoundAngleImageView.java
+0
-117
RoundCheckBox.kt
...in/java/com/mints/wisdomclean/ui/widgets/RoundCheckBox.kt
+0
-14
TransformativeImageView.java
...mints/wisdomclean/ui/widgets/TransformativeImageView.java
+0
-589
WaveView.java
.../main/java/com/mints/wisdomclean/ui/widgets/WaveView.java
+0
-154
GestureView.java
...com/mints/wisdomclean/ui/widgets/applock/GestureView.java
+0
-214
GestureViewGroup.java
...ints/wisdomclean/ui/widgets/applock/GestureViewGroup.java
+0
-531
No files found.
video/app/src/main/java/com/mints/wisdomclean/ui/adapter/ItemRecyclerViewAdapter.java
deleted
100755 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
adapter
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.net.Uri
;
import
android.os.Build
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.webkit.MimeTypeMap
;
import
android.widget.ImageView
;
import
android.widget.RelativeLayout
;
import
android.widget.TextView
;
import
android.widget.Toast
;
import
androidx.appcompat.widget.AppCompatCheckBox
;
import
androidx.core.content.FileProvider
;
import
androidx.recyclerview.widget.RecyclerView
;
import
com.bumptech.glide.Glide
;
import
com.bumptech.glide.Priority
;
import
com.bumptech.glide.load.engine.DiskCacheStrategy
;
import
com.mints.library.utils.Utils
;
import
com.mints.wisdomclean.R
;
import
com.mints.wisdomclean.mvp.model.Duplicate
;
import
com.mints.wisdomclean.mvp.model.TypeFile
;
import
java.io.File
;
import
java.util.ArrayList
;
/**
* Created by sonu on 24/07/17.
*/
public
class
ItemRecyclerViewAdapter
extends
RecyclerView
.
Adapter
<
ItemRecyclerViewAdapter
.
ItemViewHolder
>
{
class
ItemViewHolder
extends
RecyclerView
.
ViewHolder
{
private
TextView
itemLabel
;
private
TextView
tvSize
;
private
TextView
tvPath
;
ImageView
image
,
ivPlay
;
AppCompatCheckBox
ivCheckbox
;
private
RelativeLayout
rlCard
;
public
ItemViewHolder
(
View
itemView
)
{
super
(
itemView
);
itemLabel
=
(
TextView
)
itemView
.
findViewById
(
R
.
id
.
name
);
tvSize
=
(
TextView
)
itemView
.
findViewById
(
R
.
id
.
size
);
tvPath
=
(
TextView
)
itemView
.
findViewById
(
R
.
id
.
path
);
image
=
(
ImageView
)
itemView
.
findViewById
(
R
.
id
.
image
);
ivCheckbox
=
(
AppCompatCheckBox
)
itemView
.
findViewById
(
R
.
id
.
checked
);
ivPlay
=
(
ImageView
)
itemView
.
findViewById
(
R
.
id
.
play
);
rlCard
=
(
RelativeLayout
)
itemView
.
findViewById
(
R
.
id
.
rlCard
);
}
}
private
Context
context
;
private
ArrayList
<
Duplicate
>
mDuplicates
;
public
ItemRecyclerViewAdapter
(
Context
context
,
ArrayList
<
Duplicate
>
arrayList
)
{
this
.
context
=
context
;
this
.
mDuplicates
=
arrayList
;
}
@Override
public
ItemViewHolder
onCreateViewHolder
(
ViewGroup
parent
,
int
viewType
)
{
View
view
=
LayoutInflater
.
from
(
parent
.
getContext
()).
inflate
(
R
.
layout
.
item_custom_row_dupicate
,
parent
,
false
);
return
new
ItemViewHolder
(
view
);
}
@Override
public
void
onBindViewHolder
(
final
ItemViewHolder
holder
,
final
int
position
)
{
final
Duplicate
mDuplicate
=
mDuplicates
.
get
(
position
);
holder
.
itemLabel
.
setText
(
getFileName
(
mDuplicate
.
getFile
().
getPath
()));
holder
.
tvSize
.
setText
(
Utils
.
formatSize
(
mDuplicate
.
getFile
().
length
()));
holder
.
tvPath
.
setText
(
mDuplicate
.
getFile
().
getPath
());
holder
.
ivCheckbox
.
setChecked
(
mDuplicate
.
isChecked
());
switch
(
mDuplicate
.
getTypeFile
()){
case
TypeFile
.
IMAGE
:
try
{
Glide
.
with
(
context
)
.
load
(
"file://"
+
mDuplicate
.
getFile
().
getPath
())
.
diskCacheStrategy
(
DiskCacheStrategy
.
ALL
)
.
priority
(
Priority
.
HIGH
)
.
centerCrop
()
.
error
(
R
.
mipmap
.
ic_launcher_main
)
.
into
(
holder
.
image
);
}
catch
(
Exception
e
){
//do nothing
Toast
.
makeText
(
context
,
"Exception: "
+
e
.
getMessage
(),
Toast
.
LENGTH_SHORT
).
show
();
}
break
;
case
TypeFile
.
VIDEO
:
holder
.
ivPlay
.
setVisibility
(
View
.
VISIBLE
);
try
{
Glide
.
with
(
context
)
.
load
(
"file://"
+
mDuplicate
.
getFile
().
getPath
())
.
diskCacheStrategy
(
DiskCacheStrategy
.
ALL
)
.
priority
(
Priority
.
HIGH
)
.
centerCrop
()
.
error
(
R
.
mipmap
.
ic_launcher_main
)
.
into
(
holder
.
image
);
}
catch
(
Exception
e
){
//do nothing
Toast
.
makeText
(
context
,
"Exception: "
+
e
.
getMessage
(),
Toast
.
LENGTH_SHORT
).
show
();
}
break
;
case
TypeFile
.
DOCUMENT
:
try
{
Glide
.
with
(
context
)
.
load
(
R
.
drawable
.
document
)
.
diskCacheStrategy
(
DiskCacheStrategy
.
ALL
)
.
priority
(
Priority
.
HIGH
)
.
centerCrop
()
.
error
(
R
.
mipmap
.
ic_launcher_main
)
.
into
(
holder
.
image
);
}
catch
(
Exception
e
){
//do nothing
Toast
.
makeText
(
context
,
"Exception: "
+
e
.
getMessage
(),
Toast
.
LENGTH_SHORT
).
show
();
}
break
;
case
TypeFile
.
PDF
:
try
{
Glide
.
with
(
context
)
.
load
(
R
.
drawable
.
ic_pdf
)
.
diskCacheStrategy
(
DiskCacheStrategy
.
ALL
)
.
priority
(
Priority
.
HIGH
)
.
centerCrop
()
.
error
(
R
.
mipmap
.
ic_launcher_main
)
.
into
(
holder
.
image
);
}
catch
(
Exception
e
){
//do nothing
Toast
.
makeText
(
context
,
"Exception: "
+
e
.
getMessage
(),
Toast
.
LENGTH_SHORT
).
show
();
}
break
;
case
TypeFile
.
ZIP
:
try
{
Glide
.
with
(
context
)
.
load
(
R
.
drawable
.
zip
)
.
diskCacheStrategy
(
DiskCacheStrategy
.
ALL
)
.
priority
(
Priority
.
HIGH
)
.
centerCrop
()
.
error
(
R
.
mipmap
.
ic_launcher_main
)
.
into
(
holder
.
image
);
}
catch
(
Exception
e
){
//do nothing
Toast
.
makeText
(
context
,
"Exception: "
+
e
.
getMessage
(),
Toast
.
LENGTH_SHORT
).
show
();
}
break
;
case
TypeFile
.
APK
:
try
{
Glide
.
with
(
context
)
.
load
(
R
.
drawable
.
android
)
.
diskCacheStrategy
(
DiskCacheStrategy
.
ALL
)
.
priority
(
Priority
.
HIGH
)
.
centerCrop
()
.
error
(
R
.
mipmap
.
ic_launcher_main
)
.
into
(
holder
.
image
);
}
catch
(
Exception
e
){
//do nothing
Toast
.
makeText
(
context
,
"Exception: "
+
e
.
getMessage
(),
Toast
.
LENGTH_SHORT
).
show
();
}
break
;
case
TypeFile
.
VCF
:
try
{
Glide
.
with
(
context
)
.
load
(
R
.
drawable
.
vcf
)
.
diskCacheStrategy
(
DiskCacheStrategy
.
ALL
)
.
priority
(
Priority
.
HIGH
)
.
centerCrop
()
.
error
(
R
.
mipmap
.
ic_launcher_main
)
.
into
(
holder
.
image
);
}
catch
(
Exception
e
){
//do nothing
Toast
.
makeText
(
context
,
"Exception: "
+
e
.
getMessage
(),
Toast
.
LENGTH_SHORT
).
show
();
}
break
;
case
TypeFile
.
AUDIO
:
try
{
Glide
.
with
(
context
)
.
load
(
R
.
drawable
.
audio
)
.
diskCacheStrategy
(
DiskCacheStrategy
.
ALL
)
.
priority
(
Priority
.
HIGH
)
.
centerCrop
()
.
error
(
R
.
mipmap
.
ic_launcher_main
)
.
into
(
holder
.
image
);
}
catch
(
Exception
e
){
//do nothing
Toast
.
makeText
(
context
,
"Exception: "
+
e
.
getMessage
(),
Toast
.
LENGTH_SHORT
).
show
();
}
break
;
default
:
try
{
Glide
.
with
(
context
)
.
load
(
R
.
drawable
.
unknown
)
.
diskCacheStrategy
(
DiskCacheStrategy
.
ALL
)
.
priority
(
Priority
.
HIGH
)
.
centerCrop
()
.
error
(
R
.
mipmap
.
ic_launcher_main
)
.
into
(
holder
.
image
);
}
catch
(
Exception
e
){
//do nothing
Toast
.
makeText
(
context
,
"Exception: "
+
e
.
getMessage
(),
Toast
.
LENGTH_SHORT
).
show
();
}
break
;
}
holder
.
ivCheckbox
.
setOnClickListener
(
new
View
.
OnClickListener
()
{
@Override
public
void
onClick
(
View
view
)
{
if
(
holder
.
ivCheckbox
.
isChecked
()){
mDuplicate
.
setChecked
(
true
);
}
else
{
mDuplicate
.
setChecked
(
false
);
}
// Toast.makeText(context,"Check checkbox ne",Toast.LENGTH_LONG).show();
}
});
holder
.
rlCard
.
setOnClickListener
(
new
View
.
OnClickListener
()
{
@Override
public
void
onClick
(
View
view
)
{
try
{
openFile
(
mDuplicate
);
}
catch
(
Exception
e
){
}
}
});
}
public
void
openFile
(
Duplicate
mDuplicate
){
Intent
createChooser
;
try
{
File
file
=
mDuplicate
.
getFile
();
if
(
mDuplicate
.
getTypeFile
()==
1
)
{
Intent
intent
=
new
Intent
();
intent
.
setAction
(
"android.intent.action.VIEW"
);
if
(
file
.
exists
())
{
if
(
Build
.
VERSION
.
SDK_INT
<
24
)
{
intent
.
setDataAndType
(
Uri
.
fromFile
(
file
),
"audio/*"
);
}
else
{
Uri
contentUri
=
FileProvider
.
getUriForFile
(
context
,
context
.
getPackageName
()
+
".provider"
,
file
);
context
.
grantUriPermission
(
context
.
getPackageName
(),
contentUri
,
1
);
intent
.
setDataAndType
(
contentUri
,
"audio/*"
);
intent
.
setFlags
(
Intent
.
FLAG_GRANT_READ_URI_PERMISSION
);
}
createChooser
=
Intent
.
createChooser
(
intent
,
"Complete action using"
);
context
.
startActivity
(
createChooser
);
}
return
;
}
else
if
(
mDuplicate
.
getTypeFile
()==
2
)
{
if
(
Build
.
VERSION
.
SDK_INT
<
24
){
Intent
intent2
=
new
Intent
(
"android.intent.action.VIEW"
);
intent2
.
setDataAndType
(
Uri
.
fromFile
(
mDuplicate
.
getFile
()),
"video/*"
);
createChooser
=
Intent
.
createChooser
(
intent2
,
"Complete action using"
);
}
else
{
Intent
intent4
=
new
Intent
(
"android.intent.action.VIEW"
);
Uri
contentUri2
=
FileProvider
.
getUriForFile
(
context
,
context
.
getPackageName
()
+
".provider"
,
file
);
context
.
grantUriPermission
(
context
.
getPackageName
(),
contentUri2
,
1
);
intent4
.
setType
(
"*/*"
);
if
(
Build
.
VERSION
.
SDK_INT
<
24
)
{
contentUri2
=
Uri
.
fromFile
(
file
);
}
intent4
.
setData
(
contentUri2
);
intent4
.
setFlags
(
1
);
createChooser
=
Intent
.
createChooser
(
intent4
,
"Complete action using"
);
}
}
else
if
(
Build
.
VERSION
.
SDK_INT
<
24
)
{
Uri
fromFile
=
Uri
.
fromFile
(
file
);
Intent
intent3
=
new
Intent
(
"android.intent.action.VIEW"
);
String
str
=
"*/*"
;
MimeTypeMap
singleton
=
MimeTypeMap
.
getSingleton
();
if
(
singleton
.
hasExtension
(
MimeTypeMap
.
getFileExtensionFromUrl
(
fromFile
.
toString
())))
{
str
=
singleton
.
getMimeTypeFromExtension
(
MimeTypeMap
.
getFileExtensionFromUrl
(
fromFile
.
toString
()));
}
intent3
.
setDataAndType
(
fromFile
,
str
);
context
.
startActivity
(
intent3
);
return
;
}
else
{
Intent
intent4
=
new
Intent
(
"android.intent.action.VIEW"
);
Uri
contentUri2
=
FileProvider
.
getUriForFile
(
context
,
context
.
getPackageName
()
+
".provider"
,
file
);
context
.
grantUriPermission
(
context
.
getPackageName
(),
contentUri2
,
1
);
intent4
.
setType
(
"*/*"
);
if
(
Build
.
VERSION
.
SDK_INT
<
24
)
{
contentUri2
=
Uri
.
fromFile
(
file
);
}
intent4
.
setData
(
contentUri2
);
intent4
.
setFlags
(
1
);
createChooser
=
Intent
.
createChooser
(
intent4
,
"Complete action using"
);
}
context
.
startActivity
(
createChooser
);
}
catch
(
Exception
e
)
{
}
}
// public void openFile(File url) {
//
// Uri uri = Uri.fromFile(url);
// String fileName = url.getName();
// Intent intent = new Intent(Intent.ACTION_VIEW);
// Uri contentUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", url);
// context.grantUriPermission(context.getPackageName(), contentUri, 1);
//// if (fileName.endsWith(".doc") || fileName.endsWith(".docx")) {
//// // Word document
//// intent.setDataAndType(uri, "application/msword");
//// } else if (fileName.endsWith(".pdf")) {
//// // PDF file
//// intent.setDataAndType(uri, "application/pdf");
//// } else if (fileName.endsWith(".ppt") || fileName.endsWith(".pptx")) {
//// // Powerpoint file
//// intent.setDataAndType(uri, "application/vnd.ms-powerpoint");
//// } else if (fileName.endsWith(".xls") || fileName.endsWith(".xlsx")) {
//// // Excel file
//// intent.setDataAndType(uri, "application/vnd.ms-excel");
//// } else if (fileName.endsWith(".zip") || fileName.endsWith(".rar")) {
//// // WAV audio file
//// intent.setDataAndType(uri, "application/x-wav");
//// } else if (fileName.endsWith(".rtf")) {
//// // RTF file
//// intent.setDataAndType(uri, "application/rtf");
//// } else if (fileName.endsWith(".wav") || fileName.endsWith(".mp3")) {
//// // WAV audio file
//// intent.setDataAndType(uri, "audio/x-wav");
//// } else if (fileName.endsWith(".gif")) {
//// // GIF file
//// intent.setDataAndType(uri, "image/gif");
//// } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") ||fileName.endsWith(".png")) {
//// // JPG file
//// intent.setDataAndType(uri, "image/jpeg");
//// } else if (fileName.endsWith(".txt")) {
//// // Text file
//// intent.setDataAndType(uri, "text/plain");
//// } else if (fileName.endsWith(".3gp") || fileName.endsWith(".mpg") || fileName.endsWith(".mpeg") || fileName.endsWith(".mpe") || fileName.endsWith(".mp4") || fileName.endsWith(".avi")) {
//// // Video files
//// intent.setDataAndType(uri, "video/*");
//// } else if (fileName.endsWith(".apk")) {
//// // GIF file
//// intent.setDataAndType(uri, "application/vnd.android.package-archive");
//// }else {
////
//// //if you want you can also define the intent type for any other file
//// //additionally use else clause below, to manage other unknown extensions
//// //in this case, Android will show all applications installed on the device
//// //so you can choose which application to use
//// intent.setDataAndType(uri, "*/*");
//// }
// intent.setDataAndType(uri, TypeOpen.getType(url));
// intent.setData(contentUri);
// intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// context.startActivity(Intent.createChooser(intent, "Complete action using"));
//
// }
public
String
getFileName
(
String
path
)
{
String
filename
=
path
.
substring
(
path
.
lastIndexOf
(
"/"
)+
1
);
return
filename
;
}
@Override
public
int
getItemCount
()
{
return
mDuplicates
.
size
();
}
}
video/app/src/main/java/com/mints/wisdomclean/ui/adapter/SectionRecyclerViewAdapter.java
deleted
100755 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
adapter
;
import
android.content.Context
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.widget.TextView
;
import
androidx.recyclerview.widget.GridLayoutManager
;
import
androidx.recyclerview.widget.LinearLayoutManager
;
import
androidx.recyclerview.widget.RecyclerView
;
import
com.mints.wisdomclean.R
;
import
com.mints.wisdomclean.mvp.model.DataModel
;
import
com.mints.wisdomclean.ui.widgets.RecyclerViewType
;
import
java.util.ArrayList
;
/**
* Created by sonu on 24/07/17.
*/
public
class
SectionRecyclerViewAdapter
extends
RecyclerView
.
Adapter
<
SectionRecyclerViewAdapter
.
SectionViewHolder
>
{
class
SectionViewHolder
extends
RecyclerView
.
ViewHolder
{
private
TextView
sectionLabel
,
showAllButton
;
private
RecyclerView
itemRecyclerView
;
public
SectionViewHolder
(
View
itemView
)
{
super
(
itemView
);
sectionLabel
=
(
TextView
)
itemView
.
findViewById
(
R
.
id
.
section_label
);
itemRecyclerView
=
(
RecyclerView
)
itemView
.
findViewById
(
R
.
id
.
item_recycler_view
);
}
}
private
Context
context
;
private
RecyclerViewType
recyclerViewType
;
private
ArrayList
<
DataModel
>
sectionModelArrayList
;
public
SectionRecyclerViewAdapter
(
Context
context
,
RecyclerViewType
recyclerViewType
,
ArrayList
<
DataModel
>
sectionModelArrayList
)
{
this
.
context
=
context
;
this
.
recyclerViewType
=
recyclerViewType
;
this
.
sectionModelArrayList
=
sectionModelArrayList
;
}
@Override
public
SectionViewHolder
onCreateViewHolder
(
ViewGroup
parent
,
int
viewType
)
{
View
view
=
LayoutInflater
.
from
(
parent
.
getContext
()).
inflate
(
R
.
layout
.
section_custom_row_dupicate
,
parent
,
false
);
return
new
SectionViewHolder
(
view
);
}
@Override
public
void
onBindViewHolder
(
SectionViewHolder
holder
,
int
position
)
{
final
DataModel
mDataModel
=
sectionModelArrayList
.
get
(
position
);
holder
.
sectionLabel
.
setText
(
mDataModel
.
getTitleGroup
());
//recycler view for items
holder
.
itemRecyclerView
.
setHasFixedSize
(
true
);
holder
.
itemRecyclerView
.
setNestedScrollingEnabled
(
false
);
/* set layout manager on basis of recyclerview enum type */
switch
(
recyclerViewType
)
{
case
LINEAR_VERTICAL:
LinearLayoutManager
linearLayoutManager
=
new
LinearLayoutManager
(
context
,
RecyclerView
.
VERTICAL
,
false
);
holder
.
itemRecyclerView
.
setLayoutManager
(
linearLayoutManager
);
break
;
case
LINEAR_HORIZONTAL:
LinearLayoutManager
linearLayoutManager1
=
new
LinearLayoutManager
(
context
,
RecyclerView
.
HORIZONTAL
,
false
);
holder
.
itemRecyclerView
.
setLayoutManager
(
linearLayoutManager1
);
break
;
case
GRID:
GridLayoutManager
gridLayoutManager
=
new
GridLayoutManager
(
context
,
3
);
holder
.
itemRecyclerView
.
setLayoutManager
(
gridLayoutManager
);
break
;
}
ItemRecyclerViewAdapter
adapter
=
new
ItemRecyclerViewAdapter
(
context
,
mDataModel
.
getListDuplicate
());
holder
.
itemRecyclerView
.
setAdapter
(
adapter
);
//show toast on click of show all button
// holder.showAllButton.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// Toast.makeText(context, "You clicked on Show All of : " + mDataModel.getTitleGroup() ,Toast.LENGTH_SHORT).show();
// }
// });
}
@Override
public
int
getItemCount
()
{
return
sectionModelArrayList
.
size
();
}
}
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/BgChooseView.kt
deleted
100644 → 0
View file @
1af1a0f7
package
com.mints.wisdomclean.ui.widgets
import
android.content.Context
import
android.graphics.*
import
android.util.AttributeSet
import
android.view.View
import
com.mints.wisdomclean.R
class
BgChooseView
:
View
{
constructor
(
context
:
Context
)
:
this
(
context
,
null
)
constructor
(
context
:
Context
,
attributeSet
:
AttributeSet
?)
:
this
(
context
,
attributeSet
,
0
)
constructor
(
context
:
Context
,
attributeSet
:
AttributeSet
?,
defStyleAttr
:
Int
)
:
super
(
context
,
attributeSet
,
defStyleAttr
)
companion
object
{
const
val
BG_COLOR_RED
=
"#FF0000"
const
val
BG_COLOR_BLUE
=
"#00BFF3"
const
val
BG_COLOR_WHITE
=
"#FFFFFF"
const
val
BG_COLOR_BLUE_GRADUAL
=
"BLUE_GRADUAL"
}
private
var
mColor
:
String
=
BG_COLOR_BLUE
private
var
mPaint
:
Paint
=
Paint
(
Paint
.
ANTI_ALIAS_FLAG
)
private
var
mIsChecked
:
Boolean
=
false
private
val
mGary
=
context
.
resources
.
getColor
(
R
.
color
.
id_photo_gray
)
private
var
mWidth
=
0f
private
var
mHeight
=
0f
init
{
mPaint
.
strokeWidth
=
6f
}
fun
setColor
(
color
:
String
)
{
mColor
=
color
invalidate
()
}
fun
setChecked
(
isChecked
:
Boolean
)
{
mIsChecked
=
isChecked
invalidate
()
}
override
fun
onDraw
(
canvas
:
Canvas
)
{
super
.
onDraw
(
canvas
)
mPaint
.
shader
=
null
mPaint
.
color
=
mGary
mPaint
.
style
=
Paint
.
Style
.
FILL
canvas
.
drawCircle
(
mWidth
/
2
,
mHeight
/
2
,
mWidth
/
2
,
mPaint
)
if
(
mColor
==
BG_COLOR_BLUE_GRADUAL
)
{
val
colors
=
IntArray
(
2
)
val
positions
=
FloatArray
(
2
)
// 第1个点
colors
[
0
]
=
Color
.
parseColor
(
BG_COLOR_BLUE
)
positions
[
0
]
=
0f
// 第2个点
colors
[
1
]
=
Color
.
WHITE
positions
[
1
]
=
1f
val
shader
=
LinearGradient
(
0f
,
0f
,
0f
,
mHeight
,
colors
,
positions
,
Shader
.
TileMode
.
MIRROR
)
mPaint
.
shader
=
shader
}
else
{
mPaint
.
shader
=
null
mPaint
.
color
=
Color
.
parseColor
(
mColor
)
mPaint
.
style
=
Paint
.
Style
.
FILL
}
canvas
.
drawCircle
(
mWidth
/
2
,
mHeight
/
2
,
mWidth
/
2
-
12
,
mPaint
)
if
(
mIsChecked
)
{
mPaint
.
style
=
Paint
.
Style
.
STROKE
mPaint
.
color
=
Color
.
WHITE
if
(
mColor
==
BG_COLOR_WHITE
)
{
mPaint
.
color
=
mGary
}
canvas
.
translate
(
mWidth
/
2
-
25
,
mHeight
/
2
)
val
path
=
Path
()
path
.
lineTo
(
25f
,
20f
)
path
.
lineTo
(
50f
,
-
20f
)
canvas
.
drawPath
(
path
,
mPaint
)
}
}
override
fun
onMeasure
(
widthMeasureSpec
:
Int
,
heightMeasureSpec
:
Int
)
{
super
.
onMeasure
(
widthMeasureSpec
,
heightMeasureSpec
)
val
minimumWidth
=
suggestedMinimumWidth
val
minimumHeight
=
suggestedMinimumHeight
val
width
=
measureWidth
(
minimumWidth
,
widthMeasureSpec
)
val
height
=
measureHeight
(
minimumHeight
,
heightMeasureSpec
)
mWidth
=
width
.
toFloat
()
mHeight
=
height
.
toFloat
()
setMeasuredDimension
(
width
,
height
)
}
private
fun
measureWidth
(
defaultWidth
:
Int
,
measureSpec
:
Int
):
Int
{
var
measureWidth
=
defaultWidth
val
specMode
=
MeasureSpec
.
getMode
(
measureSpec
)
val
specSize
=
MeasureSpec
.
getSize
(
measureSpec
)
when
(
specMode
)
{
MeasureSpec
.
AT_MOST
->
{
measureWidth
=
specSize
+
paddingLeft
+
paddingRight
}
MeasureSpec
.
EXACTLY
->
{
measureWidth
=
specSize
}
MeasureSpec
.
UNSPECIFIED
->
{
measureWidth
=
defaultWidth
.
coerceAtLeast
(
specSize
)
}
}
return
measureWidth
}
private
fun
measureHeight
(
defaultHeight
:
Int
,
measureSpec
:
Int
):
Int
{
var
measureHeight
=
defaultHeight
val
specMode
=
MeasureSpec
.
getMode
(
measureSpec
)
val
specSize
=
MeasureSpec
.
getSize
(
measureSpec
)
when
(
specMode
)
{
MeasureSpec
.
AT_MOST
->
{
measureHeight
=
specSize
+
paddingTop
+
paddingBottom
}
MeasureSpec
.
EXACTLY
->
{
measureHeight
=
specSize
}
MeasureSpec
.
UNSPECIFIED
->
{
measureHeight
=
defaultHeight
.
coerceAtLeast
(
specSize
)
}
}
return
measureHeight
}
}
\ No newline at end of file
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/ButtonView.java
deleted
100644 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
widgets
;
import
android.animation.Animator
;
import
android.animation.AnimatorListenerAdapter
;
import
android.animation.AnimatorSet
;
import
android.animation.ArgbEvaluator
;
import
android.animation.ObjectAnimator
;
import
android.content.Context
;
import
android.content.res.TypedArray
;
import
android.graphics.Canvas
;
import
android.graphics.Color
;
import
android.graphics.Paint
;
import
android.graphics.RectF
;
import
android.graphics.Paint.Style
;
import
android.os.Handler
;
import
android.util.AttributeSet
;
import
android.util.Property
;
import
android.util.TypedValue
;
import
android.view.MotionEvent
;
import
android.view.VelocityTracker
;
import
android.view.View
;
import
android.view.ViewConfiguration
;
import
android.view.animation.DecelerateInterpolator
;
import
android.widget.Scroller
;
import
com.mints.wisdomclean.R
;
/*
* findViewById返回Null..
* 自定义View需要重写两个参数的构造
* 并且调用super(context, attrs);方法
* 为什么调用三个的构造却不行。
* 事实证明调用三个的构造函数也是可以的 不过defStyleAttr必须设置为0 而不是-1;
*/
public
class
ButtonView
extends
View
{
int
mWidth
=(
int
)
TypedValue
.
applyDimension
(
TypedValue
.
COMPLEX_UNIT_DIP
,
50
,
this
.
getResources
().
getDisplayMetrics
());
int
onBackground
;
int
offBackground
;
int
time
;
float
layout_width
;
float
layout_height
;
Paint
mPaint
;
Scroller
mScroller
;
float
lastX
;
VelocityTracker
mVelocity
;
ViewConfiguration
mConfig
;
static
final
int
RADIO
=
50
;
int
circleX
=
0
;
boolean
isOn
=
false
;
//是否开启了
AnimatorSet
set
;
int
circleColor
;
private
Property
<
ButtonView
,
Integer
>
mColor
=
new
Property
<
ButtonView
,
Integer
>(
Integer
.
class
,
"currentColor"
)
{
@Override
public
Integer
get
(
ButtonView
object
)
{
return
object
.
currentColor
;
}
@Override
public
void
set
(
ButtonView
object
,
Integer
value
)
{
// TODO Auto-generated method stub
object
.
currentColor
=
value
;
invalidate
();
}
};
private
Property
<
ButtonView
,
Integer
>
mMove
=
new
Property
<
ButtonView
,
Integer
>(
Integer
.
class
,
"current_move"
)
{
@Override
public
Integer
get
(
ButtonView
object
)
{
// TODO Auto-generated method stub
return
object
.
current_move
;
}
@Override
public
void
set
(
ButtonView
object
,
Integer
value
)
{
// TODO Auto-generated method stub
object
.
current_move
=
value
;
}
};
boolean
isAnimatorStart
=
false
;
@SuppressWarnings
(
"unchecked"
)
public
void
startAnimator
(
int
start
,
int
end
,
int
startColor
,
int
endColor
,
int
duration
){
set
=
new
AnimatorSet
();
set
.
playTogether
(
ObjectAnimator
.
ofInt
(
this
,
mMove
,
start
,
end
),
ObjectAnimator
.
ofObject
(
this
,
mColor
,
new
ArgbEvaluator
(),
startColor
,
endColor
));
set
.
setDuration
(
duration
);
set
.
addListener
(
new
AnimatorListenerAdapter
()
{
@Override
public
void
onAnimationStart
(
Animator
animation
)
{
// TODO Auto-generated method stub
isAnimatorStart
=
true
;
}
@Override
public
void
onAnimationEnd
(
Animator
animation
)
{
isAnimatorStart
=
false
;
if
(
changeListener
!=
null
){
changeListener
.
onChange
(
isOn
);
}
}
});
set
.
setInterpolator
(
new
DecelerateInterpolator
());
set
.
start
();
}
public
ButtonView
(
Context
context
)
{
this
(
context
,
null
);
}
public
ButtonView
(
Context
context
,
AttributeSet
attrs
,
int
defStyleAttr
)
{
super
(
context
,
attrs
,
defStyleAttr
);
// TODO Auto-generated constructor stub
}
public
ButtonView
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
TypedArray
a
=
context
.
obtainStyledAttributes
(
attrs
,
R
.
styleable
.
buttonView
);
offBackground
=
a
.
getColor
(
R
.
styleable
.
buttonView_offBackground
,
Color
.
parseColor
(
"#F6F6F6"
));
onBackground
=
a
.
getColor
(
R
.
styleable
.
buttonView_onBackground
,
Color
.
parseColor
(
"#38DA4E"
));
time
=
a
.
getInteger
(
R
.
styleable
.
buttonView_time
,
500
);
circleColor
=
a
.
getColor
(
R
.
styleable
.
buttonView_circleColor
,
Color
.
parseColor
(
"#D7D7D7"
));
layout_height
=
a
.
getDimension
(
R
.
styleable
.
buttonView_layout_height
,
TypedValue
.
applyDimension
(
TypedValue
.
COMPLEX_UNIT_DIP
,
30
,
context
.
getResources
().
getDisplayMetrics
()));
layout_width
=
a
.
getDimension
(
R
.
styleable
.
buttonView_layout_width
,
TypedValue
.
applyDimension
(
TypedValue
.
COMPLEX_UNIT_DIP
,
60
,
context
.
getResources
().
getDisplayMetrics
()));
mPaint
=
new
Paint
();
mPaint
.
setAntiAlias
(
true
);
mPaint
.
setColor
(
offBackground
);
mPaint
.
setDither
(
true
);
mScroller
=
new
Scroller
(
context
);
mConfig
=
ViewConfiguration
.
get
(
context
);
}
@Override
public
void
computeScroll
()
{
// TODO Auto-generated method stub
if
(
mScroller
.
computeScrollOffset
()){
current_move
=
mScroller
.
getCurrX
();
invalidate
();
}
}
int
min_move
=
circleX
+
RADIO
;
int
max_move
=
0
;
@Override
protected
void
onMeasure
(
int
widthMeasureSpec
,
int
heightMeasureSpec
)
{
int
heightMode
=
MeasureSpec
.
getMode
(
heightMeasureSpec
);
int
heightSize
=
MeasureSpec
.
getSize
(
heightMeasureSpec
);
int
widthMode
=
MeasureSpec
.
getMode
(
widthMeasureSpec
);
int
widthSize
=
MeasureSpec
.
getSize
(
widthMeasureSpec
);
int
measureView_width
=
measureView
(
widthMode
,
widthSize
,
layout_width
);
int
measureView_height
=
measureView
(
heightMode
,
heightSize
,
layout_height
);
//最大移动位置
max_move
=(
int
)
(
layout_width
-
RADIO
-
circleX
);
//最小移动位置
setMeasuredDimension
(
measureView_width
,
measureView_height
);
}
private
int
measureView
(
int
mode
,
int
size
,
float
defaultSize
){
switch
(
mode
)
{
case
MeasureSpec
.
UNSPECIFIED
:
case
MeasureSpec
.
AT_MOST
:
if
(
size
>
defaultSize
){
size
=(
int
)
Math
.
ceil
(
defaultSize
);
}
return
MeasureSpec
.
makeMeasureSpec
(
size
,
MeasureSpec
.
EXACTLY
);
case
MeasureSpec
.
EXACTLY
:
return
MeasureSpec
.
makeMeasureSpec
(
size
,
MeasureSpec
.
EXACTLY
);
}
return
-
1
;
}
int
current_move
=
min_move
;
@Override
protected
void
onDraw
(
Canvas
canvas
)
{
// TODO Auto-generated method stub
super
.
onDraw
(
canvas
);
mPaint
.
reset
();
mPaint
.
setAntiAlias
(
true
);
mPaint
.
setColor
(
currentColor
);
mPaint
.
setDither
(
true
);
canvas
.
drawRoundRect
(
new
RectF
(
0
,
0
,
layout_width
,
layout_height
),
RADIO
,
RADIO
,
mPaint
);
mPaint
.
setStyle
(
Style
.
STROKE
);
mPaint
.
setColor
(
Color
.
parseColor
(
"#DADADA"
));
canvas
.
drawRoundRect
(
new
RectF
(
0
,
0
,
layout_width
,
layout_height
),
RADIO
,
RADIO
,
mPaint
);
mPaint
.
setStyle
(
Style
.
FILL
);
mPaint
.
setColor
(
circleColor
);
canvas
.
drawCircle
(
current_move
,
layout_height
/
2
,
layout_height
/
2
-
4
,
mPaint
);
}
float
x
=
0
;
float
y
=
0
;
boolean
isClick
=
false
;
Handler
mHandler
=
new
Handler
();
/**
* 当前颜色
*/
int
currentColor
=
offBackground
;
@Override
public
boolean
onTouchEvent
(
MotionEvent
event
)
{
// TODO Auto-generated method stub
switch
(
event
.
getAction
())
{
case
MotionEvent
.
ACTION_UP
:
mHandler
.
removeCallbacks
(
clickRunable
);
if
(
isClick
){
if
(
isOn
){
//开启则关闭
if
(!
isAnimatorStart
){
startAnimator
(
max_move
,
min_move
,
onBackground
,
offBackground
,
time
);
isOn
=
false
;
}
// if(mScroller.isFinished()){
// mScroller.startScroll(max_move, (int)this.getY(), min_move-max_move,(int)this.getY(), 1000);
// currentColor=offBackground;
// invalidate();
// isOn=false;
// }
}
else
{
//否则开启
if
(!
isAnimatorStart
){
startAnimator
(
min_move
,
max_move
,
offBackground
,
onBackground
,
time
);
isOn
=
true
;
}
//if(mScroller.isFinished()){
// mScroller.startScroll(min_move, (int)this.getY(), max_move-min_move,(int)this.getY(), 1000);
// currentColor=onBackground;
// invalidate();
// isOn=true;
//}
}
if
(
click
!=
null
){
click
.
onClick
(
this
);
}
//Toast.makeText(getContext(), "单击事件", Toast.LENGTH_SHORT).show();
}
break
;
case
MotionEvent
.
ACTION_DOWN
:
x
=
event
.
getX
();
y
=
event
.
getY
();
isClick
=
false
;
mHandler
.
postDelayed
(
clickRunable
,
mConfig
.
getScaledTouchSlop
());
break
;
case
MotionEvent
.
ACTION_MOVE
:
float
x
=
event
.
getX
();
float
y
=
event
.
getY
();
isMove
(
x
,
y
,
mConfig
.
getScaledTouchSlop
());
break
;
default
:
break
;
}
return
true
;
}
private
void
isMove
(
float
x
,
float
y
,
int
touchSlop
){
if
(
Math
.
abs
(
this
.
x
-
x
)>
touchSlop
||
Math
.
abs
(
this
.
y
-
y
)>
touchSlop
){
isClick
=
false
;
}
}
private
onChangeListener
changeListener
;
private
onClickListener
click
;
public
void
setClick
(
onClickListener
click
)
{
this
.
click
=
click
;
}
public
void
setChangeListener
(
onChangeListener
changeListener
)
{
this
.
changeListener
=
changeListener
;
}
public
interface
onChangeListener
{
void
onChange
(
boolean
state
);
}
public
interface
onClickListener
{
void
onClick
(
View
view
);
}
ClickRunAble
clickRunable
=
new
ClickRunAble
();
class
ClickRunAble
implements
Runnable
{
@Override
public
void
run
()
{
// TODO Auto-generated method stub
isClick
=
true
;
}
}
}
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/CustomProgressDialog.java
deleted
100755 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
widgets
;
import
android.app.ProgressDialog
;
import
android.content.Context
;
public
class
CustomProgressDialog
extends
ProgressDialog
{
public
CustomProgressDialog
(
Context
context
)
{
super
(
context
);
setMessage
(
"压缩中..."
);
setMax
(
100
);
setProgressStyle
(
ProgressDialog
.
STYLE_HORIZONTAL
);
setCanceledOnTouchOutside
(
false
);
setCancelable
(
false
);
}
@Override
public
void
dismiss
()
{
super
.
dismiss
();
setProgress
(
0
);
}
@Override
public
void
cancel
()
{
super
.
cancel
();
setProgress
(
0
);
}
}
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/DashboradView.kt
deleted
100644 → 0
View file @
1af1a0f7
@file
:
Suppress
(
"SpellCheckingInspection"
)
package
com.mints.wisdomclean.ui.widgets
import
android.annotation.SuppressLint
import
android.content.Context
import
android.content.res.Resources
import
android.graphics.*
import
android.text.TextUtils
import
android.util.AttributeSet
import
android.util.TypedValue
import
android.view.View
import
androidx.core.content.ContextCompat
import
com.mints.wisdomclean.R
import
kotlin.math.cos
import
kotlin.math.sin
private
val
TAG
=
DashboradView
::
class
.
java
.
simpleName
/**
*
* @author jyx
* @date 2021/6/4
* @des 测速仪表盘
*/
class
DashboradView
:
View
{
/** 缺省值 */
private
var
mRadius
=
0
// 扇形半径
private
var
mStartAngle
=
150f
// 起始角度,180-30度(左边平行夹角30度)
private
var
mSweepAngle
=
240f
// 绘制角度,360+30度 = 150+240度)
private
var
mMin
=
0
// 最小值 0Mb/s
private
var
mMax
=
100
// 最大值 1000Mb/s
private
var
mSection
=
8
// 值域(mMax-mMin)等分份数
private
var
mPortion
=
4
// 一个mSection等分份数
private
var
mHeaderText
=
""
// 表头 Mbs
private
var
mVelocity
=
mMin
// 实时速度
private
var
mSpeed
=
mMin
.
toFloat
()
// 实时速度
private
var
mStrokeWidth
=
0f
// 画笔宽度
private
var
mLength1
=
0
// 长刻度的相对圆弧的长度
private
var
mLength2
=
0
// 刻度读数顶部的相对圆弧的长度
private
var
mPLRadius
=
0
// 指针长半径
private
var
mPSRadius
=
0
// 指针短半径
private
var
mPadding
=
0
private
var
mCenterX
=
0f
// 坐标轴X
private
var
mCenterY
=
0f
// 坐标轴Y
private
var
mPaint
:
Paint
private
var
mRectFArc
:
RectF
private
var
mPath
:
Path
private
var
mRectFInnerArc
:
RectF
private
var
mRectText
:
Rect
private
var
mTexts
:
Array
<
String
>
private
var
mReadSpeed
=
0f
// 真实进度
private
var
mReadSpeedStr
=
"KB/s"
// 真实进度单位
// private var mColors: IntArray
private
var
mGradient
:
Shader
?
=
null
private
var
mContext
:
Context
=
context
constructor
(
ctx
:
Context
)
:
this
(
ctx
,
null
)
constructor
(
ctx
:
Context
,
attrs
:
AttributeSet
?)
:
this
(
ctx
,
attrs
,
0
)
constructor
(
ctx
:
Context
,
attrs
:
AttributeSet
?,
defStyleAttr
:
Int
)
:
super
(
ctx
,
attrs
,
defStyleAttr
)
init
{
mStrokeWidth
=
dp2px
(
3
).
toFloat
()
mLength1
=
(
dp2px
(
8
)
+
mStrokeWidth
).
toInt
()
mLength2
=
mLength1
+
dp2px
(
4
)
mPaint
=
Paint
()
mPaint
.
isAntiAlias
=
true
mPaint
.
strokeCap
=
Paint
.
Cap
.
ROUND
mRectFArc
=
RectF
()
mPath
=
Path
()
mRectFInnerArc
=
RectF
()
mRectText
=
Rect
()
mTexts
=
arrayOf
(
"0M"
,
"10M"
,
"20M"
,
"50M"
,
"100M"
,
"200M"
,
"500M"
,
"800M"
,
"1000M"
)
// for (i in 0..mSection + 1) {// 需要显示mSection + 1个刻度读数
// val n = (mMax - mMin) / mSection
// mTexts[i] = "" + (mMin + i * n)
// }
// mTexts[0] = "0M"
// mTexts[1] = "1M"
// mTexts[2] = "2M"
// mTexts[3] = "5M"
// mTexts[4] = "10M"
// mTexts[5] = "20M"
// mTexts[6] = "50M"
// mTexts[7] = "80M"
// mTexts[8] = "100M"
// mTexts[9] = "1000M"
// mColors = intArrayOf(
// ContextCompat.getColor(mContext, R.color.color_4BB93F),
// ContextCompat.getColor(mContext, R.color.color_fcf16e),
// ContextCompat.getColor(mContext, R.color.red)
// )
}
override
fun
onMeasure
(
widthMeasureSpec
:
Int
,
heightMeasureSpec
:
Int
)
{
super
.
onMeasure
(
widthMeasureSpec
,
heightMeasureSpec
)
mPadding
=
paddingLeft
.
coerceAtLeast
(
paddingTop
)
.
coerceAtLeast
(
paddingRight
.
coerceAtLeast
(
paddingBottom
))
setPadding
(
mPadding
,
mPadding
,
mPadding
,
mPadding
)
val
width
=
resolveSize
(
dp2px
(
230
),
widthMeasureSpec
)
mRadius
=
((
width
-
mPadding
*
2
-
mStrokeWidth
*
2
)
/
2
).
toInt
()
// 由起始角度确定的高度
val
point1
=
getCoordinatePoint
(
mRadius
,
mStartAngle
)
// 由结束角度确定的高度
// val point2 = getCoordinatePoint(mRadius, mStartAngle + mSweepAngle)
// val height =
// (point1[1] + mRadius + mStrokeWidth * 2).coerceAtLeast(point2[1] + mRadius + mStrokeWidth * 2)
// .toInt()
// LogUtil.d(TAG, "mRadius -> " + mRadius + " mStrokeWidth -> " + mStrokeWidth)
// LogUtil.d(TAG, "point1 -> " + point1[1] + " point2 -> " + point2[1])
// LogUtil.d(TAG, "width -> " + width + " height -> " + height)
val
height
=
(
point1
[
1
]
+
mStrokeWidth
*
2
+
20
).
toInt
()
setMeasuredDimension
(
width
,
height
)
mCenterX
=
measuredWidth
/
2f
mCenterY
=
measuredWidth
/
2f
mRectFArc
.
set
(
paddingLeft
+
mStrokeWidth
,
paddingTop
+
mStrokeWidth
,
measuredWidth
-
paddingRight
-
mStrokeWidth
,
measuredWidth
-
paddingBottom
-
mStrokeWidth
)
mPaint
.
textSize
=
sp2px
(
14
).
toFloat
()
mPaint
.
getTextBounds
(
"0"
,
0
,
"0"
.
length
,
mRectText
)
mRectFInnerArc
.
set
(
(
paddingLeft
+
mLength2
+
mRectText
.
height
()
+
dp2px
(
30
)).
toFloat
(),
(
paddingTop
+
mLength2
+
mRectText
.
height
()
+
dp2px
(
30
)).
toFloat
(),
(
measuredWidth
-
paddingRight
-
mLength2
-
mRectText
.
height
()
-
dp2px
(
30
)).
toFloat
(),
(
measuredWidth
-
paddingBottom
-
mLength2
-
mRectText
.
height
()
-
dp2px
(
30
)).
toFloat
()
)
mPLRadius
=
mRadius
-
dp2px
(
35
)
mPSRadius
=
dp2px
(
25
)
}
@SuppressLint
(
"DrawAllocation"
)
override
fun
onDraw
(
canvas
:
Canvas
)
{
super
.
onDraw
(
canvas
)
setLayerType
(
LAYER_TYPE_SOFTWARE
,
null
);
/** 画测速仪背景色 */
// canvas.drawColor(mContext.getColor(R.color.color_dark))
/** 画圆弧 最外层 */
mPaint
.
style
=
Paint
.
Style
.
STROKE
mPaint
.
strokeWidth
=
mStrokeWidth
mGradient
=
LinearGradient
(
0f
,
0f
,
mRectFArc
.
right
,
mRectFArc
.
bottom
,
Color
.
parseColor
(
"#8275DF"
),
Color
.
parseColor
(
"#25C7AD"
),
Shader
.
TileMode
.
MIRROR
)
mPaint
.
shader
=
mGradient
canvas
.
drawArc
(
mRectFArc
,
mStartAngle
,
mSweepAngle
,
false
,
mPaint
)
mPaint
.
shader
=
null
val
mRectFArc1
=
RectF
(
mRectFArc
.
left
+
dp2px
(
2
),
mRectFArc
.
top
+
dp2px
(
2
),
mRectFArc
.
right
-
dp2px
(
2
),
mRectFArc
.
bottom
-
dp2px
(
2
)
)
mPaint
.
color
=
Color
.
parseColor
(
"#E2E2E2"
)
canvas
.
drawArc
(
mRectFArc1
,
mStartAngle
,
mSweepAngle
,
false
,
mPaint
)
/**
* 画长刻度
* 画好起始角度的一条刻度后通过canvas绕着原点旋转来画剩下的长刻度
*/
val
cos
=
cos
(
Math
.
toRadians
((
mStartAngle
-
180
).
toDouble
()))
val
sin
=
sin
(
Math
.
toRadians
((
mStartAngle
-
180
).
toDouble
()))
val
x0
=
(
mPadding
+
mStrokeWidth
+
mRadius
*
(
1
-
cos
)).
toFloat
()
val
y0
=
(
mPadding
+
mStrokeWidth
+
mRadius
*
(
1
-
sin
)).
toFloat
()
val
x1
=
(
mPadding
+
mStrokeWidth
+
mRadius
-
(
mRadius
-
mLength1
)
*
cos
).
toFloat
()
val
y1
=
(
mPadding
+
mStrokeWidth
+
mRadius
-
(
mRadius
-
mLength1
)
*
sin
).
toFloat
()
canvas
.
save
()
mPaint
.
color
=
Color
.
parseColor
(
"#8275DF"
)
canvas
.
drawLine
(
x0
,
y0
,
x0
-
(
x1
-
x0
),
y0
-
(
y1
-
y0
),
mPaint
)
// var angle = mSweepAngle * 1f / mSection
// for (i in 0..mSection - 1) {
// canvas.rotate(angle, mCenterX, mCenterY)
// canvas.drawLine(x0, y0, x1, y1, mPaint)
// }
canvas
.
rotate
(
mSweepAngle
,
mCenterX
,
mCenterY
)
mPaint
.
color
=
Color
.
parseColor
(
"#25C7AD"
)
canvas
.
drawLine
(
x0
,
y0
,
x0
-
(
x1
-
x0
),
y0
-
(
y1
-
y0
),
mPaint
)
canvas
.
restore
()
/**
* 画短刻度
* 同样采用canvas的旋转原理
*/
// canvas.save()
// mPaint.strokeWidth = mStrokeWidth / 2f
// val x2 = (mPadding + mStrokeWidth + mRadius - (mRadius - 2 * mLength1 / 3f) * cos).toFloat()
// val y2 = (mPadding + mStrokeWidth + mRadius - (mRadius - 2 * mLength1 / 3f) * sin).toFloat()
// canvas.drawLine(x0, y0, x2, y2, mPaint)
// angle = mSweepAngle * 1f / (mSection * mPortion)
// for (i in 1..(mSection * mPortion - 1)) {
// canvas.rotate(angle, mCenterX, mCenterY)
// if (i % mPortion == 0) {
// continue
// }
// canvas.drawLine(x0, y0, x2, y2, mPaint)
// }
// canvas.restore()
/**
* 画长刻度读数
*/
mPaint
.
textSize
=
sp2px
(
14
).
toFloat
()
mPaint
.
style
=
Paint
.
Style
.
FILL
mPaint
.
color
=
ContextCompat
.
getColor
(
mContext
,
R
.
color
.
gray
)
var
α
:
Float
var
p
:
Array
<
Float
>
val
angle
=
mSweepAngle
*
1f
/
mSection
for
(
i
in
0
..
mSection
)
{
α
=
mStartAngle
+
angle
*
i
p
=
getCoordinatePoint
(
mRadius
-
mLength2
,
α
)
if
(
α
%
360
>
135
&&
α
%
360
<
225
)
{
mPaint
.
textAlign
=
Paint
.
Align
.
LEFT
}
else
if
((
α
%
360
>=
0
&&
α
%
360
<
45
)
||
(
α
%
360
>
315
&&
α
%
360
<=
360
))
{
mPaint
.
textAlign
=
Paint
.
Align
.
RIGHT
}
else
{
mPaint
.
textAlign
=
Paint
.
Align
.
CENTER
}
if
(!
TextUtils
.
isEmpty
(
mHeaderText
))
{
mPaint
.
getTextBounds
(
mHeaderText
,
0
,
mTexts
[
i
].
length
,
mRectText
)
}
val
txtH
=
mRectText
.
height
()
if
(
i
<=
1
||
i
>=
mSection
-
1
)
{
canvas
.
drawText
(
mTexts
[
i
],
p
[
0
],
(
p
[
1
]
+
txtH
/
2
),
mPaint
)
}
else
if
(
i
==
3
)
{
// LogUtil.d(" α -> " + α)
// LogUtil.d("AAA ->" + mTexts[i] + "x -> " + p[0] + "y -> " + p[1])
canvas
.
drawText
(
mTexts
[
i
],
p
[
0
]
+
txtH
/
2
,
p
[
1
]
+
txtH
,
mPaint
)
}
else
if
(
i
==
mSection
-
3
)
{
// LogUtil.d(" α -> " + α)
// LogUtil.d("BBB ->" + mTexts[i] + "x -> " + p[0] + "y -> " + p[1])
canvas
.
drawText
(
mTexts
[
i
],
p
[
0
]
-
txtH
/
2
,
p
[
1
]
+
txtH
,
mPaint
)
}
else
{
canvas
.
drawText
(
mTexts
[
i
],
p
[
0
],
(
p
[
1
]
+
txtH
),
mPaint
)
}
}
mPaint
.
color
=
ContextCompat
.
getColor
(
mContext
,
R
.
color
.
gray
)
mPaint
.
strokeCap
=
Paint
.
Cap
.
ROUND
mPaint
.
style
=
Paint
.
Style
.
FILL
mPaint
.
shader
=
null
/** 画表头 没有表头就不画 */
if
(!
TextUtils
.
isEmpty
(
mHeaderText
))
{
mPaint
.
textSize
=
sp2px
(
14
).
toFloat
()
mPaint
.
textAlign
=
Paint
.
Align
.
CENTER
mPaint
.
getTextBounds
(
mHeaderText
,
0
,
mHeaderText
.
length
,
mRectText
)
canvas
.
drawText
(
mHeaderText
,
mCenterX
,
mCenterY
-
mRectText
.
height
()
*
3
,
mPaint
)
}
// mCenterY += 20
val
a
=
mStartAngle
+
mSweepAngle
*
(
mVelocity
-
mMin
)
/
(
mMax
-
mMin
)
// 指针与水平线夹角
val
d
=
dp2px
(
10
)
// 指针由两个等腰三角形构成,d为共底边长的一半
mPath
.
reset
()
val
p1
=
getCoordinatePoint
(
mPLRadius
,
a
)
mPath
.
moveTo
(
p1
[
0
],
p1
[
1
])
val
p2
=
getCoordinatePoint
(
d
,
a
-
90
)
mPath
.
lineTo
(
p2
[
0
],
p2
[
1
])
val
p3
=
getCoordinatePoint
(
d
,
a
+
90
)
mPath
.
lineTo
(
p3
[
0
],
p3
[
1
])
mPath
.
close
()
mGradient
=
LinearGradient
(
p1
[
0
],
p1
[
1
],
p3
[
0
],
p3
[
1
],
Color
.
parseColor
(
"#FE9D75"
),
Color
.
TRANSPARENT
,
Shader
.
TileMode
.
MIRROR
)
mPaint
.
shader
=
mGradient
canvas
.
drawPath
(
mPath
,
mPaint
)
mPaint
.
shader
=
null
/** 画指针 */
mPaint
.
color
=
Color
.
WHITE
mPaint
.
setShadowLayer
(
10f
,
0f
,
0f
,
Color
.
parseColor
(
"#E2E2E2"
));
canvas
.
drawCircle
(
mCenterX
,
mCenterY
,
dp2px
(
60
).
toFloat
(),
mPaint
)
//中心圆
// 去除阴影
mPaint
.
setShadowLayer
(
0f
,
0f
,
0f
,
Color
.
GRAY
);
//
// mGradient = SweepGradient(
// 0f,
// 0f,
// Color.parseColor("#BEC2CC"),
// Color.TRANSPARENT,
// )
// mPaint.shader = mGradient
// mPaint.style = Paint.Style.STROKE
// mPaint.strokeWidth = dp2px(2).toFloat()
// canvas.drawCircle(mCenterX, mCenterY, dp2px(60).toFloat(), mPaint)//空心圆
// mPaint.shader = null
mPaint
.
style
=
Paint
.
Style
.
FILL
mPaint
.
textSize
=
sp2px
(
22
).
toFloat
()
mPaint
.
textAlign
=
Paint
.
Align
.
CENTER
mPaint
.
typeface
=
Typeface
.
DEFAULT_BOLD
mPaint
.
color
=
ContextCompat
.
getColor
(
mContext
,
R
.
color
.
black
)
canvas
.
drawText
(
"$mReadSpeed"
,
mCenterX
,
mCenterY
-
mRectText
.
height
()
/
2
,
mPaint
)
mPaint
.
textSize
=
sp2px
(
14
).
toFloat
()
mPaint
.
typeface
=
Typeface
.
DEFAULT
canvas
.
drawText
(
mReadSpeedStr
,
mCenterX
,
mCenterY
+
mRectText
.
height
()
*
2
,
mPaint
)
// mCenterY -= 20
// canvas.drawLine(p1[0], p1[1], mCenterX, mCenterY, mPaint)
// val p2 = getCoordinatePoint(mPSRadius, θ + 180)
// canvas.drawLine(mCenterX, mCenterY, p2[0], p2[1], mPaint)
}
/** 获取坐标 */
fun
getCoordinatePoint
(
radius
:
Int
,
angle
:
Float
):
Array
<
Float
>
{
val
point
=
arrayOf
(
0f
,
0f
)
var
arcAngle
=
Math
.
toRadians
(
angle
.
toDouble
())
if
(
angle
<
90f
)
{
point
[
0
]
=
(
mCenterX
+
cos
(
arcAngle
)
*
radius
).
toFloat
()
point
[
1
]
=
(
mCenterY
+
sin
(
arcAngle
)
*
radius
).
toFloat
()
}
else
if
(
angle
==
90f
)
{
point
[
0
]
=
mCenterX
point
[
1
]
=
mCenterY
+
radius
}
else
if
(
angle
>
90f
&&
angle
<
180f
)
{
arcAngle
=
Math
.
PI
*
(
180f
-
angle
)
/
180
point
[
0
]
=
(
mCenterX
-
cos
(
arcAngle
)
*
radius
).
toFloat
()
point
[
1
]
=
(
mCenterY
+
sin
(
arcAngle
)
*
radius
).
toFloat
()
}
else
if
(
angle
==
180f
)
{
point
[
0
]
=
mCenterX
-
radius
point
[
1
]
=
mCenterY
}
else
if
(
angle
>
180f
&&
angle
<
270f
)
{
arcAngle
=
Math
.
PI
*
(
angle
-
180f
)
/
180
point
[
0
]
=
(
mCenterX
-
cos
(
arcAngle
)
*
radius
).
toFloat
()
point
[
1
]
=
(
mCenterY
-
sin
(
arcAngle
)
*
radius
).
toFloat
()
}
else
if
(
angle
==
270f
)
{
point
[
0
]
=
mCenterX
point
[
1
]
=
mCenterY
-
radius
}
else
{
arcAngle
=
Math
.
PI
*
(
360
-
angle
)
/
180.0
point
[
0
]
=
(
mCenterX
+
cos
(
arcAngle
)
*
radius
).
toFloat
()
point
[
1
]
=
(
mCenterY
-
sin
(
arcAngle
)
*
radius
).
toFloat
()
}
return
point
}
fun
getVelocity
():
Int
=
mVelocity
fun
setVelocity
(
velocity
:
Int
,
speed
:
Float
)
{
mSpeed
=
String
.
format
(
"%.2f"
,
speed
/
1024
).
toFloat
()
if
(
speed
>
1024
)
{
mReadSpeed
=
mSpeed
mReadSpeedStr
=
"Mb/s"
}
else
{
mReadSpeed
=
speed
mReadSpeedStr
=
"Kb/s"
}
if
(
mVelocity
==
velocity
||
velocity
<
mMin
||
velocity
>
mMax
)
{
return
}
mVelocity
=
velocity
postInvalidate
()
}
fun
getmMax
():
Int
{
return
mMax
}
fun
getmSection
():
Int
{
return
mSection
}
fun
getmPortion
():
Int
{
return
mPortion
}
private
fun
dp2px
(
dp
:
Int
):
Int
{
return
TypedValue
.
applyDimension
(
TypedValue
.
COMPLEX_UNIT_DIP
,
dp
.
toFloat
(),
Resources
.
getSystem
().
displayMetrics
).
toInt
()
}
private
fun
sp2px
(
sp
:
Int
):
Int
{
return
TypedValue
.
applyDimension
(
TypedValue
.
COMPLEX_UNIT_SP
,
sp
.
toFloat
(),
Resources
.
getSystem
().
displayMetrics
).
toInt
()
}
}
\ No newline at end of file
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/DrawHookView.java
deleted
100644 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
widgets
;
import
android.content.Context
;
import
android.content.res.TypedArray
;
import
android.graphics.Canvas
;
import
android.graphics.Color
;
import
android.graphics.Paint
;
import
android.graphics.RectF
;
import
android.util.AttributeSet
;
import
android.view.View
;
import
com.mints.wisdomclean.R
;
import
com.mints.wisdomclean.utils.BubbleUtils
;
/**
* DrawHook
* Created by Zane on 2015/3/4.
*/
public
class
DrawHookView
extends
View
{
//绘制圆弧的进度值
private
int
progress
=
0
;
//线1的x轴
private
int
line1_x
=
0
;
//线1的y轴
private
int
line1_y
=
0
;
//线2的x轴
private
int
line2_x
=
0
;
//线2的y轴
private
int
line2_y
=
0
;
private
final
Paint
paint
;
public
DrawHookView
(
Context
context
)
{
this
(
context
,
null
);
}
public
DrawHookView
(
Context
context
,
AttributeSet
attrs
)
{
this
(
context
,
attrs
,
0
);
}
public
DrawHookView
(
Context
context
,
AttributeSet
attrs
,
int
defStyle
)
{
super
(
context
,
attrs
,
defStyle
);
TypedArray
a
=
context
.
obtainStyledAttributes
(
attrs
,
R
.
styleable
.
DrawHookView
,
defStyle
,
0
);
int
color
=
a
.
getColor
(
R
.
styleable
.
DrawHookView_dhv_color
,
Color
.
WHITE
);
a
.
recycle
();
paint
=
new
Paint
();
//设置画笔颜色
paint
.
setColor
(
getResources
().
getColor
(
R
.
color
.
white
));
//设置圆弧的宽度
paint
.
setStrokeWidth
(
BubbleUtils
.
dp2px
(
3
));
//设置圆弧为空心
paint
.
setStyle
(
Paint
.
Style
.
STROKE
);
//消除锯齿
paint
.
setAntiAlias
(
true
);
//圆润边
paint
.
setStrokeCap
(
Paint
.
Cap
.
ROUND
);
paint
.
setColor
(
color
);
}
//绘制
@Override
protected
void
onDraw
(
Canvas
canvas
)
{
super
.
onDraw
(
canvas
);
progress
+=
2
;
//获取圆心的x坐标
int
center
=
getWidth
()
/
2
;
int
center1
=
center
-
getWidth
()
/
4
;
//圆弧半径
int
radius
=
getWidth
()
/
2
-
5
;
//定义的圆弧的形状和大小的界限
RectF
rectF
=
new
RectF
(
center
-
radius
-
1
,
center
-
radius
-
1
,
center
+
radius
+
1
,
center
+
radius
+
1
);
//根据进度画圆弧
canvas
.
drawArc
(
rectF
,
180
,
360
*
progress
/
100
,
false
,
paint
);
/*
* 绘制对勾
*/
//先等圆弧画完,才话对勾
if
(
progress
>=
100
)
{
if
(
line1_x
<
radius
/
3
)
{
line1_x
++;
line1_y
++;
}
//画第一根线
canvas
.
drawLine
(
center1
,
center
,
center1
+
line1_x
,
center
+
line1_y
,
paint
);
if
(
line1_x
==
radius
/
3
)
{
line2_x
=
line1_x
;
line2_y
=
line1_y
;
line1_x
++;
line1_y
++;
}
if
(
line1_x
>=
radius
/
3
&&
line2_x
<=
radius
)
{
line2_x
++;
line2_y
--;
}
//画第二根线
canvas
.
drawLine
(
center1
+
line1_x
,
center
+
line1_y
,
center1
+
line2_x
,
center
+
line2_y
,
paint
);
}
//每隔10毫秒界面刷新
postInvalidateDelayed
(
6
);
}
}
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/ExpandableGridView.java
deleted
100644 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
widgets
;
import
android.content.Context
;
import
android.util.AttributeSet
;
import
android.view.ViewGroup
;
import
android.widget.GridView
;
public
class
ExpandableGridView
extends
GridView
{
boolean
expanded
=
true
;
public
boolean
isExpanded
()
{
return
expanded
;
}
public
ExpandableGridView
(
Context
context
)
{
super
(
context
);
}
public
ExpandableGridView
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
}
public
ExpandableGridView
(
Context
context
,
AttributeSet
attrs
,
int
defStyle
)
{
super
(
context
,
attrs
,
defStyle
);
}
@Override
public
void
onMeasure
(
int
widthMeasureSpec
,
int
heightMeasureSpec
)
{
if
(
isExpanded
())
{
int
expandSpec
=
MeasureSpec
.
makeMeasureSpec
(
Integer
.
MAX_VALUE
>>
2
,
MeasureSpec
.
AT_MOST
);
super
.
onMeasure
(
widthMeasureSpec
,
expandSpec
);
ViewGroup
.
LayoutParams
params
=
getLayoutParams
();
params
.
height
=
getMeasuredHeight
();
}
else
{
super
.
onMeasure
(
widthMeasureSpec
,
heightMeasureSpec
);
}
}
public
void
setExpanded
(
boolean
expanded
)
{
this
.
expanded
=
expanded
;
}
}
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/GifView.kt
deleted
100644 → 0
View file @
1af1a0f7
package
com.mints.wisdomclean.ui.widgets
import
android.annotation.SuppressLint
import
android.content.Context
import
android.graphics.Canvas
import
android.graphics.Movie
import
android.os.Build
import
android.util.AttributeSet
import
android.view.View
import
com.mints.wisdomclean.R
/**
* Created by Cuneyt on 4.10.2015.
* Updated by Cuneyt on 02.04.2019.
* Gifview
*/
class
GifView
@JvmOverloads
constructor
(
context
:
Context
,
attrs
:
AttributeSet
?
=
null
,
defStyle
:
Int
=
R
.
styleable
.
CustomTheme_gifViewStyle
)
:
View
(
context
,
attrs
,
defStyle
)
{
private
var
movieMovieResourceId
:
Int
=
0
private
var
movie
:
Movie
?
=
null
private
var
movieStart
:
Long
=
0
private
var
currentAnimationTime
:
Int
=
0
private
var
movieLeft
:
Float
=
0F
private
var
movieTop
:
Float
=
0F
private
var
movieScale
:
Float
=
0F
private
var
movieMeasuredMovieWidth
:
Int
=
0
private
var
movieMeasuredMovieHeight
:
Int
=
0
@Volatile
var
isPaused
:
Boolean
=
false
private
var
isVisible
=
true
var
gifResource
:
Int
get
()
=
this
.
movieMovieResourceId
set
(
movieResourceId
)
{
this
.
movieMovieResourceId
=
movieResourceId
movie
=
Movie
.
decodeStream
(
resources
.
openRawResource
(
movieMovieResourceId
))
requestLayout
()
}
val
isPlaying
:
Boolean
get
()
=
!
this
.
isPaused
init
{
setViewAttributes
(
context
,
attrs
,
defStyle
)
}
@SuppressLint
(
"NewApi"
)
private
fun
setViewAttributes
(
context
:
Context
,
attrs
:
AttributeSet
?,
defStyle
:
Int
)
{
setLayerType
(
LAYER_TYPE_SOFTWARE
,
null
)
val
array
=
context
.
obtainStyledAttributes
(
attrs
,
R
.
styleable
.
GifView
,
defStyle
,
R
.
style
.
Widget_GifView
)
//-1 is default value
movieMovieResourceId
=
array
.
getResourceId
(
R
.
styleable
.
GifView_src
,
-
1
)
isPaused
=
array
.
getBoolean
(
R
.
styleable
.
GifView_paused
,
false
)
array
.
recycle
()
if
(
movieMovieResourceId
!=
-
1
)
{
movie
=
Movie
.
decodeStream
(
resources
.
openRawResource
(
movieMovieResourceId
))
}
}
fun
play
()
{
if
(
this
.
isPaused
)
{
this
.
isPaused
=
false
/**
* Calculate new movie start time, so that it resumes from the same
* frame.
*/
movieStart
=
android
.
os
.
SystemClock
.
uptimeMillis
()
-
currentAnimationTime
invalidate
()
}
}
fun
pause
()
{
if
(!
this
.
isPaused
)
{
this
.
isPaused
=
true
invalidate
()
}
}
override
fun
onMeasure
(
widthMeasureSpec
:
Int
,
heightMeasureSpec
:
Int
)
{
if
(
movie
!=
null
)
{
val
movieWidth
=
movie
!!
.
width
()
val
movieHeight
=
movie
!!
.
height
()
/*
* Calculate horizontal scaling
*/
var
scaleH
=
1f
val
measureModeWidth
=
MeasureSpec
.
getMode
(
widthMeasureSpec
)
if
(
measureModeWidth
!=
MeasureSpec
.
UNSPECIFIED
)
{
val
maximumWidth
=
MeasureSpec
.
getSize
(
widthMeasureSpec
)
if
(
movieWidth
>
maximumWidth
*
2
)
{
scaleH
=
movieWidth
.
toFloat
()
/
maximumWidth
.
toFloat
()
}
else
{
scaleH
=
movieWidth
.
toFloat
()
/
maximumWidth
.
toFloat
()
}
// if (movieWidth > maximumWidth) {
// scaleH = movieWidth.toFloat() / maximumWidth.toFloat()
// }
}
/*
* calculate vertical scaling
*/
var
scaleW
=
1f
val
measureModeHeight
=
MeasureSpec
.
getMode
(
heightMeasureSpec
)
if
(
measureModeHeight
!=
MeasureSpec
.
UNSPECIFIED
)
{
val
maximumHeight
=
MeasureSpec
.
getSize
(
heightMeasureSpec
)
if
(
movieHeight
>
maximumHeight
*
2
)
{
scaleW
=
movieHeight
.
toFloat
()
/
maximumHeight
.
toFloat
()
}
else
{
scaleW
=
movieHeight
.
toFloat
()
/
maximumHeight
.
toFloat
()
}
// if (movieHeight > maximumHeight) {
// scaleW = movieHeight.toFloat() / maximumHeight.toFloat()
// }
}
// LogUtil.d("AAAAAAA" + scaleH)
// LogUtil.d("BBBBBB" + scaleW)
/*
* calculate overall scale
*/
if
(
scaleH
>
1f
||
scaleW
>
1f
||
scaleW
<
0.5f
||
scaleH
<
0.5f
)
{
movieScale
=
1f
/
scaleH
.
coerceAtLeast
(
scaleW
)
}
else
{
movieScale
=
1f
/
scaleH
.
coerceAtMost
(
scaleW
)
}
movieMeasuredMovieWidth
=
(
movieWidth
*
movieScale
).
toInt
()
movieMeasuredMovieHeight
=
(
movieHeight
*
movieScale
).
toInt
()
setMeasuredDimension
(
movieMeasuredMovieWidth
,
movieMeasuredMovieHeight
)
}
else
{
/*
* No movie set, just set minimum available size.
*/
setMeasuredDimension
(
suggestedMinimumWidth
,
suggestedMinimumHeight
)
}
}
override
fun
onLayout
(
changed
:
Boolean
,
left
:
Int
,
top
:
Int
,
right
:
Int
,
bottom
:
Int
)
{
super
.
onLayout
(
changed
,
left
,
top
,
right
,
bottom
)
/*
* Calculate movieLeft / movieTop for drawing in center
*/
movieLeft
=
(
width
-
movieMeasuredMovieWidth
)
/
2f
movieTop
=
(
height
-
movieMeasuredMovieHeight
)
/
2f
isVisible
=
visibility
==
VISIBLE
}
override
fun
onDraw
(
canvas
:
Canvas
)
{
if
(
movie
!=
null
)
{
if
(!
isPaused
)
{
updateAnimationTime
()
drawMovieFrame
(
canvas
)
invalidateView
()
}
else
{
drawMovieFrame
(
canvas
)
}
}
}
/**
* Invalidates view only if it is isVisible.
* <br></br>
* [.postInvalidateOnAnimation] is used for Jelly Bean and higher.
*/
@SuppressLint
(
"NewApi"
)
private
fun
invalidateView
()
{
if
(
isVisible
)
{
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
JELLY_BEAN
)
{
postInvalidateOnAnimation
()
}
else
{
invalidate
()
}
}
}
/**
* Calculate current animation time
*/
private
fun
updateAnimationTime
()
{
val
now
=
android
.
os
.
SystemClock
.
uptimeMillis
()
if
(
movieStart
==
0L
)
{
movieStart
=
now
}
var
duration
=
movie
!!
.
duration
()
if
(
duration
==
0
)
{
duration
=
DEFAULT_MOVIE_VIEW_DURATION
}
currentAnimationTime
=
((
now
-
movieStart
)
%
duration
).
toInt
()
}
/**
* Draw current GIF frame
*/
private
fun
drawMovieFrame
(
canvas
:
Canvas
)
{
movie
!!
.
setTime
(
currentAnimationTime
)
canvas
.
save
()
canvas
.
scale
(
movieScale
,
movieScale
)
movie
!!
.
draw
(
canvas
,
movieLeft
/
movieScale
,
movieTop
/
movieScale
)
canvas
.
restore
()
}
@SuppressLint
(
"NewApi"
)
override
fun
onScreenStateChanged
(
screenState
:
Int
)
{
super
.
onScreenStateChanged
(
screenState
)
isVisible
=
screenState
==
SCREEN_STATE_ON
invalidateView
()
}
@SuppressLint
(
"NewApi"
)
override
fun
onVisibilityChanged
(
changedView
:
View
,
visibility
:
Int
)
{
super
.
onVisibilityChanged
(
changedView
,
visibility
)
isVisible
=
visibility
==
VISIBLE
invalidateView
()
}
override
fun
onWindowVisibilityChanged
(
visibility
:
Int
)
{
super
.
onWindowVisibilityChanged
(
visibility
)
isVisible
=
visibility
==
VISIBLE
invalidateView
()
}
companion
object
{
private
const
val
DEFAULT_MOVIE_VIEW_DURATION
=
1000
}
}
\ No newline at end of file
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/InterceptFrameLayout.java
deleted
100644 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
widgets
;
import
android.content.Context
;
import
android.util.AttributeSet
;
import
android.view.MotionEvent
;
import
android.widget.FrameLayout
;
public
class
InterceptFrameLayout
extends
FrameLayout
{
boolean
isIntercept
=
true
;
public
boolean
isInterceptTouch
()
{
return
isIntercept
;
}
@Override
public
boolean
onInterceptTouchEvent
(
MotionEvent
ev
)
{
return
isIntercept
;
}
public
InterceptFrameLayout
(
Context
context
)
{
super
(
context
);
}
public
InterceptFrameLayout
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
}
public
InterceptFrameLayout
(
Context
context
,
AttributeSet
attrs
,
int
defStyle
)
{
super
(
context
,
attrs
,
defStyle
);
}
public
void
isIntercept
(
boolean
isIntercept
)
{
this
.
isIntercept
=
isIntercept
;
}
}
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/MilliCountDownTimer.java
deleted
100755 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
widgets
;
import
android.os.CountDownTimer
;
import
android.widget.TextView
;
/**
* 简单 时,分,秒,毫秒倒计时
* <p>
* 精确到毫秒
*/
public
class
MilliCountDownTimer
extends
CountDownTimer
{
// 默认倒计时间隔
private
static
final
long
DEFAULT_INTERVAL
=
100L
;
/**
* 秒,分,时对应的毫秒数
*/
private
int
sec
=
1000
,
min
=
sec
*
60
,
hr
=
min
*
60
;
/**
* 显示时间的视图
*/
private
TextView
tvDisplay
;
/**
* 结束监听
*/
private
static
OnFinishListener
onFinishListener
;
/**
* @param millisInFuture 倒计时总时间 单位:毫秒
* The number of millis in the future from the call
* to {@link #start()} until the countdown is done and {@link #onFinish()}
* is called.
* @param countDownInterval 倒计时间隔 单位:毫秒
* The interval along the way to receive
* {@link #onTick(long)} callbacks.
* @param tvDisplay 显示时间的视图
*/
public
MilliCountDownTimer
(
long
millisInFuture
,
long
countDownInterval
,
TextView
tvDisplay
)
{
super
(
millisInFuture
,
countDownInterval
);
this
.
tvDisplay
=
tvDisplay
;
}
/**
* @param millisInFuture 倒计时总时间 单位:毫秒
* The number of millis in the future from the call
* to {@link #start()} until the countdown is done and {@link #onFinish()}
* is called.
* @param tvDisplay 显示时间的视图
*/
public
MilliCountDownTimer
(
long
millisInFuture
,
TextView
tvDisplay
)
{
super
(
millisInFuture
,
DEFAULT_INTERVAL
);
this
.
tvDisplay
=
tvDisplay
;
}
/**
* 每一次间隔时间到后调用
*
* @param millisUntilFinished 剩余总时间 单位:毫秒
*/
@Override
public
void
onTick
(
long
millisUntilFinished
)
{
// 剩余的小时,分钟,秒,毫秒
long
lHr
=
millisUntilFinished
/
hr
;
long
lMin
=
(
millisUntilFinished
-
lHr
*
hr
)
/
min
;
long
lSec
=
(
millisUntilFinished
-
lHr
*
hr
-
lMin
*
min
)
/
sec
;
long
lMs
=
millisUntilFinished
-
lHr
*
hr
-
lMin
*
min
-
lSec
*
sec
;
String
strLHr
=
getTime
(
lHr
);
String
strLMin
=
getTime
(
lMin
);
String
strLSec
=
getTime
(
lSec
);
String
strLMs
=
getMs
(
lMs
);
// 依次拼接时间 时:分:秒:毫秒
tvDisplay
.
setText
(
strLHr
+
"时"
+
strLMin
+
"分"
+
strLSec
+
"秒"
+
strLMs
);
}
/**
* 根据毫秒换算成相应单位后是否大于10来返回相应时间
*/
private
String
getTime
(
long
time
)
{
return
time
>
10
?
String
.
valueOf
(
time
)
:
"0"
+
time
;
}
/**
* 获取毫秒
*/
private
String
getMs
(
long
time
)
{
String
strMs
=
String
.
valueOf
(
time
);
return
time
>
100
?
strMs
.
substring
(
0
,
strMs
.
length
()
-
1
)
:
"00"
;
}
/**
* 结束监听,可以在倒计时结束时做一些事
*/
public
interface
OnFinishListener
{
void
onFinish
();
}
/**
* 设置结束监听
*
* @param onFinishListener 结束监听对象
*/
public
MilliCountDownTimer
setOnFinishListener
(
OnFinishListener
onFinishListener
)
{
MilliCountDownTimer
.
onFinishListener
=
onFinishListener
;
return
this
;
}
/**
* 倒计时结束时调用
*/
@Override
public
void
onFinish
()
{
tvDisplay
.
setText
(
"00:00:00"
);
if
(
onFinishListener
!=
null
)
onFinishListener
.
onFinish
();
}
}
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/PhotoDialog.kt
deleted
100644 → 0
View file @
1af1a0f7
package
com.mints.wisdomclean.ui.widgets
import
android.app.Dialog
import
android.content.Context
import
android.view.*
import
android.widget.LinearLayout
import
android.widget.TextView
import
com.mints.wisdomclean.R
class
PhotoDialog
(
context
:
Context
)
:
Dialog
(
context
,
R
.
style
.
dialog
)
{
private
val
llDialogCamera
:
LinearLayout
private
val
llDialogAlbum
:
LinearLayout
private
val
tvDialogCancel
:
TextView
private
var
mOnChangePhotoListener
:
OnChangePhotoListener
?
=
null
init
{
setContentView
(
R
.
layout
.
dialog_photo
)
// 设置window属性
window
?.
let
{
val
lp
=
it
.
attributes
lp
.
gravity
=
Gravity
.
BOTTOM
lp
.
width
=
WindowManager
.
LayoutParams
.
MATCH_PARENT
lp
.
height
=
WindowManager
.
LayoutParams
.
WRAP_CONTENT
lp
.
windowAnimations
=
R
.
style
.
DialogAnimBottom
it
.
attributes
=
lp
}
// 设置外部不可关闭
// setCancelable(false)
// setCanceledOnTouchOutside(false)
setOnKeyListener
{
_
,
i
,
_
->
i
==
KeyEvent
.
KEYCODE_BACK
}
llDialogCamera
=
findViewById
<
View
>(
R
.
id
.
llDialogCamera
)
as
LinearLayout
llDialogAlbum
=
findViewById
<
View
>(
R
.
id
.
llDialogAlbum
)
as
LinearLayout
tvDialogCancel
=
findViewById
<
View
>(
R
.
id
.
tvDialogCancel
)
as
TextView
llDialogCamera
.
setOnClickListener
{
mOnChangePhotoListener
?.
onChangePhoto
(
0
)
}
llDialogAlbum
.
setOnClickListener
{
mOnChangePhotoListener
?.
onChangePhoto
(
1
)
}
tvDialogCancel
.
setOnClickListener
{
dismiss
()
}
}
fun
setOnChangePhotoListener
(
onChangePhotoListener
:
OnChangePhotoListener
):
PhotoDialog
{
this
.
mOnChangePhotoListener
=
onChangePhotoListener
return
this
}
interface
OnChangePhotoListener
{
fun
onChangePhoto
(
status
:
Int
)
}
}
\ No newline at end of file
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/PhotoWrpView.kt
deleted
100644 → 0
View file @
1af1a0f7
package
com.mints.wisdomclean.ui.widgets
import
android.annotation.SuppressLint
import
android.content.Context
import
android.graphics.*
import
android.text.TextPaint
import
android.util.AttributeSet
import
android.view.View
class
PhotoWrpView
:
View
{
constructor
(
context
:
Context
)
:
this
(
context
,
null
)
constructor
(
context
:
Context
,
attributeSet
:
AttributeSet
?)
:
this
(
context
,
attributeSet
,
0
)
constructor
(
context
:
Context
,
attributeSet
:
AttributeSet
?,
defStyleAttr
:
Int
)
:
super
(
context
,
attributeSet
,
defStyleAttr
)
private
var
mPaint
:
Paint
=
Paint
(
Paint
.
ANTI_ALIAS_FLAG
)
private
var
mTextPaint
:
TextPaint
=
TextPaint
(
Paint
.
ANTI_ALIAS_FLAG
)
private
var
mWaterMarkPaint
:
TextPaint
=
TextPaint
(
Paint
.
ANTI_ALIAS_FLAG
)
private
var
mWaterMarkOnOff
=
false
private
var
mBitmap
:
Bitmap
?
=
null
private
var
mWidth
=
0f
private
var
mHeight
=
0f
private
val
mPaintWidth
=
2f
private
var
mCurrentPhotoInch
=
PHOTO_INCH_ONE
private
var
mTopStr
:
String
?
=
null
private
var
mRightStr
:
String
?
=
null
private
var
mBottomStr
:
String
?
=
null
private
var
mLeftStr
:
String
?
=
null
private
var
mArr
:
IntArray
?
=
null
companion
object
{
/**
* 一寸:25mm*35mm 295*413px
* 二寸:35mm*49mm 413*579px
* 小二寸:35mm*45mm 413*531px
* 大一寸:33mm*48mm 390*567px
*/
const
val
PHOTO_INCH_ONE
=
1
// 一寸
const
val
PHOTO_INCH_TWO
=
2
// 二寸
const
val
PHOTO_INCH_BIG_ONE
=
3
// 大一寸
const
val
PHOTO_INCH_SMALL_TWO
=
5
// 小二寸
const
val
WATER_MARK_STR
=
"保存后不显示此文字"
}
init
{
mPaint
.
strokeWidth
=
mPaintWidth
mPaint
.
color
=
Color
.
GRAY
mPaint
.
style
=
Paint
.
Style
.
STROKE
mTextPaint
.
strokeWidth
=
1f
mTextPaint
.
textSize
=
dp2px
(
context
,
12f
)
mTextPaint
.
textAlign
=
Paint
.
Align
.
CENTER
mTextPaint
.
color
=
Color
.
GRAY
mTextPaint
.
style
=
Paint
.
Style
.
FILL
mWaterMarkPaint
.
strokeWidth
=
10f
mWaterMarkPaint
.
textSize
=
dp2px
(
context
,
18f
)
mWaterMarkPaint
.
color
=
Color
.
GRAY
mWaterMarkPaint
.
style
=
Paint
.
Style
.
FILL
}
private
fun
dp2px
(
context
:
Context
,
pxVal
:
Float
):
Float
{
return
pxVal
*
context
.
resources
.
displayMetrics
.
scaledDensity
+
0.5f
}
/**
*
* @param bitmap
* @param photoInch
*/
fun
setBitmap
(
bitmap
:
Bitmap
?,
photoInch
:
Int
)
{
if
(
bitmap
==
null
)
{
return
}
mCurrentPhotoInch
=
photoInch
mArr
=
calculatePosition
()
//获取图片的宽高
mBitmap
=
getNewBitmap
(
bitmap
,
mArr
!!
[
0
],
mArr
!!
[
1
])
invalidate
()
}
private
fun
getNewBitmap
(
bitmap
:
Bitmap
,
newWidth
:
Int
,
newHeight
:
Int
):
Bitmap
?
{
// 获得图片的宽高.
val
width
=
bitmap
.
width
val
height
=
bitmap
.
height
// 计算缩放比例.
val
scaleWidth
=
newWidth
.
toFloat
()
/
width
val
scaleHeight
=
newHeight
.
toFloat
()
/
height
// 取得想要缩放的matrix参数.
val
matrix
=
Matrix
()
matrix
.
postScale
(
scaleWidth
,
scaleHeight
)
// 得到新的图片.
return
Bitmap
.
createBitmap
(
bitmap
,
0
,
0
,
width
,
height
,
matrix
,
true
)
}
fun
turnOnWaterMark
(
onOff
:
Boolean
)
{
mWaterMarkOnOff
=
onOff
invalidate
()
}
private
fun
calculatePosition
():
IntArray
{
var
scaleWidth
=
0
var
scaleHeight
=
0
when
(
mCurrentPhotoInch
)
{
PHOTO_INCH_ONE
->
{
mTopStr
=
"295px"
mRightStr
=
"413px"
mBottomStr
=
"25mm"
mLeftStr
=
"35mm"
scaleWidth
=
(
mWidth
*
0.6
).
toInt
()
scaleHeight
=
(
scaleWidth
*
1.4
).
toInt
()
}
PHOTO_INCH_TWO
->
{
mTopStr
=
"413px"
mRightStr
=
"579px"
mBottomStr
=
"35mm"
mLeftStr
=
"49mm"
scaleWidth
=
(
mWidth
*
0.6
).
toInt
()
scaleHeight
=
(
scaleWidth
*
1.45
).
toInt
()
}
PHOTO_INCH_BIG_ONE
->
{
mTopStr
=
"390px"
mRightStr
=
"567px"
mBottomStr
=
"33mm"
mLeftStr
=
"48mm"
scaleWidth
=
(
mWidth
*
0.6
).
toInt
()
scaleHeight
=
(
scaleWidth
*
1.45
).
toInt
()
}
PHOTO_INCH_SMALL_TWO
->
{
mTopStr
=
"413px"
mRightStr
=
"531px"
mBottomStr
=
"35mm"
mLeftStr
=
"45mm"
scaleWidth
=
(
mWidth
*
0.6
).
toInt
()
scaleHeight
=
(
scaleWidth
*
1.4
).
toInt
()
}
}
return
intArrayOf
(
scaleWidth
,
scaleHeight
)
}
@SuppressLint
(
"DrawAllocation"
)
override
fun
onDraw
(
canvas
:
Canvas
)
{
super
.
onDraw
(
canvas
)
if
(
mBitmap
==
null
)
return
val
arr
=
mArr
!!
// 计算左边位置
val
left
=
(
mWidth
-
arr
[
0
])
/
2
// 计算上边位置
val
top
=
(
mHeight
-
arr
[
1
])
/
2
val
destRect
=
Rect
(
left
.
toInt
(),
top
.
toInt
(),
(
left
+
arr
[
0
]).
toInt
(),
(
top
+
arr
[
1
]).
toInt
())
val
srcRect
=
Rect
(
0
,
0
,
arr
[
0
],
arr
[
1
])
canvas
.
drawBitmap
(
mBitmap
!!
,
srcRect
,
destRect
,
mPaint
)
// 上方
canvas
.
drawLine
(
left
,
(
top
-
50
),
left
,
top
,
mPaint
)
canvas
.
drawLine
(
left
,
(
top
-
40
),
(
left
+
arr
[
0
]
/
3
),
(
top
-
40
),
mPaint
)
canvas
.
drawLine
((
left
+
arr
[
0
]
/
3
*
2
),
(
top
-
40
),
(
left
+
arr
[
0
]),
(
top
-
40
),
mPaint
)
canvas
.
drawLine
((
left
+
arr
[
0
]),
(
top
-
50
),
(
left
+
arr
[
0
]),
top
,
mPaint
)
canvas
.
drawText
(
mTopStr
!!
,
mWidth
/
2
,
(
top
-
30
),
mTextPaint
)
// 右方
canvas
.
drawLine
((
left
+
arr
[
0
]),
top
,
(
left
+
arr
[
0
]
+
50
),
top
,
mPaint
)
canvas
.
drawLine
((
left
+
arr
[
0
]
+
40
),
top
,
(
left
+
arr
[
0
]
+
40
),
(
top
+
arr
[
1
]
/
3
),
mPaint
)
canvas
.
drawLine
((
left
+
arr
[
0
]),
(
top
+
arr
[
1
]),
(
left
+
arr
[
0
]
+
50
),
(
top
+
arr
[
1
]),
mPaint
)
canvas
.
drawLine
((
left
+
arr
[
0
]
+
40
),
(
top
+
arr
[
1
]
/
3
*
2
),
(
left
+
arr
[
0
]
+
40
),
(
top
+
arr
[
1
]),
mPaint
)
drawAngleText
(
canvas
,
mRightStr
!!
,
(
left
+
arr
[
0
]
+
50
),
mHeight
/
2
,
mTextPaint
,
-
90f
)
// 下方
canvas
.
drawLine
(
left
,
(
top
+
arr
[
1
]),
left
,
(
top
+
arr
[
1
]
+
50
),
mPaint
)
canvas
.
drawLine
(
left
,
(
top
+
arr
[
1
]
+
40
),
(
left
+
arr
[
0
]
/
3
),
(
top
+
arr
[
1
]
+
40
),
mPaint
)
canvas
.
drawLine
((
left
+
arr
[
0
]
/
3
*
2
),
(
top
+
arr
[
1
]
+
40
),
(
left
+
arr
[
0
]),
(
top
+
arr
[
1
]
+
40
),
mPaint
)
canvas
.
drawLine
((
left
+
arr
[
0
]),
(
top
+
arr
[
1
]),
(
left
+
arr
[
0
]),
(
top
+
arr
[
1
]
+
50
),
mPaint
)
canvas
.
drawText
(
mBottomStr
!!
,
mWidth
/
2
,
(
top
+
arr
[
1
]
+
50
),
mTextPaint
)
// 左方
canvas
.
drawLine
((
left
-
50
),
top
,
left
,
top
,
mPaint
)
canvas
.
drawLine
((
left
-
40
),
top
,
(
left
-
40
),
(
top
+
arr
[
1
]
/
3
),
mPaint
)
canvas
.
drawLine
((
left
-
40
),
(
top
+
arr
[
1
]
/
3
*
2
),
(
left
-
40
),
(
top
+
arr
[
1
]),
mPaint
)
canvas
.
drawLine
((
left
-
50
),
(
top
+
arr
[
1
]),
left
,
(
top
+
arr
[
1
]),
mPaint
)
drawAngleText
(
canvas
,
mLeftStr
!!
,
(
left
-
30
),
mHeight
/
2
,
mTextPaint
,
-
90f
)
// if (mWaterMarkOnOff) {
drawAngleText
(
canvas
,
WATER_MARK_STR
,
left
+
arr
[
0
]
/
6
,
top
+
arr
[
1
]
/
6
*
3
,
mWaterMarkPaint
,
-
30f
)
drawAngleText
(
canvas
,
WATER_MARK_STR
,
left
+
arr
[
0
]
/
6
,
top
+
arr
[
1
]
/
6
*
4
,
mWaterMarkPaint
,
-
30f
)
drawAngleText
(
canvas
,
WATER_MARK_STR
,
left
+
arr
[
0
]
/
6
,
top
+
arr
[
1
]
/
6
*
5
,
mWaterMarkPaint
,
-
30f
)
// }
}
private
fun
drawAngleText
(
canvas
:
Canvas
,
text
:
String
,
x
:
Float
,
y
:
Float
,
paint
:
Paint
,
angle
:
Float
)
{
if
(
angle
!=
0f
)
{
canvas
.
rotate
(
angle
,
x
,
y
)
}
canvas
.
drawText
(
text
,
x
,
y
,
paint
)
if
(
angle
!=
0f
)
{
canvas
.
rotate
(-
angle
,
x
,
y
)
}
}
override
fun
onMeasure
(
widthMeasureSpec
:
Int
,
heightMeasureSpec
:
Int
)
{
super
.
onMeasure
(
widthMeasureSpec
,
heightMeasureSpec
)
val
minimumWidth
=
suggestedMinimumWidth
val
minimumHeight
=
suggestedMinimumHeight
val
width
=
measureWidth
(
minimumWidth
,
widthMeasureSpec
)
val
height
=
measureHeight
(
minimumHeight
,
heightMeasureSpec
)
mWidth
=
width
.
toFloat
()
mHeight
=
height
.
toFloat
()
setMeasuredDimension
(
width
,
height
)
}
private
fun
measureWidth
(
defaultWidth
:
Int
,
measureSpec
:
Int
):
Int
{
var
measureWidth
=
defaultWidth
val
specMode
=
MeasureSpec
.
getMode
(
measureSpec
)
val
specSize
=
MeasureSpec
.
getSize
(
measureSpec
)
when
(
specMode
)
{
MeasureSpec
.
AT_MOST
->
{
measureWidth
=
specSize
+
paddingLeft
+
paddingRight
}
MeasureSpec
.
EXACTLY
->
{
measureWidth
=
specSize
}
MeasureSpec
.
UNSPECIFIED
->
{
measureWidth
=
defaultWidth
.
coerceAtLeast
(
specSize
)
}
}
return
measureWidth
}
private
fun
measureHeight
(
defaultHeight
:
Int
,
measureSpec
:
Int
):
Int
{
var
measureHeight
=
defaultHeight
val
specMode
=
MeasureSpec
.
getMode
(
measureSpec
)
val
specSize
=
MeasureSpec
.
getSize
(
measureSpec
)
when
(
specMode
)
{
MeasureSpec
.
AT_MOST
->
{
measureHeight
=
specSize
+
paddingTop
+
paddingBottom
}
MeasureSpec
.
EXACTLY
->
{
measureHeight
=
specSize
}
MeasureSpec
.
UNSPECIFIED
->
{
measureHeight
=
defaultHeight
.
coerceAtLeast
(
specSize
)
}
}
return
measureHeight
}
}
\ No newline at end of file
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/ProgressButton.java
deleted
100644 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
widgets
;
import
android.content.Context
;
import
android.content.res.TypedArray
;
import
android.graphics.Canvas
;
import
android.graphics.drawable.GradientDrawable
;
import
android.util.AttributeSet
;
import
androidx.appcompat.widget.AppCompatButton
;
import
androidx.core.content.ContextCompat
;
import
com.mints.wisdomclean.R
;
public
class
ProgressButton
extends
AppCompatButton
{
private
float
mCornerRadius
=
15
;
private
float
mProgressMargin
=
0
;
private
boolean
mFinish
;
private
int
mProgress
;
private
int
mMaxProgress
=
100
;
private
int
mMinProgress
=
0
;
private
boolean
isCycle
=
false
;
private
GradientDrawable
mDrawableButton
;
private
GradientDrawable
mDrawableProgressBackground
;
private
GradientDrawable
mDrawableProgress
;
public
ProgressButton
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
initialize
(
context
,
attrs
);
}
public
ProgressButton
(
Context
context
,
AttributeSet
attrs
,
int
defStyle
)
{
super
(
context
,
attrs
,
defStyle
);
initialize
(
context
,
attrs
);
}
private
void
initialize
(
Context
context
,
AttributeSet
attrs
)
{
mDrawableProgressBackground
=
new
GradientDrawable
();
mDrawableProgress
=
new
GradientDrawable
();
mDrawableButton
=
new
GradientDrawable
();
int
defaultButtonColor
=
ContextCompat
.
getColor
(
context
,
R
.
color
.
color_main
);
int
defaultProgressColor
=
ContextCompat
.
getColor
(
context
,
R
.
color
.
color_10000000
);
int
defaultBackColor
=
ContextCompat
.
getColor
(
context
,
R
.
color
.
color_main
);
TypedArray
attr
=
context
.
obtainStyledAttributes
(
attrs
,
R
.
styleable
.
ProgressButton
);
try
{
mProgressMargin
=
attr
.
getDimension
(
R
.
styleable
.
ProgressButton_progressMargin
,
mProgressMargin
);
mCornerRadius
=
attr
.
getDimension
(
R
.
styleable
.
ProgressButton_cornerRadius
,
mCornerRadius
);
//Get custom normal color
int
buttonColor
=
attr
.
getColor
(
R
.
styleable
.
ProgressButton_buttonColor
,
defaultButtonColor
);
//Set normal color
mDrawableButton
.
setColor
(
buttonColor
);
//Get custom progress background color
int
progressBackColor
=
attr
.
getColor
(
R
.
styleable
.
ProgressButton_progressBackColor
,
defaultBackColor
);
//Set progress background drawable color
mDrawableProgressBackground
.
setColor
(
progressBackColor
);
//Get custom progress color
int
progressColor
=
attr
.
getColor
(
R
.
styleable
.
ProgressButton_progressColor
,
defaultProgressColor
);
//Set progress drawable color
mDrawableProgress
.
setColor
(
progressColor
);
//Get default progress
mProgress
=
attr
.
getInteger
(
R
.
styleable
.
ProgressButton_progress
,
mProgress
);
//Get minimum progress
mMinProgress
=
attr
.
getInteger
(
R
.
styleable
.
ProgressButton_minProgress
,
mMinProgress
);
//Get maximize progress
mMaxProgress
=
attr
.
getInteger
(
R
.
styleable
.
ProgressButton_maxProgress
,
mMaxProgress
);
}
finally
{
attr
.
recycle
();
}
//Set corner radius
mDrawableButton
.
setCornerRadius
(
mCornerRadius
);
mDrawableProgressBackground
.
setCornerRadius
(
mCornerRadius
);
mDrawableProgress
.
setCornerRadius
(
mCornerRadius
-
mProgressMargin
);
setBackgroundDrawable
(
mDrawableButton
);
mFinish
=
false
;
}
@Override
protected
void
onDraw
(
Canvas
canvas
)
{
if
(
isCycle
)
{
if
(
mProgress
>=
100
)
{
mProgress
=
0
;
}
mProgress
++;
postInvalidateDelayed
(
10
);
}
if
(
mProgress
>
mMinProgress
&&
mProgress
<=
mMaxProgress
)
{
float
progressWidth
=
(
float
)
getMeasuredWidth
()
*
((
float
)
(
mProgress
-
mMinProgress
)
/
mMaxProgress
-
mMinProgress
);
if
(
progressWidth
<
mCornerRadius
*
2
)
{
progressWidth
=
mCornerRadius
*
2
;
}
mDrawableProgress
.
setBounds
((
int
)
mProgressMargin
,
(
int
)
mProgressMargin
,
(
int
)
(
progressWidth
-
mProgressMargin
),
getMeasuredHeight
()
-
(
int
)
mProgressMargin
);
mDrawableProgress
.
draw
(
canvas
);
if
(
mProgress
==
mMaxProgress
)
{
setBackgroundDrawable
(
mDrawableButton
);
// mFinish = true;
}
}
super
.
onDraw
(
canvas
);
}
public
void
startCycle
()
{
isCycle
=
true
;
mProgress
=
0
;
invalidate
();
}
public
void
pauseCycle
()
{
isCycle
=
false
;
mProgress
=
0
;
invalidate
();
}
/**
* Set current progress
*/
public
void
setProgress
(
int
progress
)
{
if
(!
mFinish
)
{
mProgress
=
progress
;
setBackgroundDrawable
(
mDrawableProgressBackground
);
invalidate
();
}
}
public
void
setMaxProgress
(
int
maxProgress
)
{
mMaxProgress
=
maxProgress
;
}
public
void
setMinProgress
(
int
minProgress
)
{
mMinProgress
=
minProgress
;
}
public
void
reset
()
{
mFinish
=
false
;
mProgress
=
mMinProgress
;
}
}
\ No newline at end of file
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/RoundAngleImageView.java
deleted
100644 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
widgets
;
import
android.content.Context
;
import
android.content.res.TypedArray
;
import
android.graphics.Bitmap
;
import
android.graphics.Canvas
;
import
android.graphics.Color
;
import
android.graphics.Paint
;
import
android.graphics.Path
;
import
android.graphics.PorterDuff
;
import
android.graphics.PorterDuffXfermode
;
import
android.graphics.RectF
;
import
android.util.AttributeSet
;
import
android.widget.ImageView
;
import
com.mints.wisdomclean.R
;
public
class
RoundAngleImageView
extends
ImageView
{
private
Paint
paint
;
/**
* 个人理解是
*
* 这两个都是画圆的半径
*/
private
int
roundWidth
=
20
;
private
int
roundHeight
=
20
;
private
Paint
paint2
;
public
RoundAngleImageView
(
Context
context
,
AttributeSet
attrs
,
int
defStyle
)
{
super
(
context
,
attrs
,
defStyle
);
init
(
context
,
attrs
);
}
public
RoundAngleImageView
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
init
(
context
,
attrs
);
}
public
RoundAngleImageView
(
Context
context
)
{
super
(
context
);
init
(
context
,
null
);
}
private
void
init
(
Context
context
,
AttributeSet
attrs
)
{
if
(
attrs
!=
null
)
{
TypedArray
a
=
context
.
obtainStyledAttributes
(
attrs
,
R
.
styleable
.
RoundAngleImageView
);
roundWidth
=
a
.
getDimensionPixelSize
(
R
.
styleable
.
RoundAngleImageView_roundWidth
,
roundWidth
);
roundHeight
=
a
.
getDimensionPixelSize
(
R
.
styleable
.
RoundAngleImageView_roundHeight
,
roundHeight
);
}
else
{
float
density
=
context
.
getResources
().
getDisplayMetrics
().
density
;
roundWidth
=
(
int
)
(
roundWidth
*
density
);
roundHeight
=
(
int
)
(
roundHeight
*
density
);
}
paint
=
new
Paint
();
paint
.
setColor
(
Color
.
WHITE
);
paint
.
setAntiAlias
(
true
);
paint
.
setXfermode
(
new
PorterDuffXfermode
(
PorterDuff
.
Mode
.
DST_OUT
));
paint2
=
new
Paint
();
paint2
.
setXfermode
(
null
);
}
@Override
public
void
draw
(
Canvas
canvas
)
{
Bitmap
bitmap
=
Bitmap
.
createBitmap
(
getWidth
(),
getHeight
(),
Bitmap
.
Config
.
ARGB_8888
);
Canvas
canvas2
=
new
Canvas
(
bitmap
);
super
.
draw
(
canvas2
);
drawLiftUp
(
canvas2
);
drawLiftDown
(
canvas2
);
drawRightUp
(
canvas2
);
drawRightDown
(
canvas2
);
canvas
.
drawBitmap
(
bitmap
,
0
,
0
,
paint2
);
bitmap
.
recycle
();
}
private
void
drawLiftUp
(
Canvas
canvas
)
{
Path
path
=
new
Path
();
path
.
moveTo
(
0
,
roundHeight
);
path
.
lineTo
(
0
,
0
);
path
.
lineTo
(
roundWidth
,
0
);
path
.
arcTo
(
new
RectF
(
0
,
0
,
roundWidth
*
2
,
roundHeight
*
2
),
-
90
,
-
90
);
path
.
close
();
canvas
.
drawPath
(
path
,
paint
);
}
private
void
drawLiftDown
(
Canvas
canvas
)
{
Path
path
=
new
Path
();
path
.
moveTo
(
0
,
getHeight
()
-
roundHeight
);
path
.
lineTo
(
0
,
getHeight
());
path
.
lineTo
(
roundWidth
,
getHeight
());
path
.
arcTo
(
new
RectF
(
0
,
getHeight
()
-
roundHeight
*
2
,
roundWidth
*
2
,
getHeight
()),
90
,
90
);
path
.
close
();
canvas
.
drawPath
(
path
,
paint
);
}
private
void
drawRightDown
(
Canvas
canvas
)
{
Path
path
=
new
Path
();
path
.
moveTo
(
getWidth
()
-
roundWidth
,
getHeight
());
path
.
lineTo
(
getWidth
(),
getHeight
());
path
.
lineTo
(
getWidth
(),
getHeight
()
-
roundHeight
);
path
.
arcTo
(
new
RectF
(
getWidth
()
-
roundWidth
*
2
,
getHeight
()
-
roundHeight
*
2
,
getWidth
(),
getHeight
()),
-
0
,
90
);
path
.
close
();
canvas
.
drawPath
(
path
,
paint
);
}
private
void
drawRightUp
(
Canvas
canvas
)
{
Path
path
=
new
Path
();
path
.
moveTo
(
getWidth
(),
roundHeight
);
path
.
lineTo
(
getWidth
(),
0
);
path
.
lineTo
(
getWidth
()
-
roundWidth
,
0
);
path
.
arcTo
(
new
RectF
(
getWidth
()
-
roundWidth
*
2
,
0
,
getWidth
(),
0
+
roundHeight
*
2
),
-
90
,
90
);
path
.
close
();
canvas
.
drawPath
(
path
,
paint
);
}
}
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/RoundCheckBox.kt
deleted
100644 → 0
View file @
1af1a0f7
package
com.mints.wisdomclean.ui.widgets
import
android.content.Context
import
android.util.AttributeSet
class
RoundCheckBox
:
androidx
.
appcompat
.
widget
.
AppCompatCheckBox
{
constructor
(
context
:
Context
,
attrs
:
AttributeSet
?,
defStyle
:
Int
)
:
super
(
context
,
attrs
,
defStyle
)
constructor
(
context
:
Context
,
attrs
:
AttributeSet
?)
:
this
(
context
,
attrs
,
androidx
.
appcompat
.
R
.
attr
.
radioButtonStyle
)
constructor
(
context
:
Context
)
:
this
(
context
,
null
)
}
\ No newline at end of file
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/TransformativeImageView.java
deleted
100644 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
widgets
;
import
android.animation.Animator
;
import
android.animation.AnimatorListenerAdapter
;
import
android.animation.ValueAnimator
;
import
android.content.Context
;
import
android.content.res.TypedArray
;
import
android.graphics.Canvas
;
import
android.graphics.Color
;
import
android.graphics.Matrix
;
import
android.graphics.Paint
;
import
android.graphics.PaintFlagsDrawFilter
;
import
android.graphics.PointF
;
import
android.graphics.RectF
;
import
android.util.AttributeSet
;
import
android.view.MotionEvent
;
import
androidx.appcompat.widget.AppCompatImageView
;
import
com.mints.wisdomclean.R
;
/**
* 多点触控加Matrix类实现图片的旋转、缩放、平移
*
* @attr R.styleable#TransformativeImageView_max_scale
* @attr R.styleable#TransformativeImageView_min_scale
* @attr R.styleable#TransformativeImageView_revert_duration
* @attr R.styleable#TransformativeImageView_revert
* @attr R.styleable#TransformativeImageView_scale_center
*/
public
class
TransformativeImageView
extends
AppCompatImageView
{
private
static
final
String
TAG
=
TransformativeImageView
.
class
.
getSimpleName
();
private
static
final
float
MAX_SCALE_FACTOR
=
2.0f
;
// 默认最大缩放比例为2
private
static
final
float
UNSPECIFIED_SCALE_FACTOR
=
-
1
f
;
// 未指定缩放比例
private
static
final
float
MIN_SCALE_FACTOR
=
1.0f
;
// 默认最小缩放比例为0.3
// private static final float INIT_SCALE_FACTOR = 1.2f; // 默认适应控件大小后的初始化缩放比例
private
static
final
float
INIT_SCALE_FACTOR
=
0.5f
;
// 默认适应控件大小后的初始化缩放比例
private
static
final
int
DEFAULT_REVERT_DURATION
=
300
;
private
int
mRevertDuration
=
DEFAULT_REVERT_DURATION
;
// 回弹动画时间
private
float
mMaxScaleFactor
=
MAX_SCALE_FACTOR
;
// 最大缩放比例
private
float
mMinScaleFactor
=
UNSPECIFIED_SCALE_FACTOR
;
// 此最小缩放比例优先级高于下面两个
private
float
mVerticalMinScaleFactor
=
MIN_SCALE_FACTOR
;
// 图片最初的最小缩放比例
private
float
mHorizontalMinScaleFactor
=
MIN_SCALE_FACTOR
;
// 图片旋转90(或-90)度后的的最小缩放比例
protected
Matrix
mMatrix
=
new
Matrix
();
// 用于图片旋转、平移、缩放的矩阵
protected
RectF
mImageRect
=
new
RectF
();
// 保存图片所在区域矩形,坐标为相对于本View的坐标
private
boolean
mOpenScaleRevert
=
false
;
// 是否开启缩放回弹
private
boolean
mOpenRotateRevert
=
false
;
// 是否开启旋转回弹
private
boolean
mOpenTranslateRevert
=
false
;
// 是否开启平移回弹
private
boolean
mOpenAnimator
=
false
;
// 是否开启动画
private
boolean
mOpenRotate
=
true
;
// 是否开启旋转
private
boolean
mOpenScale
=
true
;
// 是否开启缩放
private
boolean
mOpenTranslate
=
true
;
// 是否开启平移
private
boolean
mOpenBorder
=
false
;
// 是否显示边框
private
Paint
paint
=
new
Paint
();
private
float
srokeWidth
=
2
f
;
public
TransformativeImageView
(
Context
context
)
{
this
(
context
,
null
);
}
public
TransformativeImageView
(
Context
context
,
AttributeSet
attrs
)
{
this
(
context
,
attrs
,
0
);
}
public
TransformativeImageView
(
Context
context
,
AttributeSet
attrs
,
int
defStyleAttr
)
{
super
(
context
,
attrs
,
defStyleAttr
);
obtainAttrs
(
attrs
);
init
();
}
private
void
obtainAttrs
(
AttributeSet
attrs
)
{
if
(
attrs
==
null
)
return
;
TypedArray
typedArray
=
getContext
()
.
obtainStyledAttributes
(
attrs
,
R
.
styleable
.
TransformativeImageView
);
mMaxScaleFactor
=
typedArray
.
getFloat
(
R
.
styleable
.
TransformativeImageView_max_scale
,
MAX_SCALE_FACTOR
);
// mMinScaleFactor = typedArray.getFloat(
// R.styleable.TransformativeImageView_min_scale, UNSPECIFIED_SCALE_FACTOR);
mMinScaleFactor
=
typedArray
.
getFloat
(
R
.
styleable
.
TransformativeImageView_min_scale
,
MIN_SCALE_FACTOR
);
mRevertDuration
=
typedArray
.
getInteger
(
R
.
styleable
.
TransformativeImageView_revert_duration
,
DEFAULT_REVERT_DURATION
);
mOpenScaleRevert
=
typedArray
.
getBoolean
(
R
.
styleable
.
TransformativeImageView_open_scale_revert
,
false
);
mOpenRotateRevert
=
typedArray
.
getBoolean
(
R
.
styleable
.
TransformativeImageView_open_rotate_revert
,
false
);
mOpenTranslateRevert
=
typedArray
.
getBoolean
(
R
.
styleable
.
TransformativeImageView_open_translate_revert
,
false
);
mOpenAnimator
=
typedArray
.
getBoolean
(
R
.
styleable
.
TransformativeImageView_open_animator
,
true
);
mScaleBy
=
typedArray
.
getInt
(
R
.
styleable
.
TransformativeImageView_scale_center
,
SCALE_BY_IMAGE_CENTER
);
mOpenRotate
=
typedArray
.
getBoolean
(
R
.
styleable
.
TransformativeImageView_open_rotate
,
true
);
mOpenScale
=
typedArray
.
getBoolean
(
R
.
styleable
.
TransformativeImageView_open_scale
,
true
);
mOpenTranslate
=
typedArray
.
getBoolean
(
R
.
styleable
.
TransformativeImageView_open_translate
,
true
);
typedArray
.
recycle
();
}
private
void
init
()
{
// FIXME 修复图片锯齿,关闭硬件加速ANTI_ALIAS_FLAG才能生效
// setLayerType(View.LAYER_TYPE_SOFTWARE, null);
setScaleType
(
ScaleType
.
MATRIX
);
mRevertAnimator
.
setDuration
(
mRevertDuration
);
paint
.
setColor
(
Color
.
WHITE
);
paint
.
setStrokeWidth
(
srokeWidth
);
paint
.
setStyle
(
Paint
.
Style
.
STROKE
);
}
@Override
protected
void
onLayout
(
boolean
changed
,
int
left
,
int
top
,
int
right
,
int
bottom
)
{
super
.
onLayout
(
changed
,
left
,
top
,
right
,
bottom
);
initImgPositionAndSize
();
}
/**
* 初始化图片位置和大小
*/
private
void
initImgPositionAndSize
()
{
mMatrix
.
reset
();
// 初始化ImageRect
refreshImageRect
();
// 计算缩放比例,使图片适应控件大小
mHorizontalMinScaleFactor
=
Math
.
min
(
getWidth
()
/
mImageRect
.
width
(),
getHeight
()
/
mImageRect
.
height
());
mVerticalMinScaleFactor
=
Math
.
min
(
getHeight
()
/
mImageRect
.
width
(),
getWidth
()
/
mImageRect
.
height
());
float
scaleFactor
=
mHorizontalMinScaleFactor
;
// 初始图片缩放比例比最小缩放比例稍大
scaleFactor
*=
INIT_SCALE_FACTOR
;
mScaleFactor
=
scaleFactor
;
mMatrix
.
postScale
(
scaleFactor
,
scaleFactor
,
mImageRect
.
centerX
(),
mImageRect
.
centerY
());
refreshImageRect
();
// 移动图片到中心
mMatrix
.
postTranslate
((
getRight
()
-
getLeft
())
/
2
-
mImageRect
.
centerX
(),
(
getBottom
()
-
getTop
())
/
2
-
mImageRect
.
centerY
());
applyMatrix
();
// 如果用户有指定最小缩放比例则使用用户指定的
if
(
mMinScaleFactor
!=
UNSPECIFIED_SCALE_FACTOR
)
{
mHorizontalMinScaleFactor
=
mMinScaleFactor
;
mVerticalMinScaleFactor
=
mMinScaleFactor
;
}
}
private
PaintFlagsDrawFilter
mDrawFilter
=
new
PaintFlagsDrawFilter
(
0
,
Paint
.
ANTI_ALIAS_FLAG
|
Paint
.
FILTER_BITMAP_FLAG
);
@Override
protected
void
onDraw
(
Canvas
canvas
)
{
canvas
.
setDrawFilter
(
mDrawFilter
);
if
(
mOpenBorder
)
{
canvas
.
drawRect
(
mImageRect
,
paint
);
}
super
.
onDraw
(
canvas
);
}
private
PointF
mLastPoint1
=
new
PointF
();
// 上次事件的第一个触点
private
PointF
mLastPoint2
=
new
PointF
();
// 上次事件的第二个触点
private
PointF
mCurrentPoint1
=
new
PointF
();
// 本次事件的第一个触点
private
PointF
mCurrentPoint2
=
new
PointF
();
// 本次事件的第二个触点
private
float
mScaleFactor
=
1.0f
;
// 当前的缩放倍数
private
boolean
mCanScale
=
false
;
// 是否可以缩放
protected
PointF
mLastMidPoint
=
new
PointF
();
// 图片平移时记录上一次ACTION_MOVE的点
private
PointF
mCurrentMidPoint
=
new
PointF
();
// 当前各触点的中点
protected
boolean
mCanDrag
=
false
;
// 是否可以平移
private
PointF
mLastVector
=
new
PointF
();
// 记录上一次触摸事件两指所表示的向量
private
PointF
mCurrentVector
=
new
PointF
();
// 记录当前触摸事件两指所表示的向量
private
boolean
mCanRotate
=
false
;
// 判断是否可以旋转
private
MatrixRevertAnimator
mRevertAnimator
=
new
MatrixRevertAnimator
();
// 回弹动画
private
float
[]
mFromMatrixValue
=
new
float
[
9
];
// 动画初始时矩阵值
private
float
[]
mToMatrixValue
=
new
float
[
9
];
// 动画终结时矩阵值
protected
boolean
isTransforming
=
false
;
// 图片是否正在变化
@Override
public
boolean
onTouchEvent
(
MotionEvent
event
)
{
PointF
midPoint
=
getMidPointOfFinger
(
event
);
switch
(
event
.
getActionMasked
())
{
case
MotionEvent
.
ACTION_DOWN
:
case
MotionEvent
.
ACTION_POINTER_DOWN
:
// 每次触摸事件开始都初始化mLastMidPonit
mLastMidPoint
.
set
(
midPoint
);
isTransforming
=
false
;
mRevertAnimator
.
cancel
();
// 新手指落下则需要重新判断是否可以对图片进行变换
mCanRotate
=
false
;
mCanScale
=
false
;
mCanDrag
=
false
;
if
(
event
.
getPointerCount
()
==
2
)
{
// 旋转、平移、缩放分别使用三个判断变量,避免后期某个操作执行条件改变
mCanScale
=
true
;
mLastPoint1
.
set
(
event
.
getX
(
0
),
event
.
getY
(
0
));
mLastPoint2
.
set
(
event
.
getX
(
1
),
event
.
getY
(
1
));
mCanRotate
=
true
;
mLastVector
.
set
(
event
.
getX
(
1
)
-
event
.
getX
(
0
),
event
.
getY
(
1
)
-
event
.
getY
(
0
));
}
else
if
(
event
.
getPointerCount
()
==
1
)
{
mCanDrag
=
true
;
}
break
;
case
MotionEvent
.
ACTION_MOVE
:
if
(
mCanDrag
&&
mOpenTranslate
)
translate
(
midPoint
);
if
(
mCanScale
&&
mOpenScale
)
scale
(
event
);
if
(
mCanRotate
&&
mOpenRotate
)
rotate
(
event
);
// 判断图片是否发生了变换
if
(!
getImageMatrix
().
equals
(
mMatrix
))
isTransforming
=
true
;
if
(
mCanDrag
||
mCanScale
||
mCanRotate
)
applyMatrix
();
break
;
case
MotionEvent
.
ACTION_UP
:
case
MotionEvent
.
ACTION_CANCEL
:
// 检测是否需要回弹
if
(
mOpenRotateRevert
||
mOpenScaleRevert
||
mOpenTranslateRevert
)
{
mMatrix
.
getValues
(
mFromMatrixValue
);
/*设置矩阵动画初始值*/
/* 旋转和缩放都会影响矩阵,进而影响后续需要使用到ImageRect的地方,
* 所以检测顺序不能改变
*/
if
(
mOpenRotateRevert
)
checkRotation
();
if
(
mOpenScaleRevert
)
checkScale
();
if
(
mOpenTranslateRevert
)
checkBorder
();
mMatrix
.
getValues
(
mToMatrixValue
);
/*设置矩阵动画结束值*/
if
(
mOpenAnimator
)
{
// 启动回弹动画
mRevertAnimator
.
setMatrixValue
(
mFromMatrixValue
,
mToMatrixValue
);
mRevertAnimator
.
cancel
();
mRevertAnimator
.
start
();
}
else
{
applyMatrix
();
}
}
case
MotionEvent
.
ACTION_POINTER_UP
:
mCanScale
=
false
;
mCanDrag
=
false
;
mCanRotate
=
false
;
break
;
}
super
.
onTouchEvent
(
event
);
return
true
;
}
private
void
rotate
(
MotionEvent
event
)
{
// 计算当前两指触点所表示的向量
mCurrentVector
.
set
(
event
.
getX
(
1
)
-
event
.
getX
(
0
),
event
.
getY
(
1
)
-
event
.
getY
(
0
));
// 获取旋转角度
float
degree
=
getRotateDegree
(
mLastVector
,
mCurrentVector
);
mMatrix
.
postRotate
(
degree
,
mImageRect
.
centerX
(),
mImageRect
.
centerY
());
mLastVector
.
set
(
mCurrentVector
);
}
/**
* 使用Math#atan2(double y, double x)方法求上次触摸事件两指所示向量与x轴的夹角,
* 再求出本次触摸事件两指所示向量与x轴夹角,最后求出两角之差即为图片需要转过的角度
*
* @param lastVector 上次触摸事件两指间连线所表示的向量
* @param currentVector 本次触摸事件两指间连线所表示的向量
* @return 两向量夹角,单位“度”,顺时针旋转时为正数,逆时针旋转时返回负数
*/
private
float
getRotateDegree
(
PointF
lastVector
,
PointF
currentVector
)
{
//上次触摸事件向量与x轴夹角
double
lastRad
=
Math
.
atan2
(
lastVector
.
y
,
lastVector
.
x
);
//当前触摸事件向量与x轴夹角
double
currentRad
=
Math
.
atan2
(
currentVector
.
y
,
currentVector
.
x
);
// 两向量与x轴夹角之差即为需要旋转的角度
double
rad
=
currentRad
-
lastRad
;
//“弧度”转“度”
return
(
float
)
Math
.
toDegrees
(
rad
);
}
protected
void
translate
(
PointF
midPoint
)
{
float
dx
=
midPoint
.
x
-
mLastMidPoint
.
x
;
float
dy
=
midPoint
.
y
-
mLastMidPoint
.
y
;
mMatrix
.
postTranslate
(
dx
,
dy
);
mLastMidPoint
.
set
(
midPoint
);
}
/**
* 计算所有触点的中点
*
* @param event 当前触摸事件
* @return 本次触摸事件所有触点的中点
*/
private
PointF
getMidPointOfFinger
(
MotionEvent
event
)
{
// 初始化mCurrentMidPoint
mCurrentMidPoint
.
set
(
0
f
,
0
f
);
int
pointerCount
=
event
.
getPointerCount
();
for
(
int
i
=
0
;
i
<
pointerCount
;
i
++)
{
mCurrentMidPoint
.
x
+=
event
.
getX
(
i
);
mCurrentMidPoint
.
y
+=
event
.
getY
(
i
);
}
mCurrentMidPoint
.
x
/=
pointerCount
;
mCurrentMidPoint
.
y
/=
pointerCount
;
return
mCurrentMidPoint
;
}
private
static
final
int
SCALE_BY_IMAGE_CENTER
=
0
;
// 以图片中心为缩放中心
private
static
final
int
SCALE_BY_FINGER_MID_POINT
=
1
;
// 以所有手指的中点为缩放中心
private
int
mScaleBy
=
SCALE_BY_FINGER_MID_POINT
;
private
PointF
scaleCenter
=
new
PointF
();
/**
* 获取图片的缩放中心,该属性可在外部设置,或通过xml文件设置
* 默认中心点为图片中心
*
* @return 图片的缩放中心点
*/
private
PointF
getScaleCenter
()
{
// 使用全局变量避免频繁创建变量
switch
(
mScaleBy
)
{
case
SCALE_BY_IMAGE_CENTER:
scaleCenter
.
set
(
mImageRect
.
centerX
(),
mImageRect
.
centerY
());
break
;
case
SCALE_BY_FINGER_MID_POINT:
scaleCenter
.
set
(
mLastMidPoint
.
x
,
mLastMidPoint
.
y
);
break
;
}
return
scaleCenter
;
}
private
void
scale
(
MotionEvent
event
)
{
PointF
scaleCenter
=
getScaleCenter
();
// 初始化当前两指触点
mCurrentPoint1
.
set
(
event
.
getX
(
0
),
event
.
getY
(
0
));
mCurrentPoint2
.
set
(
event
.
getX
(
1
),
event
.
getY
(
1
));
// 计算缩放比例
float
scaleFactor
=
distance
(
mCurrentPoint1
,
mCurrentPoint2
)
/
distance
(
mLastPoint1
,
mLastPoint2
);
// 更新当前图片的缩放比例
mScaleFactor
*=
scaleFactor
;
mMatrix
.
postScale
(
scaleFactor
,
scaleFactor
,
scaleCenter
.
x
,
scaleCenter
.
y
);
mLastPoint1
.
set
(
mCurrentPoint1
);
mLastPoint2
.
set
(
mCurrentPoint2
);
}
/**
* 获取两点间距离
*/
private
float
distance
(
PointF
point1
,
PointF
point2
)
{
float
dx
=
point2
.
x
-
point1
.
x
;
float
dy
=
point2
.
y
-
point1
.
y
;
return
(
float
)
Math
.
sqrt
(
dx
*
dx
+
dy
*
dy
);
}
/**
* 根据当前图片旋转的角度,判断是否回弹
*/
private
void
checkRotation
()
{
float
currentDegree
=
getCurrentRotateDegree
();
float
degree
=
currentDegree
;
// 根据当前图片旋转的角度值所在区间,判断要转到几度
degree
=
Math
.
abs
(
degree
);
if
(
degree
>
45
&&
degree
<=
135
)
{
degree
=
90
;
}
else
if
(
degree
>
135
&&
degree
<=
225
)
{
degree
=
180
;
}
else
if
(
degree
>
225
&&
degree
<=
315
)
{
degree
=
270
;
}
else
{
degree
=
0
;
}
// 判断顺时针还是逆时针旋转
degree
=
currentDegree
<
0
?
-
degree
:
degree
;
mMatrix
.
postRotate
(
degree
-
currentDegree
,
mImageRect
.
centerX
(),
mImageRect
.
centerY
());
}
private
float
[]
xAxis
=
new
float
[]{
1
f
,
0
f
};
// 表示与x轴同方向的向量
/**
* 获取当前图片旋转角度
*
* @return 图片当前的旋转角度
*/
private
float
getCurrentRotateDegree
()
{
// 每次重置初始向量的值为与x轴同向
xAxis
[
0
]
=
1
f
;
xAxis
[
1
]
=
0
f
;
// 初始向量通过矩阵变换后的向量
mMatrix
.
mapVectors
(
xAxis
);
// 变换后向量与x轴夹角
double
rad
=
Math
.
atan2
(
xAxis
[
1
],
xAxis
[
0
]);
return
(
float
)
Math
.
toDegrees
(
rad
);
}
/**
* 检查图片缩放比例是否超过设置的大小
*/
private
void
checkScale
()
{
PointF
scaleCenter
=
getScaleCenter
();
float
scaleFactor
=
1.0f
;
// 获取图片当前是水平还是垂直
int
imgOrientation
=
imgOrientation
();
// 超过设置的上限或下限则回弹到设置的限制值
// 除以当前图片缩放比例mScaleFactor,postScale()方法执行后的图片的缩放比例即为被除数大小
if
(
imgOrientation
==
HORIZONTAL
&&
mScaleFactor
<
mHorizontalMinScaleFactor
)
{
scaleFactor
=
mHorizontalMinScaleFactor
/
mScaleFactor
;
}
else
if
(
imgOrientation
==
VERTICAL
&&
mScaleFactor
<
mVerticalMinScaleFactor
)
{
scaleFactor
=
mVerticalMinScaleFactor
/
mScaleFactor
;
}
else
if
(
mScaleFactor
>
mMaxScaleFactor
)
{
scaleFactor
=
mMaxScaleFactor
/
mScaleFactor
;
}
mMatrix
.
postScale
(
scaleFactor
,
scaleFactor
,
scaleCenter
.
x
,
scaleCenter
.
y
);
mScaleFactor
*=
scaleFactor
;
}
private
static
final
int
HORIZONTAL
=
0
;
private
static
final
int
VERTICAL
=
1
;
/**
* 判断图片当前是水平还是垂直
*
* @return 水平则返回 {@code HORIZONTAL},垂直则返回 {@code VERTICAL}
*/
private
int
imgOrientation
()
{
float
degree
=
Math
.
abs
(
getCurrentRotateDegree
());
int
orientation
=
HORIZONTAL
;
if
(
degree
>
45
f
&&
degree
<=
135
f
)
{
orientation
=
VERTICAL
;
}
return
orientation
;
}
/**
* 将图片移回控件中心
*/
private
void
checkBorder
()
{
// 由于旋转回弹与缩放回弹会影响图片所在位置,所以此处需要更新ImageRect的值
refreshImageRect
();
// 默认不移动
float
dx
=
0
f
;
float
dy
=
0
f
;
// mImageRect中的坐标值为相对View的值
// 图片宽大于控件时图片与控件之间不能有白边
if
(
mImageRect
.
width
()
>
getWidth
())
{
if
(
mImageRect
.
left
>
0
)
{
/*判断图片左边界与控件之间是否有空隙*/
dx
=
-
mImageRect
.
left
;
}
else
if
(
mImageRect
.
right
<
getWidth
())
{
/*判断图片右边界与控件之间是否有空隙*/
dx
=
getWidth
()
-
mImageRect
.
right
;
}
}
else
{
/*宽小于控件则移动到中心*/
dx
=
getWidth
()
/
2
-
mImageRect
.
centerX
();
}
// 图片高大于控件时图片与控件之间不能有白边
if
(
mImageRect
.
height
()
>
getHeight
())
{
if
(
mImageRect
.
top
>
0
)
{
/*判断图片上边界与控件之间是否有空隙*/
dy
=
-
mImageRect
.
top
;
}
else
if
(
mImageRect
.
bottom
<
getHeight
())
{
/*判断图片下边界与控件之间是否有空隙*/
dy
=
getHeight
()
-
mImageRect
.
bottom
;
}
}
else
{
/*高小于控件则移动到中心*/
dy
=
getHeight
()
/
2
-
mImageRect
.
centerY
();
}
mMatrix
.
postTranslate
(
dx
,
dy
);
}
/**
* 更新图片所在区域,并将矩阵应用到图片
*/
protected
void
applyMatrix
()
{
refreshImageRect
();
/*将矩阵映射到ImageRect*/
setImageMatrix
(
mMatrix
);
}
/**
* 图片使用矩阵变换后,刷新图片所对应的mImageRect所指示的区域
*/
private
void
refreshImageRect
()
{
if
(
getDrawable
()
!=
null
)
{
mImageRect
.
set
(
getDrawable
().
getBounds
());
mMatrix
.
mapRect
(
mImageRect
,
mImageRect
);
}
}
@Override
protected
void
onDetachedFromWindow
()
{
super
.
onDetachedFromWindow
();
mRevertAnimator
.
cancel
();
}
//-----Aninmator-------------------
/**
* 图片回弹动画
*/
private
class
MatrixRevertAnimator
extends
ValueAnimator
implements
ValueAnimator
.
AnimatorUpdateListener
{
private
float
[]
mFromMatrixValue
;
// 动画初始时矩阵值
private
float
[]
mToMatrixValue
;
// 动画终结时矩阵值
private
float
[]
mInterpolateMatrixValue
;
// 动画执行过程中矩阵值
MatrixRevertAnimator
()
{
mInterpolateMatrixValue
=
new
float
[
9
];
setFloatValues
(
0
f
,
1
f
);
addUpdateListener
(
this
);
}
void
setMatrixValue
(
float
[]
fromMatrixValue
,
final
float
[]
toMatrixValue
)
{
mFromMatrixValue
=
fromMatrixValue
;
mToMatrixValue
=
toMatrixValue
;
addListener
(
new
AnimatorListenerAdapter
()
{
@Override
public
void
onAnimationEnd
(
Animator
animation
)
{
mMatrix
.
setValues
(
toMatrixValue
);
applyMatrix
();
}
});
}
@Override
public
void
onAnimationUpdate
(
ValueAnimator
animation
)
{
if
(
mFromMatrixValue
!=
null
&&
mToMatrixValue
!=
null
&&
mInterpolateMatrixValue
!=
null
)
{
// 根据动画当前进度设置矩阵的值
for
(
int
i
=
0
;
i
<
9
;
i
++)
{
float
animatedValue
=
(
float
)
animation
.
getAnimatedValue
();
mInterpolateMatrixValue
[
i
]
=
mFromMatrixValue
[
i
]
+
(
mToMatrixValue
[
i
]
-
mFromMatrixValue
[
i
])
*
animatedValue
;
}
mMatrix
.
setValues
(
mInterpolateMatrixValue
);
applyMatrix
();
}
}
}
//-------getter and setter---------
public
void
setmMaxScaleFactor
(
float
mMaxScaleFactor
)
{
this
.
mMaxScaleFactor
=
mMaxScaleFactor
;
}
public
void
setmMinScaleFactor
(
float
mMinScaleFactor
)
{
this
.
mMinScaleFactor
=
mMinScaleFactor
;
}
public
void
setOpenScale
(
boolean
openScale
)
{
this
.
mOpenScale
=
openScale
;
}
public
void
setOpenTranslate
(
boolean
openTranslate
)
{
this
.
mOpenTranslate
=
openTranslate
;
}
public
void
setOpenRotate
(
boolean
openRotate
)
{
this
.
mOpenRotate
=
openRotate
;
}
public
void
setOpenBorder
(
boolean
openBorder
)
{
this
.
mOpenBorder
=
openBorder
;
invalidate
();
}
public
boolean
openBorder
()
{
return
this
.
mOpenBorder
;
}
}
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/WaveView.java
deleted
100644 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
widgets
;
import
android.animation.ValueAnimator
;
import
android.content.Context
;
import
android.graphics.Canvas
;
import
android.graphics.Color
;
import
android.graphics.Paint
;
import
android.graphics.Path
;
import
android.text.TextPaint
;
import
android.util.AttributeSet
;
import
android.view.View
;
import
android.view.animation.LinearInterpolator
;
public
class
WaveView
extends
View
{
private
int
width
=
0
;
private
int
height
=
0
;
private
int
baseLine
=
0
;
// 基线,用于控制水位上涨的,这里是写死了没动,你可以不断的设置改变。
private
Paint
mPaint
;
private
Paint
mCirclePaint
;
private
TextPaint
mTextPaint
=
new
TextPaint
(
Paint
.
ANTI_ALIAS_FLAG
);
private
int
waveHeight
=
26
;
// 波浪的最高度
private
int
waveWidth
;
//波长
private
float
offset
=
0
f
;
//偏移量
private
String
mForegroundColor
=
"#F61F03"
;
private
String
mProgressStr
=
"72%"
;
private
Path
mCirclePath
;
public
WaveView
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
initView
();
}
public
void
setProgressStr
(
String
progressStr
)
{
this
.
mProgressStr
=
progressStr
;
invalidate
();
}
public
void
setForegroundColor
(
String
foregroundColor
)
{
this
.
mForegroundColor
=
foregroundColor
;
invalidate
();
}
/**
* 不断的更新偏移量,并且循环。
*/
private
void
updateXControl
()
{
//设置一个波长的偏移
ValueAnimator
mAnimator
=
ValueAnimator
.
ofFloat
(
0
,
waveWidth
);
mAnimator
.
setInterpolator
(
new
LinearInterpolator
());
mAnimator
.
addUpdateListener
(
animation
->
{
float
animatorValue
=
(
float
)
animation
.
getAnimatedValue
();
offset
=
animatorValue
;
//不断的设置偏移量,并重画
postInvalidate
();
});
mAnimator
.
setDuration
(
1000
);
mAnimator
.
setRepeatCount
(
ValueAnimator
.
INFINITE
);
mAnimator
.
start
();
}
@Override
protected
void
onDraw
(
Canvas
canvas
)
{
super
.
onDraw
(
canvas
);
mPaint
.
setColor
(
Color
.
WHITE
);
canvas
.
drawPath
(
mCirclePath
,
mPaint
);
canvas
.
save
();
canvas
.
clipPath
(
mCirclePath
);
mPaint
.
setColor
(
Color
.
WHITE
);
canvas
.
drawPath
(
getPath
(),
mPaint
);
mPaint
.
setColor
(
Color
.
parseColor
(
mForegroundColor
));
mPaint
.
setStyle
(
Paint
.
Style
.
STROKE
);
mPaint
.
setStyle
(
Paint
.
Style
.
FILL
);
canvas
.
drawPath
(
getPath
(),
mPaint
);
mCirclePaint
.
setColor
(
Color
.
parseColor
(
mForegroundColor
));
canvas
.
drawCircle
(
waveWidth
/
2
,
waveWidth
/
2
,
waveWidth
/
2
-
2
f
,
mCirclePaint
);
canvas
.
drawText
(
mProgressStr
,
waveWidth
/
2
,
waveWidth
/
2
+
10
,
mTextPaint
);
canvas
.
restore
();
}
//初始化paint,没什么可说的。
private
void
initView
()
{
mPaint
=
new
Paint
();
mPaint
.
setStyle
(
Paint
.
Style
.
FILL
);
mPaint
.
setAntiAlias
(
true
);
mCirclePaint
=
new
Paint
();
mCirclePaint
.
setStrokeWidth
(
4
f
);
mCirclePaint
.
setStyle
(
Paint
.
Style
.
STROKE
);
mCirclePaint
.
setAntiAlias
(
true
);
mCirclePath
=
new
Path
();
mTextPaint
.
setStrokeWidth
(
1
f
);
mTextPaint
.
setTextSize
(
dp2px
(
getContext
(),
12
f
));
mTextPaint
.
setTextAlign
(
Paint
.
Align
.
CENTER
);
mTextPaint
.
setColor
(
Color
.
BLACK
);
mTextPaint
.
setStyle
(
Paint
.
Style
.
FILL
);
}
@Override
protected
void
onLayout
(
boolean
changed
,
int
left
,
int
top
,
int
right
,
int
bottom
)
{
super
.
onLayout
(
changed
,
left
,
top
,
right
,
bottom
);
width
=
getMeasuredWidth
();
//获取屏幕宽度
height
=
getMeasuredHeight
();
//获取屏幕高度
waveWidth
=
width
;
baseLine
=
height
/
2
-
10
;
updateXControl
();
int
circleRadius
=
height
<
width
?
height
/
2
:
width
/
2
;
mCirclePath
.
addCircle
(
width
/
2
,
height
/
2
,
circleRadius
,
Path
.
Direction
.
CCW
);
}
/**
* 核心代码,计算path
*
* @return
*/
private
Path
getPath
()
{
int
itemWidth
=
waveWidth
/
2
;
//半个波长
Path
mPath
=
new
Path
();
mPath
.
moveTo
(-
itemWidth
*
3
,
baseLine
);
//起始坐标
//核心的代码就是这里
for
(
int
i
=
-
3
;
i
<
2
;
i
++)
{
int
startX
=
i
*
itemWidth
;
mPath
.
quadTo
(
startX
+
itemWidth
/
2
+
offset
,
//控制点的X,(起始点X + itemWidth/2 + offset)
getWaveHeight
(
i
),
//控制点的Y
startX
+
itemWidth
+
offset
,
//结束点的X
baseLine
//结束点的Y
);
//只需要处理完半个波长,剩下的有for循环自已就添加了。
}
//下面这三句话很重要,它是形成了一封闭区间,让曲线以下的面积填充一种颜色,大家可以把这3句话注释了看看效果。
mPath
.
lineTo
(
width
,
height
);
mPath
.
lineTo
(
0
,
height
);
mPath
.
close
();
return
mPath
;
}
//奇数峰值是正的,偶数峰值是负数
private
int
getWaveHeight
(
int
num
)
{
if
(
num
%
2
==
0
)
{
return
baseLine
+
waveHeight
;
}
return
baseLine
-
waveHeight
;
}
private
float
dp2px
(
Context
context
,
Float
pxVal
)
{
return
pxVal
*
context
.
getResources
().
getDisplayMetrics
().
scaledDensity
+
0.5f
;
}
}
\ No newline at end of file
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/applock/GestureView.java
deleted
100644 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
widgets
.
applock
;
import
android.annotation.SuppressLint
;
import
android.content.Context
;
import
android.graphics.Canvas
;
import
android.graphics.Paint
;
import
android.graphics.Paint.Style
;
import
android.graphics.Path
;
import
android.view.View
;
import
com.mints.wisdomclean.utils.BubbleUtils
;
@SuppressLint
(
"ViewConstructor"
)
public
class
GestureView
extends
View
{
private
static
final
String
TAG
=
GestureView
.
class
.
getName
();
/**
* GestureLockView的三种状态
*/
enum
Mode
{
STATUS_NO_FINGER
,
STATUS_FINGER_ON
,
STATUS_FINGER_UP
;
}
/**
* GestureLockView的当前状态
*/
private
Mode
mCurrentStatus
=
Mode
.
STATUS_NO_FINGER
;
/**
* 宽度
*/
private
int
mWidth
;
/**
* 高度
*/
private
int
mHeight
;
/**
* 外圆半径
*/
private
int
mRadius
;
/**
* 画笔的宽度
*/
private
int
mStrokeWidth
=
2
;
/**
* 圆心坐标
*/
private
int
mCenterX
;
private
int
mCenterY
;
private
Paint
mPaint
;
/**
* 箭头(小三角最长边的一半长度 = mArrawRate * mWidth / 2 )
*/
private
float
mArrowRate
=
0.333f
;
private
int
mArrowDegree
=
-
1
;
private
Path
mArrowPath
;
/**
* 内圆的半径 = mInnerCircleRadiusRate * mRadus
*/
private
float
mInnerCircleRadiusRate
=
0.25f
;
/**
* 四个颜色,可由用户自定义,初始化时由GestureLockViewGroup传入
*/
private
int
mColorNoFingerInner
;
private
int
mColorNoFingerOutter
;
private
int
mColorFingerOn
;
private
int
mColorFingerUpMatched
;
private
int
mColorFingerUpNotMatched
;
private
boolean
matched
;
public
GestureView
(
Context
context
,
int
colorNoFingerInner
,
int
colorNoFingerOutter
,
int
colorFingerOn
,
int
colorFingerUpMatched
,
int
colorFingerUpNotMatched
)
{
super
(
context
);
this
.
mColorNoFingerInner
=
colorNoFingerInner
;
this
.
mColorNoFingerOutter
=
colorNoFingerOutter
;
this
.
mColorFingerOn
=
colorFingerOn
;
this
.
mColorFingerUpMatched
=
colorFingerUpMatched
;
this
.
mColorFingerUpNotMatched
=
colorFingerUpNotMatched
;
mPaint
=
new
Paint
(
Paint
.
ANTI_ALIAS_FLAG
);
mArrowPath
=
new
Path
();
mStrokeWidth
=
BubbleUtils
.
dp2px
(
1
);
}
@Override
protected
void
onMeasure
(
int
widthMeasureSpec
,
int
heightMeasureSpec
)
{
super
.
onMeasure
(
widthMeasureSpec
,
heightMeasureSpec
);
mWidth
=
MeasureSpec
.
getSize
(
widthMeasureSpec
);
mHeight
=
MeasureSpec
.
getSize
(
heightMeasureSpec
);
// 取长和宽中的小值
mWidth
=
Math
.
min
(
mWidth
,
mHeight
);
mCenterX
=
mCenterY
=
mWidth
/
2
;
mRadius
=
mWidth
/
3
;
mRadius
-=
mStrokeWidth
/
2
;
// 绘制三角形,初始时是个默认箭头朝上的一个等腰三角形,用户绘制结束后,根据由两个GestureLockView决定需要旋转多少度
float
mArrowLength
=
mWidth
/
2
*
mArrowRate
;
mArrowPath
.
moveTo
(
mWidth
/
2
,
mStrokeWidth
+
2
);
mArrowPath
.
lineTo
(
mWidth
/
2
-
mArrowLength
,
mStrokeWidth
+
2
+
mArrowLength
);
mArrowPath
.
lineTo
(
mWidth
/
2
+
mArrowLength
,
mStrokeWidth
+
2
+
mArrowLength
);
mArrowPath
.
close
();
mArrowPath
.
setFillType
(
Path
.
FillType
.
WINDING
);
}
@Override
protected
void
onDraw
(
Canvas
canvas
)
{
switch
(
mCurrentStatus
)
{
case
STATUS_FINGER_ON:
// 绘制外圆
mPaint
.
setStyle
(
Style
.
FILL
);
//
mPaint
.
setColor
(
0x33ffffff
);
mPaint
.
setStrokeWidth
(
mStrokeWidth
);
canvas
.
drawCircle
(
mCenterX
,
mCenterY
,
mRadius
,
mPaint
);
// 绘制外圆环
mPaint
.
setStyle
(
Style
.
STROKE
);
mPaint
.
setColor
(
0x99fdfdfd
);
mPaint
.
setStrokeWidth
(
mStrokeWidth
);
canvas
.
drawCircle
(
mCenterX
,
mCenterY
,
mRadius
,
mPaint
);
// 绘制内圆
mPaint
.
setStyle
(
Style
.
FILL
);
mPaint
.
setColor
(
mColorFingerOn
);
canvas
.
drawCircle
(
mCenterX
,
mCenterY
,
mRadius
*
mInnerCircleRadiusRate
,
mPaint
);
break
;
case
STATUS_FINGER_UP:
if
(
matched
)
{
// 绘制外圆环
mPaint
.
setColor
(
mColorFingerUpMatched
);
mPaint
.
setStyle
(
Style
.
STROKE
);
mPaint
.
setStrokeWidth
(
mStrokeWidth
);
canvas
.
drawCircle
(
mCenterX
,
mCenterY
,
mRadius
,
mPaint
);
}
else
{
// 外圆
mPaint
.
setStyle
(
Style
.
FILL
);
mPaint
.
setColor
(
0x33ff5c5c
);
mPaint
.
setStrokeWidth
(
mStrokeWidth
);
canvas
.
drawCircle
(
mCenterX
,
mCenterY
,
mRadius
,
mPaint
);
// 外圆环
mPaint
.
setColor
(
0x99e3362d
);
mPaint
.
setStyle
(
Style
.
STROKE
);
mPaint
.
setStrokeWidth
(
mStrokeWidth
);
canvas
.
drawCircle
(
mCenterX
,
mCenterY
,
mRadius
,
mPaint
);
mPaint
.
setColor
(
mColorFingerUpNotMatched
);
}
// 绘制内圆
mPaint
.
setStyle
(
Style
.
FILL
);
canvas
.
drawCircle
(
mCenterX
,
mCenterY
,
mRadius
*
mInnerCircleRadiusRate
,
mPaint
);
// drawArrow(canvas);
break
;
case
STATUS_NO_FINGER:
// 绘制外圆
mPaint
.
setStyle
(
Style
.
STROKE
);
mPaint
.
setStrokeWidth
(
mStrokeWidth
);
mPaint
.
setColor
(
mColorNoFingerOutter
);
canvas
.
drawCircle
(
mCenterX
,
mCenterY
,
mRadius
,
mPaint
);
// 绘制内圆
mPaint
.
setStyle
(
Style
.
FILL
);
mPaint
.
setColor
(
mColorNoFingerInner
);
canvas
.
drawCircle
(
mCenterX
,
mCenterY
,
mRadius
*
mInnerCircleRadiusRate
,
mPaint
);
break
;
}
}
/**
* 绘制箭头
*
* @param canvas
*/
private
void
drawArrow
(
Canvas
canvas
)
{
if
(
mArrowDegree
!=
-
1
)
{
mPaint
.
setStyle
(
Style
.
FILL
);
canvas
.
save
();
canvas
.
rotate
(
mArrowDegree
,
mCenterX
,
mCenterY
);
canvas
.
drawPath
(
mArrowPath
,
mPaint
);
canvas
.
restore
();
}
}
public
void
setMatched
(
boolean
matched
)
{
this
.
matched
=
matched
;
}
/**
* 设置当前模式并重绘界面
*
* @param mode
*/
public
void
setMode
(
Mode
mode
)
{
this
.
mCurrentStatus
=
mode
;
invalidate
();
}
public
void
setArrowDegree
(
int
degree
)
{
this
.
mArrowDegree
=
degree
;
}
public
int
getArrowDegree
()
{
return
this
.
mArrowDegree
;
}
}
video/app/src/main/java/com/mints/wisdomclean/ui/widgets/applock/GestureViewGroup.java
deleted
100644 → 0
View file @
1af1a0f7
package
com
.
mints
.
wisdomclean
.
ui
.
widgets
.
applock
;
import
android.content.Context
;
import
android.content.res.TypedArray
;
import
android.graphics.Canvas
;
import
android.graphics.Paint
;
import
android.graphics.Path
;
import
android.graphics.Point
;
import
android.os.Handler
;
import
android.util.AttributeSet
;
import
android.view.MotionEvent
;
import
android.view.View
;
import
android.widget.RelativeLayout
;
import
com.mints.wisdomclean.R
;
import
com.mints.wisdomclean.utils.BubbleUtils
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* 整体包含n*n个GestureLockView,每个GestureLockView间间隔mMarginBetweenLockView,
* 最外层的GestureLockView与容器存在mMarginBetweenLockView的外边距
*
* 关于GestureLockView的边长(n*n): n * mGestureLockViewWidth + ( n + 1 ) *
* mMarginBetweenLockView = mWidth ; 得:mGestureLockViewWidth = 4 * mWidth / ( 5
* * mCount + 1 ) 注:mMarginBetweenLockView = mGestureLockViewWidth * 0.25 ;
*
* @author
*
*/
public
class
GestureViewGroup
extends
RelativeLayout
{
private
static
final
String
TAG
=
GestureViewGroup
.
class
.
getName
();
/**
* 保存所有的GestureLockView
*/
private
GestureView
[]
mGestureLockViews
;
/**
* 每个边上的GestureLockView的个数
*/
private
int
mCount
=
3
;
/**
* 存储答案
*/
private
int
[]
mAnswer
=
new
int
[
0
];
/**
* 保存用户选中的GestureLockView的id
*/
private
final
List
<
Integer
>
mChoose
=
new
ArrayList
<>();
private
Paint
mPaint
;
/**
* 每个GestureLockView中间的间距 设置为:mGestureLockViewWidth * 25%
*/
private
int
mMarginBetweenLockView
=
0
;
/**
* GestureLockView的边长 4 * mWidth / ( 5 * mCount + 1 )
*/
private
int
mGestureLockViewWidth
=
0
;
/**
* GestureLockView无手指触摸的状态下内圆的颜色
*/
private
int
mNoFingerInnerCircleColor
=
0xffffffff
;
/**
* GestureLockView无手指触摸的状态下外圆的颜色
*/
private
int
mNoFingerOuterCircleColor
=
0xfffdfdfd
;
/**
* GestureLockView手指触摸的状态下内圆和外圆的颜色
*/
private
int
mFingerOnColor
=
0xffffffff
;
/**
* GestureLockView手指抬起的状态下内圆和外圆的颜色
*/
private
int
mFingerUpMatchedColor
=
0xffffffff
;
private
int
mFingerUpNotMatchedColor
=
0xffe3362d
;
/**
* 宽度
*/
private
int
mWidth
;
/**
* 高度
*/
private
int
mHeight
;
private
Path
mPath
;
/**
* 指引线的开始位置x
*/
private
int
mLastPathX
;
/**
* 指引线的开始位置y
*/
private
int
mLastPathY
;
/**
* 指引下的结束位置
*/
private
final
Point
mTmpTarget
=
new
Point
();
/**
* 最大尝试次数
*/
private
int
mTryTimes
=
4
;
/**
* 回调接口
*/
private
OnGestureViewListener
mOnGestureLockViewListener
;
// set password or verify password, verify password: if not matched, show red color; set password: first,show green, second(confirm the first ),show red if not match first
private
boolean
setPasswordMode
=
false
;
private
int
inputCorrectPasswordCount
=
0
;
public
GestureViewGroup
(
Context
context
,
AttributeSet
attrs
)
{
this
(
context
,
attrs
,
0
);
}
public
GestureViewGroup
(
Context
context
,
AttributeSet
attrs
,
int
defStyle
)
{
super
(
context
,
attrs
,
defStyle
);
/**
* 获得所有自定义的参数的值
*/
TypedArray
a
=
context
.
getTheme
().
obtainStyledAttributes
(
attrs
,
R
.
styleable
.
GestureLockViewGroup
,
defStyle
,
0
);
int
n
=
a
.
getIndexCount
();
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
int
attr
=
a
.
getIndex
(
i
);
switch
(
attr
)
{
case
R
.
styleable
.
GestureLockViewGroup_color_no_finger_inner_circle
:
mNoFingerInnerCircleColor
=
a
.
getColor
(
attr
,
mNoFingerInnerCircleColor
);
break
;
case
R
.
styleable
.
GestureLockViewGroup_color_no_finger_outer_circle
:
mNoFingerOuterCircleColor
=
a
.
getColor
(
attr
,
mNoFingerOuterCircleColor
);
break
;
case
R
.
styleable
.
GestureLockViewGroup_outer_circle_width
:
mGestureLockViewWidth
=
(
int
)
a
.
getDimension
(
attr
,
mGestureLockViewWidth
);
break
;
case
R
.
styleable
.
GestureLockViewGroup_margin_between_vircle
:
mMarginBetweenLockView
=
(
int
)
a
.
getDimension
(
attr
,
mMarginBetweenLockView
);
break
;
case
R
.
styleable
.
GestureLockViewGroup_color_finger_on
:
mFingerOnColor
=
a
.
getColor
(
attr
,
mFingerOnColor
);
break
;
case
R
.
styleable
.
GestureLockViewGroup_color_finger_up
:
mFingerUpMatchedColor
=
a
.
getColor
(
attr
,
mFingerUpMatchedColor
);
break
;
case
R
.
styleable
.
GestureLockViewGroup_count
:
mCount
=
a
.
getInt
(
attr
,
3
);
break
;
case
R
.
styleable
.
GestureLockViewGroup_tryTimes
:
mTryTimes
=
a
.
getInt
(
attr
,
5
);
default
:
break
;
}
}
a
.
recycle
();
// 初始化画笔
mPaint
=
new
Paint
(
Paint
.
ANTI_ALIAS_FLAG
);
mPaint
.
setStyle
(
Paint
.
Style
.
STROKE
);
mPaint
.
setStrokeWidth
(
BubbleUtils
.
dp2px
(
3
));
mPaint
.
setStrokeCap
(
Paint
.
Cap
.
ROUND
);
mPaint
.
setStrokeJoin
(
Paint
.
Join
.
ROUND
);
// mPaint.setColor(Color.parseColor("#aaffffff"));
mPath
=
new
Path
();
setPasswordMode
=
false
;
inputCorrectPasswordCount
=
0
;
}
@Override
protected
void
onMeasure
(
int
widthMeasureSpec
,
int
heightMeasureSpec
)
{
super
.
onMeasure
(
widthMeasureSpec
,
heightMeasureSpec
);
mWidth
=
MeasureSpec
.
getSize
(
widthMeasureSpec
);
mHeight
=
MeasureSpec
.
getSize
(
heightMeasureSpec
);
mHeight
=
mWidth
=
mWidth
<
mHeight
?
mWidth
:
mHeight
;
// setMeasuredDimension(mWidth, mHeight);
// 初始化mGestureLockViews
if
(
mGestureLockViews
==
null
)
{
mGestureLockViews
=
new
GestureView
[
mCount
*
mCount
];
// 计算每个GestureLockView的宽度
if
(
mGestureLockViewWidth
==
0
)
{
// mGestureLockViewWidth = (int) (4 * mWidth * 1.0f / (5 * mCount + 1));
mGestureLockViewWidth
=
(
int
)
(
mWidth
*
1.0f
/
4
f
);
}
// 计算每个GestureLockView的间距
if
(
mMarginBetweenLockView
==
0
)
{
// mMarginBetweenLockView = mGestureLockViewWidth / 4;
mMarginBetweenLockView
=
mWidth
/
8
;
}
// 设置画笔的宽度为GestureLockView的内圆直径稍微小点(不喜欢的话,随便设)
// mPaint.setStrokeWidth(mGestureLockViewWidth * 0.29f);
for
(
int
i
=
0
;
i
<
mGestureLockViews
.
length
;
i
++)
{
// 初始化每个GestureLockView
mGestureLockViews
[
i
]
=
new
GestureView
(
getContext
(),
mNoFingerInnerCircleColor
,
mNoFingerOuterCircleColor
,
mFingerOnColor
,
mFingerUpMatchedColor
,
mFingerUpNotMatchedColor
);
mGestureLockViews
[
i
].
setId
(
i
+
1
);
// 设置参数,主要是定位GestureLockView间的位置
LayoutParams
lockerParams
=
new
LayoutParams
(
mGestureLockViewWidth
,
mGestureLockViewWidth
);
// 不是每行的第一个,则设置位置为前一个的右边
if
(
i
%
mCount
!=
0
)
{
lockerParams
.
addRule
(
RelativeLayout
.
RIGHT_OF
,
mGestureLockViews
[
i
-
1
].
getId
());
}
// 从第二行开始,设置为上一行同一位置View的下面
if
(
i
>
mCount
-
1
)
{
lockerParams
.
addRule
(
RelativeLayout
.
BELOW
,
mGestureLockViews
[
i
-
mCount
].
getId
());
}
// 设置右下左上的边距
int
rightMargin
=
0
;
int
bottomMargin
=
0
;
int
leftMagin
=
mMarginBetweenLockView
;
int
topMargin
=
mMarginBetweenLockView
;
/**
* 每个View都有右外边距和底外边距 第一行的有上外边距 第一列的有左外边距
*/
if
(
i
>=
0
&&
i
<
mCount
)
// 第一行
{
topMargin
=
0
;
}
if
(
i
%
mCount
==
0
)
// 第一列
{
leftMagin
=
0
;
}
lockerParams
.
setMargins
(
leftMagin
,
topMargin
,
rightMargin
,
bottomMargin
);
mGestureLockViews
[
i
].
setMode
(
GestureView
.
Mode
.
STATUS_NO_FINGER
);
addView
(
mGestureLockViews
[
i
],
lockerParams
);
}
}
}
@Override
public
boolean
onTouchEvent
(
MotionEvent
event
)
{
int
action
=
event
.
getAction
();
int
x
=
(
int
)
event
.
getX
();
int
y
=
(
int
)
event
.
getY
();
switch
(
action
)
{
case
MotionEvent
.
ACTION_DOWN
:
// 重置
reset
();
// going through
case
MotionEvent
.
ACTION_MOVE
:
mPaint
.
setColor
(
mFingerOnColor
);
mPaint
.
setAlpha
(
50
);
GestureView
child
=
getChildIdByPos
(
x
,
y
);
if
(
child
!=
null
)
{
int
cId
=
child
.
getId
();
if
(!
mChoose
.
contains
(
cId
))
{
mChoose
.
add
(
cId
);
child
.
setMode
(
GestureView
.
Mode
.
STATUS_FINGER_ON
);
if
(
mOnGestureLockViewListener
!=
null
)
mOnGestureLockViewListener
.
onBlockSelected
(
cId
);
// 设置指引线的起点
mLastPathX
=
child
.
getLeft
()
/
2
+
child
.
getRight
()
/
2
;
mLastPathY
=
child
.
getTop
()
/
2
+
child
.
getBottom
()
/
2
;
if
(
mChoose
.
size
()
==
1
)
// 当前添加为第一个
{
mPath
.
moveTo
(
mLastPathX
,
mLastPathY
);
}
else
// 非第一个,将两者使用线连上
{
mPath
.
lineTo
(
mLastPathX
,
mLastPathY
);
}
}
}
// 指引线的终点
mTmpTarget
.
x
=
x
;
mTmpTarget
.
y
=
y
;
break
;
case
MotionEvent
.
ACTION_UP
:
// first input password and >= 4 dot
// Log.e(TAG, "inputCorrectPasswordCount:"+inputCorrectPasswordCount);
boolean
fistInputCorrectPassword
=
setPasswordMode
&&
((
inputCorrectPasswordCount
&
1
)==
0
)
&&
mChoose
.
size
()
>=
4
;
//if first input dot >=4 or the second input(confirm step)
if
(
fistInputCorrectPassword
||(
setPasswordMode
&&
((
inputCorrectPasswordCount
&
1
)==
1
))){
inputCorrectPasswordCount
++;
}
boolean
matched
=
checkAnswer
();
//for confirm step, if matched is false, the fistInputCorrectPassword is always false
matched
=
matched
||
fistInputCorrectPassword
;
for
(
int
i
=
0
;
i
<
mGestureLockViews
.
length
;
i
++)
{
// 初始化每个GestureLockView
mGestureLockViews
[
i
].
setMatched
(
matched
);
}
if
(
matched
)
{
mPaint
.
setColor
(
0x99ffffff
);
}
else
{
mPaint
.
setColor
(
0x99ff352b
);
}
mPaint
.
setAlpha
(
50
);
this
.
mTryTimes
--;
// 回调是否成功
if
(
mOnGestureLockViewListener
!=
null
&&
mChoose
.
size
()
>
0
)
{
mOnGestureLockViewListener
.
onGestureEvent
(
matched
);
if
(
this
.
mTryTimes
==
0
)
{
mOnGestureLockViewListener
.
onUnmatchedExceedBoundary
();
}
}
// Log.e(TAG, "mUnMatchExceedBoundary = " + mTryTimes);
// Log.e(TAG, "mChoose = " + mChoose);
// 将终点设置位置为起点,即取消指引线
mTmpTarget
.
x
=
mLastPathX
;
mTmpTarget
.
y
=
mLastPathY
;
// 改变子元素的状态为UP
changeItemMode
();
// 计算每个元素中箭头需要旋转的角度
for
(
int
i
=
0
;
i
+
1
<
mChoose
.
size
();
i
++)
{
int
childId
=
mChoose
.
get
(
i
);
int
nextChildId
=
mChoose
.
get
(
i
+
1
);
GestureView
startChild
=
(
GestureView
)
findViewById
(
childId
);
GestureView
nextChild
=
(
GestureView
)
findViewById
(
nextChildId
);
int
dx
=
nextChild
.
getLeft
()
-
startChild
.
getLeft
();
int
dy
=
nextChild
.
getTop
()
-
startChild
.
getTop
();
// 计算角度
int
angle
=
(
int
)
Math
.
toDegrees
(
Math
.
atan2
(
dy
,
dx
))
+
90
;
startChild
.
setArrowDegree
(
angle
);
}
break
;
}
invalidate
();
return
true
;
}
private
void
changeItemMode
()
{
for
(
GestureView
gestureLockView
:
mGestureLockViews
)
{
if
(
mChoose
.
contains
(
gestureLockView
.
getId
()))
{
gestureLockView
.
setMode
(
GestureView
.
Mode
.
STATUS_FINGER_UP
);
}
}
}
/**
*
* 做一些必要的重置
*/
public
void
reset
()
{
mChoose
.
clear
();
mPath
.
reset
();
if
(
mGestureLockViews
!=
null
)
{
for
(
GestureView
gestureLockView
:
mGestureLockViews
)
{
gestureLockView
.
setMode
(
GestureView
.
Mode
.
STATUS_NO_FINGER
);
gestureLockView
.
setArrowDegree
(-
1
);
}
}
invalidate
();
}
public
void
setGestureLockSet
(
boolean
setPasswordMode
){
this
.
setPasswordMode
=
setPasswordMode
;
}
/**
* 指定时间去清除绘制的状态
*
* @param delayTime
* 延迟执行时间
*/
public
void
clear
(
long
delayTime
)
{
new
Handler
().
postDelayed
(
new
clearStateRunnable
(),
delayTime
);
}
public
void
clear
()
{
new
Handler
().
postDelayed
(
new
clearStateRunnable
(),
200
);
}
/**
* 清除绘制状态的线程
*/
final
class
clearStateRunnable
implements
Runnable
{
public
void
run
()
{
reset
();
}
}
/**
* 检查用户绘制的手势是否正确
*
* @return
*/
private
boolean
checkAnswer
()
{
if
(
mAnswer
.
length
!=
mChoose
.
size
())
return
false
;
for
(
int
i
=
0
;
i
<
mAnswer
.
length
;
i
++)
{
if
(
mAnswer
[
i
]
!=
mChoose
.
get
(
i
))
return
false
;
}
return
true
;
}
/**
* 检查当前左边是否在child中
*
* @param child
* @param x
* @param y
* @return
*/
private
boolean
checkPositionInChild
(
View
child
,
int
x
,
int
y
)
{
// 设置了内边距,即x,y必须落入下GestureLockView的内部中间的小区域中,可以通过调整padding使得x,y落入范围不变大,或者不设置padding
int
padding
=
mChoose
.
isEmpty
()
?
0
:
(
int
)
(
mGestureLockViewWidth
*
0.15
);
if
(
x
>=
child
.
getLeft
()
+
padding
&&
x
<=
child
.
getRight
()
-
padding
&&
y
>=
child
.
getTop
()
+
padding
&&
y
<=
child
.
getBottom
()
-
padding
)
{
return
true
;
}
return
false
;
}
/**
* 通过x,y获得落入的GestureLockView
*
* @param x
* @param y
* @return
*/
private
GestureView
getChildIdByPos
(
int
x
,
int
y
)
{
for
(
GestureView
gestureLockView
:
mGestureLockViews
)
{
if
(
checkPositionInChild
(
gestureLockView
,
x
,
y
))
{
return
gestureLockView
;
}
}
return
null
;
}
/**
* 设置回调接口
*
* @param listener
*/
public
void
setOnGestureLockViewListener
(
OnGestureViewListener
listener
)
{
this
.
mOnGestureLockViewListener
=
listener
;
}
/*
*
* get the set password
*/
public
int
[]
getAnswer
()
{
int
[]
answer
=
new
int
[
mChoose
.
size
()];
for
(
int
i
=
0
;
i
<
mChoose
.
size
();
i
++)
{
answer
[
i
]
=
mChoose
.
get
(
i
);
}
return
answer
;
}
/**
* 对外公布设置答案的方法
*
* @param answer
*/
public
void
setAnswer
(
int
[]
answer
)
{
if
(
answer
==
null
)
{
this
.
mAnswer
=
new
int
[
0
];
}
else
{
this
.
mAnswer
=
answer
;
}
}
/**
* 设置最大实验次数
*
* @param boundary
*/
public
void
setUnMatchExceedBoundary
(
int
boundary
)
{
this
.
mTryTimes
=
boundary
;
}
@Override
public
void
dispatchDraw
(
Canvas
canvas
)
{
super
.
dispatchDraw
(
canvas
);
// 绘制GestureLockView间的连线
if
(
mPath
!=
null
)
{
canvas
.
drawPath
(
mPath
,
mPaint
);
}
// 绘制指引线
if
(
mChoose
.
size
()
>
0
)
{
if
(
mLastPathX
!=
0
&&
mLastPathY
!=
0
)
canvas
.
drawLine
(
mLastPathX
,
mLastPathY
,
mTmpTarget
.
x
,
mTmpTarget
.
y
,
mPaint
);
}
}
public
interface
OnGestureViewListener
{
/**
* 单独选中元素的Id
*
* @param cId
*/
public
void
onBlockSelected
(
int
cId
);
/**
* 是否匹配
*
* @param matched
*/
public
void
onGestureEvent
(
boolean
matched
);
/**
* 超过尝试次数
*/
public
void
onUnmatchedExceedBoundary
();
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment