├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── org
│ │ └── zhgeaits
│ │ └── risv
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── org
│ │ └── zhgeaits
│ │ ├── demo
│ │ └── MainActivity.java
│ │ └── risv
│ │ ├── CustomHorizontalScrollView.java
│ │ ├── DimenConverter.java
│ │ ├── MultiPointBar.java
│ │ ├── MultiRangebar.java
│ │ ├── RangeImageSelectedView.java
│ │ └── VideoImageSeekbar.java
│ └── res
│ ├── drawable
│ ├── img_bar_bg.xml
│ ├── img_bar_left.xml
│ ├── img_bar_right.xml
│ ├── left_arrow_selector.xml
│ ├── multi_range_bg.xml
│ └── right_arrow_selector.xml
│ ├── layout
│ ├── activity_main.xml
│ └── layout_image_seekbar.xml
│ ├── menu
│ └── menu_main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ ├── left_arrow_normal.png
│ ├── left_arrow_press.png
│ ├── point_arrow.png
│ ├── right_arrow_normal.png
│ ├── right_arrow_press.png
│ ├── test.jpg
│ └── vertical_bar.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── rangview.gif
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .idea
3 | .gradle
4 | /local.properties
5 | /.idea/workspace.xml
6 | /.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 | */build
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 效果
2 |
3 | 
4 |
5 | ## 使用
6 |
7 | 这是一个简单的区间选择控件,从以前的项目抽取出来的,所以里面会有包含一些业务代码,不过由于控件简单,请随意修改使用。
8 |
9 | ## TODO
10 |
11 | 1.优化代码使之成为更加通用的模块
12 |
13 | ## 实现
14 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | applicationId "org.zhgeaits.risv"
9 | minSdkVersion 15
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile 'com.android.support:appcompat-v7:23.1.1'
25 | }
26 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/shenqu_ugc/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/org/zhgeaits/risv/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package org.zhgeaits.risv;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/org/zhgeaits/demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package org.zhgeaits.demo;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.Button;
7 |
8 | import org.zhgeaits.risv.R;
9 | import org.zhgeaits.risv.VideoImageSeekbar;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | public class MainActivity extends Activity {
15 |
16 | private VideoImageSeekbar seekbar;
17 | private Button setImage;
18 | private Button addWindow;
19 | private Button addFixedWindow;
20 | private Button addrange;
21 | private Button addpoint;
22 | private Button removeWindow;
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_main);
28 |
29 | seekbar = (VideoImageSeekbar) findViewById(R.id.image_bar);
30 | setImage = (Button) findViewById(R.id.set_image);
31 | addWindow = (Button) findViewById(R.id.window);
32 | addFixedWindow = (Button) findViewById(R.id.fixed_window);
33 | addrange = (Button) findViewById(R.id.add_range_bar);
34 | addpoint = (Button) findViewById(R.id.add_range_point);
35 | removeWindow = (Button) findViewById(R.id.remove_window);
36 |
37 | setImage.setOnClickListener(new View.OnClickListener() {
38 | @Override
39 | public void onClick(View v) {
40 | List ids = new ArrayList<>();
41 | for (int i = 0; i < 20; i++) {
42 | ids.add(R.mipmap.test);
43 | }
44 | seekbar.setProgress(0);
45 | seekbar.setImageListIds(ids);
46 | }
47 | });
48 |
49 | addWindow.setOnClickListener(new View.OnClickListener() {
50 | @Override
51 | public void onClick(View v) {
52 | seekbar.addScaledRangeView(0, seekbar.getCurrentProgress(), 30);
53 | }
54 | });
55 |
56 | removeWindow.setOnClickListener(new View.OnClickListener() {
57 | @Override
58 | public void onClick(View v) {
59 | seekbar.removeRangeView(0);
60 | }
61 | });
62 |
63 | addFixedWindow.setOnClickListener(new View.OnClickListener() {
64 | @Override
65 | public void onClick(View v) {
66 | seekbar.addFixedRangeView(0, seekbar.getCurrentProgress(), 30, 30);
67 | }
68 | });
69 |
70 | addrange.setOnClickListener(new View.OnClickListener() {
71 | @Override
72 | public void onClick(View v) {
73 | if(seekbar.isRangeViewVisible()) {
74 | seekbar.addMarkRange(0);
75 | }
76 | }
77 | });
78 |
79 | addpoint.setOnClickListener(new View.OnClickListener() {
80 | @Override
81 | public void onClick(View v) {
82 | if(seekbar.isRangeViewVisible()) {
83 | seekbar.addMarkPoint(0);
84 | }
85 | }
86 | });
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/app/src/main/java/org/zhgeaits/risv/CustomHorizontalScrollView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Zhang Ge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.zhgeaits.risv;
17 |
18 | import android.content.Context;
19 | import android.os.Handler;
20 | import android.os.Message;
21 | import android.util.AttributeSet;
22 | import android.view.MotionEvent;
23 | import android.view.View;
24 | import android.widget.HorizontalScrollView;
25 |
26 | /**
27 | * Created by zhangge on 2015/9/25.
28 | */
29 | public class CustomHorizontalScrollView extends HorizontalScrollView {
30 |
31 | private boolean mRangeMoving = false;
32 | private boolean mFromUser = false;
33 | private long mFirstTouch = 0;
34 | private int mValidPointerId;
35 | private int mBarLength;//可见长度
36 | private int mImageBarLen;//图片的长度
37 | private int mSeekWidth;//整条bar的长度
38 | private int mTouchEventId = 12345;
39 | private OnScrollListener mListener;
40 | private Handler mHandler = new Handler() {
41 |
42 | private int lastX;
43 |
44 | @Override
45 | public void handleMessage(Message msg) {
46 | super.handleMessage(msg);
47 | View scroller = (View) msg.obj;
48 | if (msg.what == mTouchEventId) {
49 | if (lastX == scroller.getScrollX()) {
50 | if (mListener != null && mFromUser == false) {
51 | mListener.onScrollStop();
52 | }
53 | } else {
54 | mHandler.sendMessageDelayed(mHandler.obtainMessage(mTouchEventId, scroller), 5);
55 | lastX = scroller.getScrollX();
56 | }
57 | }
58 | }
59 | };
60 |
61 | public CustomHorizontalScrollView(Context context) {
62 | super(context);
63 | }
64 |
65 | public CustomHorizontalScrollView(Context context, AttributeSet attrs) {
66 | super(context, attrs);
67 | }
68 |
69 | public CustomHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
70 | super(context, attrs, defStyleAttr);
71 | }
72 |
73 | public void setRangeMoving(boolean rangeMoving) {
74 | this.mRangeMoving = rangeMoving;
75 | }
76 |
77 | public void setOnScrollListener(OnScrollListener listener) {
78 | this.mListener = listener;
79 | }
80 |
81 | public void setBarLength(int len) {
82 | this.mBarLength = len;
83 | }
84 |
85 | public void setImageBarLen(int len) {
86 | this.mImageBarLen = len;
87 | }
88 |
89 | public void setSeekWidth(int len) {
90 | this.mSeekWidth = len;
91 | }
92 |
93 | @Override
94 | protected void onScrollChanged(int l, int t, int oldl, int oldt) {
95 | super.onScrollChanged(l, t, oldl, oldt);
96 | if (mListener != null) {
97 | mListener.onScrollChanged(l, t, oldl, oldt, mFromUser);
98 | }
99 | }
100 |
101 | @Override
102 | public boolean onTouchEvent(MotionEvent event) {
103 | switch (event.getAction()) {
104 | case MotionEvent.ACTION_DOWN:
105 | mFromUser = true;
106 | mFirstTouch = System.currentTimeMillis();
107 | mValidPointerId = event.getPointerId(event.getActionIndex());
108 | break;
109 | case MotionEvent.ACTION_MOVE:
110 | mFromUser = true;
111 | break;
112 | case MotionEvent.ACTION_UP:
113 | mFromUser = false;
114 | mHandler.sendMessageDelayed(mHandler.obtainMessage(mTouchEventId, this), 5);
115 |
116 | //如果300毫秒之间就是一个点击事件
117 | if (event.getPointerId(event.getActionIndex()) == mValidPointerId && System.currentTimeMillis() - mFirstTouch <= 300) {
118 | float posX = event.getX();
119 | float blankWidth = (mSeekWidth - mImageBarLen) / 2.0f;
120 | if (posX + getScrollX() <= mSeekWidth - blankWidth && posX + getScrollX() >= blankWidth) {
121 | int distance = (int) (posX - (mBarLength / 2.0d));
122 | if (mListener != null) {
123 | mListener.onScrollChanged(getScrollX() + distance, 0, getScrollX(), 0, true);
124 | }
125 | this.smoothScrollTo(getScrollX() + distance, 0);
126 | }
127 | }
128 | break;
129 | }
130 | return super.onTouchEvent(event);
131 | }
132 |
133 | @Override
134 | public boolean onInterceptTouchEvent(MotionEvent ev) {
135 | if (!mRangeMoving) {
136 | return super.onInterceptTouchEvent(ev);
137 | } else {
138 | return false;
139 | }
140 | }
141 |
142 | public interface OnScrollListener {
143 | void onScrollStop();
144 |
145 | void onScrollChanged(int l, int t, int oldl, int oldt, boolean fromUser);
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/app/src/main/java/org/zhgeaits/risv/DimenConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Zhang Ge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.zhgeaits.risv;
17 |
18 | import android.content.Context;
19 |
20 | public class DimenConverter {
21 |
22 | public static int dip2px(Context context, float dpValue) {
23 | final float scale = context.getResources().getDisplayMetrics().density;
24 | return (int) (dpValue * scale + 0.5f);
25 | }
26 |
27 | public static int px2dip(Context context, float pxValue) {
28 | final float scale = context.getResources().getDisplayMetrics().density;
29 | return (int) (pxValue / scale + 0.5f);
30 | }
31 | public static int px2sp(Context context, float pxValue) {
32 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
33 | return (int) (pxValue / fontScale + 0.5f);
34 | }
35 |
36 | public static int sp2px(Context context, float spValue) {
37 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
38 | return (int) (spValue * fontScale + 0.5f);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/org/zhgeaits/risv/MultiPointBar.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Zhang Ge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.zhgeaits.risv;
17 |
18 | import android.content.Context;
19 | import android.graphics.Canvas;
20 | import android.graphics.Paint;
21 | import android.util.AttributeSet;
22 | import android.view.View;
23 |
24 | import java.util.HashMap;
25 | import java.util.Map;
26 |
27 | /**
28 | * Created by zhangge on 2015/10/12.
29 | */
30 | public class MultiPointBar extends View {
31 |
32 | private Context mContext;
33 | private Paint mPaint;
34 |
35 | private Map mPoints;
36 | private int mBarHeight;
37 | private int mBarWidth;
38 |
39 | public MultiPointBar(Context context) {
40 | super(context);
41 | init(context, null, 0);
42 | }
43 |
44 | public MultiPointBar(Context context, AttributeSet attrs) {
45 | super(context, attrs);
46 | init(context, attrs, 0);
47 | }
48 |
49 | public MultiPointBar(Context context, AttributeSet attrs, int defStyleAttr) {
50 | super(context, attrs, defStyleAttr);
51 | init(context, attrs, defStyleAttr);
52 | }
53 |
54 | @Override
55 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
56 |
57 | if (mBarWidth == 0) {
58 | mBarWidth = MeasureSpec.getSize(widthMeasureSpec);
59 | }
60 |
61 | int width = measureDimension(mBarWidth, widthMeasureSpec);
62 | int height = measureDimension(mBarHeight, heightMeasureSpec);
63 |
64 | setMeasuredDimension(width, height);
65 | }
66 |
67 | @Override
68 | protected void onDraw(Canvas canvas) {
69 | super.onDraw(canvas);
70 |
71 | for (Point point : mPoints.values()) {
72 | mPaint.setColor(point.color);
73 | canvas.drawCircle(point.position + mBarHeight / 2, mBarHeight / 2, mBarHeight / 2, mPaint);
74 | }
75 | }
76 |
77 | protected int measureDimension(int defaultSize, int measureSpec) {
78 |
79 | int result;
80 |
81 | int specMode = MeasureSpec.getMode(measureSpec);
82 | int specSize = MeasureSpec.getSize(measureSpec);
83 |
84 | if (specMode == MeasureSpec.EXACTLY) {
85 | result = specSize;
86 | } else if (specMode == MeasureSpec.AT_MOST) {
87 | result = Math.min(defaultSize, specSize);
88 | } else {
89 | result = defaultSize;
90 | }
91 |
92 | return result;
93 | }
94 |
95 | private void init(Context context, AttributeSet attrs, int defStyleAttr) {
96 | mContext = context;
97 | mPoints = new HashMap<>();
98 | mBarHeight = DimenConverter.dip2px(mContext, 4);
99 | mPaint = new Paint();
100 | mPaint.setAntiAlias(true);
101 | }
102 |
103 | public void addPoint(int id, int position, int color) {
104 | Point range = new Point();
105 | range.position = position;
106 | range.color = color;
107 | mPoints.put(id, range);
108 | invalidate();
109 | }
110 |
111 | public void removePoint(int id) {
112 | mPoints.remove(id);
113 | invalidate();
114 | }
115 |
116 | /**
117 | * 设置bar的长度
118 | * @param barWidth
119 | */
120 | public void setBarWidth(int barWidth) {
121 | this.mBarWidth = barWidth;
122 | }
123 |
124 | public class Point {
125 | int position;
126 | int color;
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/app/src/main/java/org/zhgeaits/risv/MultiRangebar.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Zhang Ge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.zhgeaits.risv;
17 |
18 | import android.content.Context;
19 | import android.graphics.Canvas;
20 | import android.graphics.drawable.Drawable;
21 | import android.util.AttributeSet;
22 | import android.view.View;
23 |
24 | import java.util.HashMap;
25 | import java.util.Map;
26 |
27 | /**
28 | * Created by zhangge on 15/9/27.
29 | *
30 | */
31 | public class MultiRangebar extends View {
32 |
33 | private Context mContext;
34 | private Drawable mSelectedBar;
35 |
36 | private Map mRanges;
37 | private int mBarHeight;
38 | private int mBarWidth;
39 |
40 | public MultiRangebar(Context context) {
41 | super(context);
42 | init(context, null, 0);
43 | }
44 |
45 | public MultiRangebar(Context context, AttributeSet attrs) {
46 | super(context, attrs);
47 | init(context, attrs, 0);
48 | }
49 |
50 | public MultiRangebar(Context context, AttributeSet attrs, int defStyleAttr) {
51 | super(context, attrs, defStyleAttr);
52 | init(context, attrs, defStyleAttr);
53 | }
54 |
55 | @Override
56 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
57 |
58 | if (mBarWidth == 0) {
59 | mBarWidth = MeasureSpec.getSize(widthMeasureSpec);
60 | }
61 |
62 | int width = measureDimension(mBarWidth, widthMeasureSpec);
63 | int height = measureDimension(mBarHeight, heightMeasureSpec);
64 |
65 | setMeasuredDimension(width, height);
66 | }
67 |
68 | @Override
69 | protected void onDraw(Canvas canvas) {
70 | super.onDraw(canvas);
71 |
72 | for (Range range : mRanges.values()) {
73 | mSelectedBar.setBounds(range.left, 0, range.right, mBarHeight);
74 | mSelectedBar.draw(canvas);
75 | }
76 | }
77 |
78 | protected int measureDimension(int defaultSize, int measureSpec) {
79 |
80 | int result;
81 |
82 | int specMode = MeasureSpec.getMode(measureSpec);
83 | int specSize = MeasureSpec.getSize(measureSpec);
84 |
85 | if (specMode == MeasureSpec.EXACTLY) {
86 | result = specSize;
87 | } else if (specMode == MeasureSpec.AT_MOST) {
88 | result = Math.min(defaultSize, specSize);
89 | } else {
90 | result = defaultSize;
91 | }
92 |
93 | return result;
94 | }
95 |
96 | private void init(Context context, AttributeSet attrs, int defStyleAttr) {
97 | mContext = context;
98 | mRanges = new HashMap<>();
99 | mBarHeight = DimenConverter.dip2px(mContext, 2);
100 | mSelectedBar = getResources().getDrawable(R.drawable.multi_range_bg);
101 | }
102 |
103 | public void addRange(int id, int left, int right) {
104 | Range range = new Range();
105 | range.left = left;
106 | range.right = right;
107 | mRanges.put(id, range);
108 | invalidate();
109 | }
110 |
111 | public void removeRange(int id) {
112 | mRanges.remove(id);
113 | invalidate();
114 | }
115 |
116 | public void setBarWidth(int barWidth) {
117 | this.mBarWidth = barWidth;
118 | }
119 |
120 | public class Range {
121 | int left;
122 | int right;
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/app/src/main/java/org/zhgeaits/risv/RangeImageSelectedView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Zhang Ge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.zhgeaits.risv;
17 |
18 | import android.content.Context;
19 | import android.graphics.Canvas;
20 | import android.graphics.Color;
21 | import android.graphics.Paint;
22 | import android.graphics.RectF;
23 | import android.graphics.drawable.Drawable;
24 | import android.util.AttributeSet;
25 | import android.view.MotionEvent;
26 | import android.view.View;
27 |
28 | /**
29 | * Created by zhangge on 2015/9/24.
30 | */
31 | public class RangeImageSelectedView extends View {
32 |
33 | public static final int HINT_NONE = 1;//无效点击状态
34 | public static final int HINT_DIRECTION_LEFT = 2;//点击左边拖动
35 | public static final int HINT_DIRECTION_RIGHT = 3;//点击右边拖动状态
36 | public static final int CHANGE_TYPE_SCALE = 1;//区间修改的类型,修改区间的大小
37 | public static final int CHANGE_TYPE_MOVE = 2;//区间修改的类型,移动区间
38 |
39 | private Drawable mLeftSelectBgDrawable;
40 | private Drawable mLeftSelectArrowDrawable;
41 | private Drawable mRightSelectBgDrawable;
42 | private Drawable mRightSelectArrowDrawable;
43 | private Drawable mPointArrowDrawable;
44 |
45 | private Context mContext;
46 | private CustomHorizontalScrollView mHorizontalScrollView;
47 | private Paint mPaint;
48 | private Paint mOutsidePaint;
49 |
50 | private int id;
51 | private int mSeekWidth;//整条bar的宽度,包括前后空白
52 | private int mSelectWidth;//点击按钮的宽度
53 | private int mSelectHeight;//点击按钮的高度,就是整条bar的高度了
54 | private int mArrowWidth;//箭头的宽度
55 | private int mArrowHeight;//箭头的高度
56 | private int mPointArrowWidth;//3个点的宽度
57 | private int mPointArrowHeight;//3个点的高度
58 | private int mStartLeft;//画左边按钮的的起始位置
59 | private int mWindowLen;//窗口的宽度
60 | private int mBorder;//窗口的边框宽度
61 | private int mHitState;//点击的状态
62 | private int mValidPointerId;//有效的多点触控点Id
63 | private int mLeftBlankWidth;//左边空白的宽度
64 | private int mRightBlankWidth;//右边空白的宽度
65 | private int mImageListLen;//图片的长度,就是bar的宽度,不包括前后空白
66 | private int mSeekbarVisibleWidth;//bar的可见宽度
67 | private int mMinWindowLen = 0;//窗口的最小宽度,默认是0
68 | private int mMaxWindowLen = 0;//窗口的最大宽度,弹幕初始值最大的宽度
69 | private float mLastX;//上次点击的X坐标
70 | private float mLastY;//上次点击的Y坐标
71 | private boolean mCanChange = true;//是否可以修改
72 | private int mChangeType = 1;//区间修改的类型
73 | private boolean mLeftChange = false;//弹幕框移动到最右边以后开始变小
74 |
75 | private OnRangeChangedListener mRangeChangedListener;
76 |
77 | public RangeImageSelectedView(Context context) {
78 | super(context);
79 | init(context, null, 0);
80 | }
81 |
82 | public RangeImageSelectedView(Context context, AttributeSet attrs) {
83 | super(context, attrs);
84 | init(context, attrs, 0);
85 | }
86 |
87 | public RangeImageSelectedView(Context context, AttributeSet attrs, int defStyleAttr) {
88 | super(context, attrs, defStyleAttr);
89 | init(context, attrs, defStyleAttr);
90 | }
91 |
92 | private void init(Context context, AttributeSet attrs, int defStyleAttr) {
93 | mContext = context;
94 | mSelectWidth = DimenConverter.dip2px(context, 16);
95 | mSelectHeight = DimenConverter.dip2px(context, 44);
96 | mArrowWidth = DimenConverter.dip2px(context, 7);
97 | mArrowHeight = DimenConverter.dip2px(context, 15);
98 | mPointArrowWidth = DimenConverter.dip2px(context, 4);
99 | mPointArrowHeight = DimenConverter.dip2px(context, 19);
100 | mBorder = DimenConverter.dip2px(context, 4);
101 | mStartLeft = 0;
102 | mWindowLen = 10;
103 |
104 | mPaint = new Paint();
105 | mPaint.setColor(Color.parseColor("#ff8900"));
106 | mPaint.setAntiAlias(true);
107 |
108 | mOutsidePaint = new Paint();
109 | mOutsidePaint.setColor(Color.parseColor("#8A000000"));
110 | mOutsidePaint.setAntiAlias(true);
111 |
112 | mLeftSelectBgDrawable = getContext().getResources().getDrawable(R.drawable.img_bar_left);
113 | mLeftSelectArrowDrawable = getResources().getDrawable(R.drawable.left_arrow_selector);
114 |
115 | mRightSelectBgDrawable = getResources().getDrawable(R.drawable.img_bar_right);
116 | mRightSelectArrowDrawable = getResources().getDrawable(R.drawable.right_arrow_selector);
117 |
118 | mPointArrowDrawable = getResources().getDrawable(R.mipmap.point_arrow);
119 | }
120 |
121 | public void setOnRangeChangedListener(OnRangeChangedListener listener) {
122 | this.mRangeChangedListener = listener;
123 | }
124 |
125 | public int getId() {
126 | return id;
127 | }
128 |
129 | public void setId(int id) {
130 | this.id = id;
131 | }
132 |
133 | /**
134 | * 设置最小的窗口宽度
135 | * @param minWindowLen
136 | */
137 | public void setMinWindowLen(int minWindowLen) {
138 | this.mMinWindowLen = minWindowLen;
139 | }
140 |
141 | /**
142 | * 设置最大的窗口宽度
143 | * @param maxWindowlen
144 | */
145 | public void setMaxWindowLen(int maxWindowlen) {
146 | this.mMaxWindowLen = maxWindowlen;
147 | }
148 |
149 | /**
150 | * 获取当前的最大窗口值
151 | * @return
152 | */
153 | public int getMaxWindowLen() {
154 | return this.mMaxWindowLen;
155 | }
156 |
157 | /**
158 | * 设置左边绘制的起点位置
159 | * @param startLeft
160 | */
161 | public void setStartLeft(int startLeft) {
162 | this.mStartLeft = startLeft;
163 | }
164 |
165 | /**
166 | * 设置左边选择的按钮样式
167 | * @param leftChange
168 | */
169 | public void setLeftChange(boolean leftChange) {
170 | mLeftChange = leftChange;
171 | invalidate();
172 | }
173 |
174 | /**
175 | * 设置窗口的起始位置
176 | * @param windowStart
177 | */
178 | public void setWindowStart(int windowStart) {
179 | this.mStartLeft = windowStart - mSelectWidth;
180 | }
181 |
182 | /**
183 | * 设置选择窗口的长度
184 | * @param windowLen
185 | */
186 | public void setWindowLen(int windowLen) {
187 | this.mWindowLen = windowLen;
188 | }
189 |
190 | /**
191 | * 获取窗口起始位置
192 | * @return
193 | */
194 | public int getWindowStart() {
195 | return mStartLeft + mSelectWidth;
196 | }
197 |
198 | /**
199 | * 获取窗口长度
200 | * @return
201 | */
202 | public int getWindowLen() {
203 | return mWindowLen;
204 | }
205 |
206 | /**
207 | * 设置左边的空白长度
208 | * @param blankWidth
209 | */
210 | public void setLeftBlankWidth(int blankWidth) {
211 | this.mLeftBlankWidth = blankWidth;
212 | }
213 |
214 | /**
215 | * 设置右边的空白宽度
216 | * @param blankWidth
217 | */
218 | public void setRightBlankWidth(int blankWidth) {
219 | this.mRightBlankWidth = blankWidth;
220 | }
221 |
222 | /**
223 | * 设置可用bar的长度
224 | * @param imageLen
225 | */
226 | public void setImageListLen(int imageLen) {
227 | this.mImageListLen = imageLen;
228 | }
229 |
230 | public void setHorizontalScrollView(CustomHorizontalScrollView scrollView) {
231 | this.mHorizontalScrollView = scrollView;
232 | }
233 |
234 | /**
235 | * 设置整个bar的宽度
236 | * @param width
237 | */
238 | public void setSeekWidth(int width) {
239 | this.mSeekWidth = width;
240 | }
241 |
242 | /**
243 | * 设置bar的可见宽度
244 | * @param width
245 | */
246 | public void setSeekbarVisiblewidth(int width) {
247 | this.mSeekbarVisibleWidth = width;
248 | }
249 |
250 | /**
251 | * 画外面的蒙层
252 | *
253 | * @param canvas
254 | */
255 | private void drawOutsideLayer(Canvas canvas) {
256 | int radius = DimenConverter.dip2px(mContext, 3);
257 | RectF rectfl = new RectF(0, 0, mStartLeft + mSelectWidth / 2, mSelectHeight);
258 | RectF rectfr = new RectF(mStartLeft + mWindowLen + mSelectWidth + mSelectWidth / 2, 0, canvas.getWidth(), mSelectHeight);
259 | canvas.drawRoundRect(rectfl, radius, radius, mOutsidePaint);
260 | canvas.drawRoundRect(rectfr, radius, radius, mOutsidePaint);
261 | }
262 |
263 | /**
264 | * 画左边的3个点选择框
265 | * @param canvas
266 | */
267 | private void drawLeftPointSelect(Canvas canvas) {
268 | mLeftSelectBgDrawable.setBounds(mStartLeft, 0, mStartLeft + mSelectWidth, mSelectHeight);
269 | mLeftSelectBgDrawable.draw(canvas);
270 | mPointArrowDrawable.setBounds((mSelectWidth - mPointArrowWidth) / 2 + mStartLeft, (mSelectHeight - mPointArrowHeight) / 2,
271 | (mSelectWidth - mPointArrowWidth) / 2 + mPointArrowWidth + mStartLeft, (mSelectHeight - mPointArrowHeight) / 2 + mPointArrowHeight);
272 | mPointArrowDrawable.draw(canvas);
273 | }
274 |
275 | /**
276 | * 画右边的3个点选择框
277 | * @param canvas
278 | */
279 | private void drawRightPointSelect(Canvas canvas) {
280 | mRightSelectBgDrawable.setBounds(mStartLeft + mSelectWidth + mWindowLen, 0, mStartLeft + mSelectWidth + mWindowLen + mSelectWidth, mSelectHeight);
281 | mRightSelectBgDrawable.draw(canvas);
282 | mPointArrowDrawable.setBounds((mSelectWidth - mPointArrowWidth) / 2 + mStartLeft + mSelectWidth + mWindowLen, (mSelectHeight - mPointArrowHeight) / 2,
283 | (mSelectWidth - mPointArrowWidth) / 2 + mStartLeft + mSelectWidth + mWindowLen + mPointArrowWidth, (mSelectHeight - mPointArrowHeight) / 2 + mPointArrowHeight);
284 | mPointArrowDrawable.draw(canvas);
285 | }
286 |
287 | /**
288 | * 画左边拖动按钮
289 | *
290 | * @param canvas
291 | */
292 | private void drawLeftSelect(Canvas canvas) {
293 | mLeftSelectBgDrawable.setBounds(mStartLeft, 0, mStartLeft + mSelectWidth, mSelectHeight);
294 | mLeftSelectBgDrawable.draw(canvas);
295 | mLeftSelectArrowDrawable.setBounds((mSelectWidth - mArrowWidth) / 2 + mStartLeft, (mSelectHeight - mArrowHeight) / 2,
296 | (mSelectWidth - mArrowWidth) / 2 + mArrowWidth + mStartLeft, (mSelectHeight - mArrowHeight) / 2 + mArrowHeight);
297 | mLeftSelectArrowDrawable.draw(canvas);
298 | }
299 |
300 | /**
301 | * 画中间的两条边框
302 | *
303 | * @param canvas
304 | */
305 | private void drawCenterRect(Canvas canvas) {
306 | canvas.drawRect(mStartLeft + mSelectWidth / 2, 0, mStartLeft + mSelectWidth + mWindowLen + mSelectWidth / 2, mBorder, mPaint);
307 | canvas.drawRect(mStartLeft + mSelectWidth / 2, mSelectHeight - mBorder, mStartLeft + mSelectWidth + mWindowLen + mSelectWidth / 2, mSelectHeight, mPaint);
308 | }
309 |
310 | /**
311 | * 画右边的拖动按钮
312 | *
313 | * @param canvas
314 | */
315 | private void drawRightSelect(Canvas canvas) {
316 | mRightSelectBgDrawable.setBounds(mStartLeft + mSelectWidth + mWindowLen, 0, mStartLeft + mSelectWidth + mWindowLen + mSelectWidth, mSelectHeight);
317 | mRightSelectBgDrawable.draw(canvas);
318 | mRightSelectArrowDrawable.setBounds((mSelectWidth - mArrowWidth) / 2 + mStartLeft + mSelectWidth + mWindowLen, (mSelectHeight - mArrowHeight) / 2,
319 | (mSelectWidth - mArrowWidth) / 2 + mStartLeft + mSelectWidth + mWindowLen + mArrowWidth, (mSelectHeight - mArrowHeight) / 2 + mArrowHeight);
320 | mRightSelectArrowDrawable.draw(canvas);
321 | }
322 |
323 | /**
324 | * 设置区间是否可以修改
325 | * @param canChange
326 | */
327 | public void setCanChange(boolean canChange) {
328 | this.mCanChange = canChange;
329 | }
330 |
331 | /**
332 | * 设置区间的修改类型
333 | * @param type
334 | */
335 | public void setChangeType(int type) {
336 | this.mChangeType = type;
337 | }
338 |
339 | /**
340 | * 获取区间的类型
341 | * @return
342 | */
343 | public int getChangeType() {
344 | return this.mChangeType;
345 | }
346 |
347 | /**
348 | * 判断点击的位置
349 | *
350 | * @param x
351 | * @param y
352 | * @return
353 | */
354 | private int getHit(float x, float y) {
355 |
356 | if (x >= mStartLeft && x <= mStartLeft + mSelectWidth) {
357 | return HINT_DIRECTION_LEFT;
358 | }
359 | if (x >= mStartLeft + mSelectWidth + mWindowLen && x <= mStartLeft + mSelectWidth + mWindowLen + mSelectWidth) {
360 | return HINT_DIRECTION_RIGHT;
361 | }
362 |
363 | return HINT_NONE;
364 | }
365 |
366 | /**
367 | * 移动窗口的大小
368 | * @param hintState
369 | * @param distance
370 | */
371 | private void handleMotion(int hintState, int distance) {
372 |
373 | if (hintState == HINT_DIRECTION_LEFT) {
374 | int startLeft = mStartLeft + distance;
375 | int windowLen = mWindowLen - distance;
376 | if(windowLen >= mMinWindowLen && startLeft + mSelectWidth >= mLeftBlankWidth && startLeft >= mHorizontalScrollView.getScrollX()) {
377 | mWindowLen = windowLen;
378 | mStartLeft = startLeft;
379 | invalidate();
380 | if(mRangeChangedListener != null) {
381 | int leftSelectPostion = mStartLeft + mSelectWidth;
382 | mRangeChangedListener.onRangeChanging(HINT_DIRECTION_LEFT, leftSelectPostion);
383 | }
384 | }
385 | } else if (hintState == HINT_DIRECTION_RIGHT) {
386 | int windowLen = mWindowLen + distance;
387 | int rightStart = mStartLeft + mSelectWidth + windowLen;
388 | //如果窗口宽度大于mMinWindowLen,或者没有超出右边范围就移动
389 | if (windowLen >= mMinWindowLen && rightStart <= mSeekWidth - mRightBlankWidth && (rightStart + mSelectWidth) <= (mHorizontalScrollView.getScrollX() + mSeekbarVisibleWidth)) {
390 | mWindowLen = windowLen;
391 | invalidate();
392 | if(mRangeChangedListener != null) {
393 | mRangeChangedListener.onRangeChanging(HINT_DIRECTION_RIGHT, rightStart);
394 | }
395 | }
396 | }
397 | }
398 |
399 | /**
400 | * 移动区间
401 | * @param hintState
402 | * @param distance
403 | */
404 | private void handleMoveMotion(int hintState, int distance) {
405 | int startLeft = mStartLeft + distance;
406 | int rightStart = startLeft + mSelectWidth + mWindowLen;
407 |
408 | if (hintState == HINT_DIRECTION_LEFT) {
409 |
410 | //如果触控点超出可视范围或者进度条最左端就不让移动了
411 | if(startLeft + mSelectWidth < mLeftBlankWidth || startLeft < mHorizontalScrollView.getScrollX()) {
412 | mLeftChange = false;
413 | invalidate();
414 | return;
415 | }
416 |
417 | //向左拖动
418 | if(distance < 0) {
419 | //如果窗口没缩小的情况,则整体拖动
420 | if(mWindowLen == mMaxWindowLen) {
421 | mLeftChange = false;
422 | mStartLeft = startLeft;
423 | } else {//窗口被缩小的情况,则放大窗口
424 | mLeftChange = true;
425 | int windowLen = mWindowLen - distance;
426 | mWindowLen = windowLen;
427 | if(mWindowLen > mMaxWindowLen) {
428 | mWindowLen = mMaxWindowLen;
429 | }
430 | mStartLeft = startLeft;
431 | }
432 | } else if(distance > 0) {//向右拖动
433 | //如果已经顶到最右端了,并且窗口为0了,则不让拖动了
434 | if(mWindowLen <= 0 && rightStart >= mSeekWidth - mRightBlankWidth) {
435 | return;
436 | }
437 |
438 | //如果已经顶到最右端了则缩小窗口,否则整体移动
439 | //只能右边移动,不能缩小窗口
440 | if(rightStart >= mSeekWidth - mRightBlankWidth) {
441 | return;
442 | /*int windowLen = mWindowLen - distance;
443 | mWindowLen = windowLen;
444 | if(mWindowLen > mMaxWindowLen) {
445 | mWindowLen = mMaxWindowLen;
446 | } else if(mWindowLen < 0) {
447 | mWindowLen = 0;
448 | }
449 | mLeftChange = true;
450 | mStartLeft = startLeft;*/
451 | } else {
452 | mLeftChange = false;
453 | mStartLeft = startLeft;
454 | }
455 | }
456 |
457 | invalidate();
458 |
459 | if(mRangeChangedListener != null) {
460 | int leftSelectPostion = mStartLeft + mSelectWidth;
461 | mRangeChangedListener.onRangeChanging(HINT_DIRECTION_LEFT, leftSelectPostion);
462 | }
463 |
464 | } else if (hintState == HINT_DIRECTION_RIGHT) {
465 |
466 | //现在右边只有完整显示的情况下可以拖动,其他时候无法点击
467 | if(mWindowLen < mMaxWindowLen) {
468 | return;
469 | }
470 |
471 | //如果触控点超出可视范围或者进度条最左端就不让移动了
472 | if(rightStart > mSeekWidth - mRightBlankWidth || (rightStart + mSelectWidth) > (mHorizontalScrollView.getScrollX() + mSeekbarVisibleWidth)) {
473 | return;
474 | }
475 |
476 | //向右拖动
477 | if(distance > 0) {
478 | mLeftChange = false;
479 | //如果窗口没缩小的情况,则整体拖动
480 | if(mWindowLen == mMaxWindowLen) {
481 | mStartLeft = startLeft;
482 | } else {//窗口被缩小的情况,则放大窗口
483 | // mLeftChange = true;
484 | // int windowLen = mWindowLen + distance;
485 | // mWindowLen = windowLen;
486 | // if(mWindowLen > mMaxWindowLen) {
487 | // mWindowLen = mMaxWindowLen;
488 | // }
489 | return;
490 | }
491 | } else if(distance < 0) {//向左拖动
492 | mLeftChange = false;
493 | //如果已经顶到最左端了,并且窗口为0了,则不让拖动了
494 | if(mWindowLen <= 0 && startLeft + mSelectWidth <= mLeftBlankWidth) {
495 | return;
496 | }
497 |
498 | //如果已经顶到最左端了则缩小窗口,否则整体移动
499 | //如果顶到最左端以后不允许缩小了,无法拖动。
500 | if(startLeft + mSelectWidth <= mLeftBlankWidth) {
501 | /*int windowLen = mWindowLen + distance;
502 | mWindowLen = windowLen;
503 | if(mWindowLen > mMaxWindowLen) {
504 | mWindowLen = mMaxWindowLen;
505 | } else if(mWindowLen < 0) {
506 | mWindowLen = 0;
507 | }*/
508 | return;
509 | } else {
510 | mStartLeft = startLeft;
511 | }
512 | }
513 |
514 | invalidate();
515 |
516 | if(mRangeChangedListener != null) {
517 | mRangeChangedListener.onRangeChanging(HINT_DIRECTION_RIGHT, rightStart);
518 | }
519 | }
520 |
521 | }
522 |
523 | protected int measureDimension(int defaultSize, int measureSpec) {
524 |
525 | int result;
526 |
527 | int specMode = MeasureSpec.getMode(measureSpec);
528 | int specSize = MeasureSpec.getSize(measureSpec);
529 |
530 | if (specMode == MeasureSpec.EXACTLY) {
531 | result = specSize;
532 | } else if (specMode == MeasureSpec.AT_MOST) {
533 | result = Math.min(defaultSize, specSize);
534 | } else {
535 | result = defaultSize;
536 | }
537 |
538 | return result;
539 | }
540 |
541 | @Override
542 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
543 |
544 | if (mSeekWidth == 0) {
545 | mSeekWidth = MeasureSpec.getSize(widthMeasureSpec);
546 | }
547 |
548 | int width = measureDimension(mSeekWidth, widthMeasureSpec);
549 | int height = measureDimension(mSelectHeight, heightMeasureSpec);
550 |
551 | setMeasuredDimension(width, height);
552 | }
553 |
554 | @Override
555 | protected void onDraw(Canvas canvas) {
556 | super.onDraw(canvas);
557 |
558 | drawOutsideLayer(canvas);
559 | if(mChangeType == CHANGE_TYPE_SCALE || (mChangeType == CHANGE_TYPE_MOVE && mLeftChange)) {
560 | drawLeftSelect(canvas);
561 | } else {
562 | drawLeftPointSelect(canvas);
563 | }
564 | drawCenterRect(canvas);
565 | if(mChangeType == CHANGE_TYPE_SCALE) {
566 | drawRightSelect(canvas);
567 | } else if(mChangeType == CHANGE_TYPE_MOVE) {
568 | drawRightPointSelect(canvas);
569 | }
570 |
571 | }
572 |
573 | @Override
574 | public boolean onTouchEvent(MotionEvent event) {
575 | if (mHorizontalScrollView != null) {
576 | mHorizontalScrollView.setRangeMoving(false);
577 | }
578 | if(!mCanChange) {
579 | return true;
580 | }
581 | switch (event.getAction()) {
582 | case MotionEvent.ACTION_DOWN:
583 | mHitState = getHit(event.getX(), event.getY());
584 | if (mHitState != HINT_NONE) {
585 | mLastX = event.getX();
586 | mLastY = event.getY();
587 | mValidPointerId = event.getPointerId(event.getActionIndex());
588 | if (mHorizontalScrollView != null) {
589 | mHorizontalScrollView.setRangeMoving(true);
590 | }
591 | }
592 | break;
593 | case MotionEvent.ACTION_UP:
594 | mHitState = HINT_NONE;
595 | if (mHorizontalScrollView != null) {
596 | mHorizontalScrollView.setRangeMoving(false);
597 | }
598 | if(mRangeChangedListener != null) {
599 | mRangeChangedListener.onRangeChangeFinished();
600 | }
601 | break;
602 | case MotionEvent.ACTION_MOVE:
603 | if (event.getPointerId(event.getActionIndex()) == mValidPointerId && mHitState != HINT_NONE) {
604 | if(mChangeType == CHANGE_TYPE_SCALE) {
605 | handleMotion(mHitState, (int) (event.getX() - mLastX));
606 | } else if(mChangeType == CHANGE_TYPE_MOVE) {
607 | handleMoveMotion(mHitState, (int) (event.getX() - mLastX));
608 | }
609 | mLastX = event.getX();
610 | mLastY = event.getY();
611 | if (mHorizontalScrollView != null) {
612 | mHorizontalScrollView.setRangeMoving(true);
613 | }
614 | }
615 | break;
616 | }
617 |
618 | return true;
619 | }
620 |
621 | public interface OnRangeChangedListener {
622 | void onRangeChanging(int direction, int postion);
623 | void onRangeChangeFinished();
624 | }
625 | }
626 |
--------------------------------------------------------------------------------
/app/src/main/java/org/zhgeaits/risv/VideoImageSeekbar.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Zhang Ge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.zhgeaits.risv;
17 |
18 | import android.content.Context;
19 | import android.graphics.Color;
20 | import android.graphics.drawable.BitmapDrawable;
21 | import android.graphics.drawable.Drawable;
22 | import android.util.AttributeSet;
23 | import android.view.Gravity;
24 | import android.view.LayoutInflater;
25 | import android.view.View;
26 | import android.view.ViewGroup;
27 | import android.widget.ImageView;
28 | import android.widget.LinearLayout;
29 | import android.widget.RelativeLayout;
30 |
31 | import java.util.ArrayList;
32 | import java.util.HashMap;
33 | import java.util.List;
34 | import java.util.Map;
35 |
36 | /**
37 | * Created by zhangge on 2015/9/24.
38 | * 区间范围选择控件
39 | */
40 | public class VideoImageSeekbar extends RelativeLayout {
41 |
42 | private Context mContext;
43 | private View mRoot;
44 | private LayoutInflater mInflater;
45 | private LinearLayout mList;
46 | private RangeImageSelectedView mRangeView;
47 | private CustomHorizontalScrollView mHorizontalScrollView;
48 | private RelativeLayout mSeekbarContainer;
49 | private ImageView mSelectbar; //进度条
50 | private RelativeLayout.LayoutParams mSelectbarParams; //选择进度条的布局参数
51 | private MultiRangebar mRangebar;
52 | private MultiPointBar mPointbar;
53 |
54 | private Map mCacheRangeView;
55 |
56 | private int mImageBarLen; //图片的长度,进度条真正意义的像素长度
57 | private int mLeftBlankWidth; //左边空白处的宽度
58 | private int mRightBlankWidth; //右边空白出的宽度
59 | private int mSelectbarWidth; //中间竖条的宽度
60 | private int mCurrentProgress; //光标所在的位置,像素
61 | private int mMaxProgress = 100; //进度条的长度,不包含前后的空白,默认是100
62 | private int mMinSelectProgress = 0; //最少的窗口选择宽度,默认是0
63 | private int mImageHeight; //图片的宽度
64 | private int mImageWidth; //图片的高度
65 | private double mLastImageWidthPercent = 1.0d; //最后一张图片的宽度的百分比
66 |
67 | private OnSeekbarChangedListener mProgressChangeListener;//滚动的监听器
68 |
69 | public VideoImageSeekbar(Context context) {
70 | super(context);
71 | }
72 |
73 | public VideoImageSeekbar(Context context, AttributeSet attrs) {
74 | super(context, attrs);
75 | init(context, attrs, 0);
76 | }
77 |
78 | public VideoImageSeekbar(Context context, AttributeSet attrs, int defStyleAttr) {
79 | super(context, attrs, defStyleAttr);
80 | init(context, attrs, defStyleAttr);
81 | }
82 |
83 | private void init(Context context, AttributeSet attrs, int defStyle) {
84 | mContext = context;
85 | mInflater = LayoutInflater.from(context);
86 | mRoot = mInflater.inflate(R.layout.layout_image_seekbar, this, true);
87 | mCacheRangeView = new HashMap<>();
88 |
89 | mList = (LinearLayout) mRoot.findViewById(R.id.video_image_seekbar_list);
90 | mSelectbar = (ImageView) mRoot.findViewById(R.id.video_image_seekbar_selectbar);
91 | mHorizontalScrollView = (CustomHorizontalScrollView) mRoot.findViewById(R.id.video_image_horizontal_scrollview);
92 | mSeekbarContainer = (RelativeLayout) mRoot.findViewById(R.id.video_image_seekbar_container);
93 |
94 | mSelectbarParams = (LayoutParams) mSelectbar.getLayoutParams();
95 |
96 | mHorizontalScrollView.setOnScrollListener(new CustomHorizontalScrollView.OnScrollListener() {
97 |
98 | @Override
99 | public void onScrollStop() {
100 | mCurrentProgress = mHorizontalScrollView.getScrollX() + mSelectbar.getLeft();
101 | if (mProgressChangeListener != null) {
102 | int progress = (mCurrentProgress - mLeftBlankWidth) * mMaxProgress / mImageBarLen;
103 | mProgressChangeListener.onProgressChanged(progress, true);
104 | }
105 | }
106 |
107 | @Override
108 | public synchronized void onScrollChanged(int l, int t, int oldl, int oldt, boolean fromUser) {
109 | mCurrentProgress = l + mSelectbar.getLeft();
110 | if (mProgressChangeListener != null) {
111 | int progress = (mCurrentProgress - mLeftBlankWidth) * mMaxProgress / mImageBarLen;
112 | mProgressChangeListener.onProgressChanged(progress, fromUser);
113 | }
114 | }
115 | });
116 | }
117 |
118 | /**
119 | * 设置最大的进度值,一般设置为100
120 | *
121 | * @param maxProgress
122 | */
123 | public void setMaxProgress(int maxProgress) {
124 | this.mMaxProgress = maxProgress;
125 | }
126 |
127 | /**
128 | * 获取当前的进度值,参考值是MaxProgress, 即返回值是0-100之间
129 | *
130 | * @return
131 | */
132 | public double getCurrentProgress() {
133 | double progress = (double) (mCurrentProgress - mLeftBlankWidth) * mMaxProgress / (double) mImageBarLen;
134 | return progress;
135 | }
136 |
137 | /**
138 | * 设置当前进度
139 | *
140 | * @param progress 0 - 100之间的百分比
141 | */
142 | public synchronized void setProgress(double progress) {
143 |
144 | //计算光标所在的像素位置
145 | int newProgress = (int) (progress * mImageBarLen / mMaxProgress + mLeftBlankWidth);
146 |
147 | if (newProgress == mCurrentProgress) {
148 | return;
149 | }
150 |
151 | //滚动到当前进度位置
152 | mHorizontalScrollView.smoothScrollTo(mHorizontalScrollView.getScrollX() + (newProgress - mCurrentProgress), 0);
153 | }
154 |
155 | /**
156 | * 设置最小的选择区间
157 | *
158 | * @param minWindowLen
159 | */
160 | public void setMinWindowLen(int minWindowLen) {
161 | this.mMinSelectProgress = minWindowLen;
162 | }
163 |
164 | /**
165 | * 获取当前窗口最大值的百分比,0-100之间
166 | * @return
167 | */
168 | public double getCurrentMaxWindowProgress() {
169 | if (mRangeView != null) {
170 | return mRangeView.getMaxWindowLen() * mMaxProgress / mImageBarLen;
171 | }
172 | return 0;
173 | }
174 |
175 | /**
176 | * 获取当前的最大窗口值
177 | *
178 | * @return
179 | */
180 | public int getCurrentMaxWindowLen() {
181 | if (mRangeView != null) {
182 | return mRangeView.getMaxWindowLen();
183 | }
184 | return 0;
185 | }
186 |
187 | /**
188 | * 设置当前选择框的最大值
189 | *
190 | * @param selectProgress 传值是0-100之间的百分比
191 | * @return
192 | */
193 | public void setCurrentMaxWindowLen(int selectProgress) {
194 | int windowLen = selectProgress * mImageBarLen / mMaxProgress;
195 | if (mRangeView != null) {
196 | mRangeView.setMaxWindowLen(windowLen);
197 | }
198 | }
199 |
200 | /**
201 | * 获取当前的rang id
202 | *
203 | * @return
204 | */
205 | public int getCurrentRangeId() {
206 | if (mRangeView != null) {
207 | return mRangeView.getId();
208 | }
209 | return -1;
210 | }
211 |
212 | /**
213 | * 判断当前是否有选择框显示,参看invisibleRangeView方法,mRangeView为null的时候没有显示
214 | * 其他情况添加或者visible以后都不为空
215 | *
216 | * @return
217 | */
218 | public boolean isRangeViewVisible() {
219 | if (mRangeView != null) {
220 | return true;
221 | }
222 | return false;
223 | }
224 |
225 | /**
226 | * 获取当前选择框的类型
227 | *
228 | * @return
229 | */
230 | public int getCurrentRangeType() {
231 | if (mRangeView != null) {
232 | return mRangeView.getChangeType();
233 | }
234 | return -1;
235 | }
236 |
237 | /**
238 | * 修改当前的rangview宽度
239 | *
240 | * @param selectProgress
241 | */
242 | public void setCurrentRangeViewLen(int selectProgress) {
243 | if (mRangeView == null) {
244 | return;
245 | }
246 |
247 | int windowLen = selectProgress * mImageBarLen / mMaxProgress;
248 | mRangeView.setWindowLen(windowLen);
249 | mRangeView.requestLayout();
250 | }
251 |
252 | /**
253 | * 修改当前rangeview的起始进度
254 | *
255 | * @param startProgress
256 | */
257 | public void setCurrentRangeViewStart(double startProgress) {
258 | if (mRangeView == null) {
259 | return;
260 | }
261 |
262 | int windowStart = (int) (startProgress * mImageBarLen / mMaxProgress + mLeftBlankWidth);
263 | mRangeView.setWindowStart(windowStart);
264 | mRangeView.requestLayout();
265 | }
266 |
267 | /**
268 | * 获取当前rangeView的起始进度
269 | * @return 参考值是MaxProgress, 即返回值是0-100之间
270 | */
271 | public double getCurrentRangeViewStart() {
272 | if (mRangeView == null) {
273 | return -1;
274 | }
275 |
276 | int windowStart = mRangeView.getWindowStart();
277 | double startProgress = (windowStart - mLeftBlankWidth) * mMaxProgress / mImageBarLen;
278 | return startProgress;
279 | }
280 |
281 | /**
282 | * 删除选择窗口
283 | *
284 | * @param id
285 | */
286 | public void removeRangeView(int id) {
287 | mSeekbarContainer.removeView(mRangeView);
288 | mCacheRangeView.remove(id);
289 | mRangeView = null;
290 | if (mRangebar != null) {
291 | mRangebar.removeRange(id);
292 | }
293 | if (mPointbar != null) {
294 | mPointbar.removePoint(id);
295 | }
296 | }
297 |
298 | /**
299 | * 隐藏选择窗口,并显示选择进度条
300 | *
301 | * @param id
302 | */
303 | public void invisibleRangeView(int id) {
304 | if (RangeImageSelectedView.CHANGE_TYPE_MOVE == getCurrentRangeType()) {
305 | addMarkPoint(id);
306 | } else {
307 | addMarkRange(id);
308 | }
309 | }
310 |
311 | /**
312 | * 显示选择窗口
313 | *
314 | * @param id
315 | */
316 | public void visibleRangeView(int id) {
317 | if (mRangeView != null && mRangeView.getId() == id) {
318 | return;
319 | }
320 |
321 | if (mRangeView != null) {
322 | invisibleRangeView(mRangeView.getId());
323 | }
324 |
325 | RangeImageSelectedView rangeView = mCacheRangeView.get(id);
326 | if (rangeView != null) {
327 | mRangeView = rangeView;
328 |
329 | mSeekbarContainer.addView(mRangeView);
330 | mRangebar.removeRange(id);
331 | mPointbar.removePoint(id);
332 |
333 | //广播进度条
334 | if (mProgressChangeListener != null) {
335 | //通知进度条的范围
336 | double startProgress = (double) (mRangeView.getWindowStart() - mLeftBlankWidth) / (double) mImageBarLen;
337 | double selectProgress = (double) mRangeView.getWindowLen() / (double) mImageBarLen;
338 | mProgressChangeListener.onRangeChanged(mRangeView.getId(), startProgress, selectProgress);
339 | }
340 | }
341 | }
342 |
343 | /**
344 | * 添加标记的选择范围
345 | *
346 | * @param id
347 | */
348 | public void addMarkRange(int id) {
349 | mSeekbarContainer.removeView(mRangeView);
350 |
351 | if (mRangebar == null) {
352 | mRangebar = new MultiRangebar(mContext);
353 | mRangebar.setBarWidth(mList.getWidth());
354 | RelativeLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
355 | params.addRule(RelativeLayout.BELOW, R.id.video_image_seekbar_list);
356 | params.topMargin = DimenConverter.dip2px(mContext, 1);
357 | mRangebar.setLayoutParams(params);
358 | mSeekbarContainer.addView(mRangebar);
359 | }
360 | mRangebar.addRange(id, mRangeView.getWindowStart(), mRangeView.getWindowStart() + mRangeView.getWindowLen());
361 |
362 | mRangeView = null;
363 | }
364 |
365 | /**
366 | * 显示标记的点
367 | *
368 | * @param id
369 | */
370 | public void addMarkPoint(int id) {
371 | mSeekbarContainer.removeView(mRangeView);
372 |
373 | int color = Color.parseColor("#FF8900");
374 | if (mPointbar == null) {
375 | mPointbar = new MultiPointBar(mContext);
376 | mPointbar.setBarWidth(mList.getWidth());
377 | RelativeLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
378 | params.addRule(RelativeLayout.ABOVE, R.id.video_image_seekbar_list);
379 | mPointbar.setLayoutParams(params);
380 | mSeekbarContainer.addView(mPointbar);
381 | }
382 | mPointbar.addPoint(id, mRangeView.getWindowStart(), color);
383 |
384 | mRangeView = null;
385 | }
386 |
387 |
388 | /**
389 | * 添加标签的选择框
390 | *
391 | * @param id
392 | * @param startProgress
393 | * @param selectProgress
394 | */
395 | public void addScaledRangeView(int id, double startProgress, int selectProgress) {
396 | addRangeView(id, startProgress, selectProgress, RangeImageSelectedView.CHANGE_TYPE_SCALE, 0);
397 | }
398 |
399 | /**
400 | * 添加弹幕的选择框
401 | *
402 | * @param id
403 | * @param startProgress
404 | * @param selectProgress
405 | */
406 | public void addFixedRangeView(int id, double startProgress, int selectProgress, int maxWindowProgress) {
407 | addRangeView(id, startProgress, selectProgress, RangeImageSelectedView.CHANGE_TYPE_MOVE, maxWindowProgress);
408 | }
409 |
410 | /**
411 | * 添加一个区间选择器,添加的时候往外广播一下区间的范围
412 | *
413 | * @param startProgress 这两个进度都是0-100之间的值
414 | * @param selectProgress
415 | */
416 | public void addRangeView(int id, double startProgress, int selectProgress, int changeType, int maxWindowSelect) {
417 | if (mRangeView != null && mRangeView.getId() == id) {
418 | return;
419 | }
420 |
421 | if (selectProgress < 0) {
422 | return;
423 | }
424 |
425 | if (mRangeView != null) {
426 | invisibleRangeView(mRangeView.getId());
427 | }
428 |
429 | mRangeView = new RangeImageSelectedView(mContext);
430 | mRangeView.setId(id);
431 | mRangeView.setChangeType(changeType);
432 |
433 | mRangeView.setHorizontalScrollView(mHorizontalScrollView);
434 | mRangeView.setSeekWidth(mList.getWidth());
435 | mRangeView.setSeekbarVisiblewidth(getWidth());
436 | mRangeView.setLeftBlankWidth(mLeftBlankWidth);
437 | mRangeView.setRightBlankWidth(mRightBlankWidth);
438 | mRangeView.setImageListLen(mImageBarLen);
439 |
440 | int windowStart = (int) (startProgress * mImageBarLen / (double) mMaxProgress + mLeftBlankWidth);
441 | int windowLen = selectProgress * mImageBarLen / mMaxProgress;
442 | int minWindowLen = mMinSelectProgress * mImageBarLen / mMaxProgress;
443 | int maxWindowLen = maxWindowSelect * mImageBarLen / mMaxProgress;
444 | mRangeView.setWindowStart(windowStart);
445 | mRangeView.setWindowLen(windowLen);
446 | //最小宽度,默认是0
447 | mRangeView.setMinWindowLen(minWindowLen);
448 |
449 | //todo
450 | //如果是固定的选择框才会有最大值
451 | if (changeType == RangeImageSelectedView.CHANGE_TYPE_MOVE) {
452 | if (maxWindowLen > 0) {
453 | mRangeView.setMaxWindowLen(maxWindowLen);
454 | if(maxWindowSelect > selectProgress) {
455 | mRangeView.setLeftChange(true);
456 | }
457 | } else {
458 | mRangeView.setMaxWindowLen(windowLen);
459 | }
460 | }
461 |
462 | mCacheRangeView.put(id, mRangeView);
463 |
464 | mSeekbarContainer.addView(mRangeView);
465 | mRangeView.setOnRangeChangedListener(new RangeImageSelectedView.OnRangeChangedListener() {
466 | @Override
467 | public void onRangeChanging(int direction, int postion) {
468 |
469 | //移动进度条的光标
470 | mCurrentProgress = postion;
471 | mSelectbarParams = new RelativeLayout.LayoutParams(mSelectbarWidth, ViewGroup.LayoutParams.MATCH_PARENT);
472 | mSelectbarParams.leftMargin = postion - mHorizontalScrollView.getScrollX();
473 | mSelectbar.setLayoutParams(mSelectbarParams);
474 | mSelectbar.requestLayout();
475 |
476 | //广播进度条
477 | if (mProgressChangeListener != null) {
478 | double progress = (double) (mCurrentProgress - mLeftBlankWidth) * mMaxProgress / (double) mImageBarLen;
479 | double startProgress = (double) (mRangeView.getWindowStart() - mLeftBlankWidth) / (double) mImageBarLen;
480 | double selectProgress = (double) mRangeView.getWindowLen() / (double) mImageBarLen;
481 |
482 | //通知进度条的范围
483 | mProgressChangeListener.onRangeChanged(mRangeView.getId(), startProgress, selectProgress);
484 |
485 | //通知光标百分比
486 | mProgressChangeListener.onProgressChanged(progress, true);
487 | }
488 | }
489 |
490 | @Override
491 | public void onRangeChangeFinished() {
492 |
493 | //光标回到中间
494 | mSelectbarParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
495 | mSelectbar.setLayoutParams(mSelectbarParams);
496 | mSelectbar.requestLayout();
497 | mHorizontalScrollView.smoothScrollTo(mCurrentProgress - getWidth() / 2, 0);
498 | }
499 |
500 | });
501 |
502 | //广播进度条
503 | if (mProgressChangeListener != null) {
504 | //通知进度条的范围
505 | mProgressChangeListener.onRangeChanged(mRangeView.getId(), startProgress / 100.0d, selectProgress / 100.0d);
506 | }
507 | }
508 |
509 |
510 | /**
511 | * 设置最后一张图片宽度的百分比
512 | *
513 | * @param percent
514 | */
515 | public void setLastImageWidthPercent(double percent) {
516 | mLastImageWidthPercent = percent;
517 | }
518 |
519 | private void setImageList0(List lists) {
520 | mList.removeAllViews();
521 |
522 | mImageHeight = DimenConverter.dip2px(mContext, 36);
523 | mImageWidth = DimenConverter.dip2px(mContext, 27);
524 | mSelectbarWidth = DimenConverter.dip2px(mContext, 4);
525 | mLeftBlankWidth = mSelectbar.getLeft();
526 | mRightBlankWidth = mLeftBlankWidth + mSelectbarWidth;
527 | mCurrentProgress = mLeftBlankWidth;
528 |
529 | View leftBlank = new View(mContext);
530 | ViewGroup.LayoutParams leftParam = new RelativeLayout.LayoutParams(mLeftBlankWidth, ViewGroup.LayoutParams.MATCH_PARENT);
531 | leftBlank.setLayoutParams(leftParam);
532 | mList.addView(leftBlank);
533 |
534 | mImageBarLen = 0;
535 | for (int i = 0; i < lists.size(); i++) {
536 |
537 | ImageView imageView = new ImageView(mContext);
538 |
539 | int destWidth = mImageWidth;
540 | if (i == lists.size() - 1) {
541 | destWidth = (int) (mImageWidth * mLastImageWidthPercent);
542 | }
543 |
544 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(destWidth, mImageHeight);
545 | params.gravity = Gravity.CENTER_VERTICAL;
546 | imageView.setLayoutParams(params);
547 | imageView.setBackgroundDrawable(lists.get(i));
548 | mList.addView(imageView);
549 | mImageBarLen += destWidth;
550 | }
551 |
552 | View rightBlank = new View(mContext);
553 | ViewGroup.LayoutParams rightParam = new RelativeLayout.LayoutParams(mRightBlankWidth, ViewGroup.LayoutParams.MATCH_PARENT);
554 | rightBlank.setLayoutParams(rightParam);
555 | mList.addView(rightBlank);
556 |
557 | mHorizontalScrollView.setBarLength(getWidth());
558 | mHorizontalScrollView.setImageBarLen(mImageBarLen);
559 | mHorizontalScrollView.setSeekWidth(mImageBarLen + mLeftBlankWidth + mRightBlankWidth);
560 | }
561 |
562 | /**
563 | * 设置图片背景
564 | * @param paths
565 | */
566 | public void setImageListPath(List paths) {
567 | List lists = new ArrayList<>();
568 | for(int i = 0; i < paths.size(); i ++) {
569 | Drawable drawable = BitmapDrawable.createFromPath(paths.get(i));
570 | lists.add(drawable);
571 | }
572 | setImageList0(lists);
573 | }
574 |
575 | /**
576 | * 设置图片背景
577 | * @param ids
578 | */
579 | public void setImageListIds(List ids) {
580 | List lists = new ArrayList<>();
581 | for(int i = 0; i < ids.size(); i ++) {
582 | Drawable drawable = getResources().getDrawable(ids.get(i));
583 | lists.add(drawable);
584 | }
585 | setImageList0(lists);
586 | }
587 |
588 | public void setOnProgressChangeListener(OnSeekbarChangedListener listener) {
589 | this.mProgressChangeListener = listener;
590 | }
591 |
592 | public interface OnSeekbarChangedListener {
593 | void onProgressChanged(double progress, boolean fromUser);
594 | void onRangeChanged(int id, double startPercent, double selectPercent);
595 | }
596 | }
597 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_bar_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_bar_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_bar_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/left_arrow_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/multi_range_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/right_arrow_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
11 |
12 |
17 |
18 |
22 |
23 |
28 |
29 |
34 |
35 |
36 |
37 |
40 |
41 |
46 |
47 |
52 |
53 |
54 |
55 |
59 |
60 |
65 |
66 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_image_seekbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
11 |
19 |
20 |
25 |
26 |
32 |
33 |
34 |
35 |
36 |
37 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/left_arrow_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/app/src/main/res/mipmap-xhdpi/left_arrow_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/left_arrow_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/app/src/main/res/mipmap-xhdpi/left_arrow_press.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/point_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/app/src/main/res/mipmap-xhdpi/point_arrow.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/right_arrow_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/app/src/main/res/mipmap-xhdpi/right_arrow_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/right_arrow_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/app/src/main/res/mipmap-xhdpi/right_arrow_press.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/app/src/main/res/mipmap-xhdpi/test.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/vertical_bar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/app/src/main/res/mipmap-xhdpi/vertical_bar.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RangeImageSelectedView
3 |
4 | Hello world!
5 | Settings
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.3.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Mar 02 14:37:17 CST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/rangview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhgeaits/RangeImageSelectedView/d9bfeed871ac6966805d39b701ee5ad601a083dd/rangview.gif
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------