├── images
├── 0.jpg
├── 1.jpg
├── 2.jpg
├── 3.jpg
├── 4.jpg
├── 5.jpg
└── 6.jpg
├── ic_launcher-web.png
├── libs
├── android-support-v4.jar
└── universal-image-loader-1.9.3.jar
├── res
├── drawable-hdpi
│ └── ic_launcher.png
├── drawable-mdpi
│ └── ic_launcher.png
├── drawable-xhdpi
│ ├── ic_launcher.png
│ ├── loading_01.png
│ ├── loading_02.png
│ ├── loading_03.png
│ ├── loading_04.png
│ ├── loading_05.png
│ ├── loading_06.png
│ ├── loading_07.png
│ ├── loading_08.png
│ ├── loading_09.png
│ ├── loading_10.png
│ ├── loading_11.png
│ ├── loading_12.png
│ ├── default_picture.png
│ ├── item_delete_pic.png
│ ├── select_new_picture.png
│ ├── pull_to_refresh_icon.png
│ ├── select_picture_take_picture.png
│ └── select_picture_grid_item_flag.png
├── drawable-xxhdpi
│ └── ic_launcher.png
├── values
│ ├── ids.xml
│ ├── dimens.xml
│ ├── strings.xml
│ ├── colors.xml
│ ├── styles.xml
│ ├── vpi__attrs.xml
│ └── attrs.xml
├── layout
│ ├── selected_picture_choose_imageview.xml
│ ├── common_im_image_pager_item.xml
│ ├── common_im_image_pager.xml
│ ├── activity_main.xml
│ ├── item_select_picture_grid.xml
│ ├── item_select_picture_view.xml
│ ├── im_select_picture_view_layout.xml
│ ├── pull_to_refresh_header_vertical.xml
│ └── activity_select_picture.xml
├── menu
│ └── main.xml
├── values-w820dp
│ └── dimens.xml
├── drawable
│ ├── normal_state_background.xml
│ ├── normal_rounderd_state_background.xml
│ ├── normal_top_state_background.xml
│ ├── normal_bottom_state_background.xml
│ ├── alert_single_button_background.xml
│ └── im_loading_icon.xml
└── anim
│ ├── pull_to_refresh_slide_in_from_top.xml
│ ├── pull_to_refresh_slide_out_to_top.xml
│ ├── pull_to_refresh_slide_in_from_bottom.xml
│ └── pull_to_refresh_slide_out_to_bottom.xml
├── .settings
└── org.eclipse.jdt.core.prefs
├── .classpath
├── project.properties
├── src
└── com
│ ├── wuba
│ └── bangbang
│ │ └── uicomponents
│ │ ├── acitonsheet
│ │ └── IActionSheetListener.java
│ │ ├── pulltorefresh
│ │ ├── internal
│ │ │ ├── Utils.java
│ │ │ ├── EmptyViewMethodAccessor.java
│ │ │ ├── IMLoadingLayout.java
│ │ │ ├── ViewCompat.java
│ │ │ ├── IndicatorLayout.java
│ │ │ └── LoadingLayout.java
│ │ ├── ILoadingLayout.java
│ │ ├── LoadingLayoutProxy.java
│ │ ├── PullToRefreshGridView.java
│ │ ├── IPullToRefresh.java
│ │ └── OverscrollHelper.java
│ │ ├── utils
│ │ ├── DensityUtil.java
│ │ ├── CompatUtil.java
│ │ └── ImageLoaderUtils.java
│ │ ├── gesture
│ │ ├── listener
│ │ │ └── OnGestureListener.java
│ │ ├── IGestureDetector.java
│ │ ├── VersionedGestureGenerator.java
│ │ ├── FroyoGestureDetector.java
│ │ ├── EclairGestureDetector.java
│ │ └── CupcakeGestureDetector.java
│ │ ├── scrollerproxy
│ │ ├── IcsScroller.java
│ │ ├── PreGingerScroller.java
│ │ └── GingerScroller.java
│ │ ├── viewpagerindicator
│ │ ├── HackyViewPager.java
│ │ └── PageIndicator.java
│ │ ├── photoview
│ │ ├── ScrollerProxy.java
│ │ ├── DefaultOnDoubleTapListener.java
│ │ ├── PhotoView.java
│ │ └── IPhotoView.java
│ │ └── imselectpicture
│ │ └── IMSelectPictureGridAdapter.java
│ └── example
│ ├── android_select_picture_module
│ ├── MyApplication.java
│ └── MainActivity.java
│ └── uicomponents
│ ├── IMPhotoView.java
│ ├── IMCirclePageIndicator.java
│ ├── IMImageView.java
│ ├── IMLocalImageViewFragment.java
│ └── IMLocalImagePager.java
├── proguard-project.txt
├── .project
├── README.md
└── AndroidManifest.xml
/images/0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/images/0.jpg
--------------------------------------------------------------------------------
/images/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/images/1.jpg
--------------------------------------------------------------------------------
/images/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/images/2.jpg
--------------------------------------------------------------------------------
/images/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/images/3.jpg
--------------------------------------------------------------------------------
/images/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/images/4.jpg
--------------------------------------------------------------------------------
/images/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/images/5.jpg
--------------------------------------------------------------------------------
/images/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/images/6.jpg
--------------------------------------------------------------------------------
/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/ic_launcher-web.png
--------------------------------------------------------------------------------
/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/loading_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/loading_01.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/loading_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/loading_02.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/loading_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/loading_03.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/loading_04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/loading_04.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/loading_05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/loading_05.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/loading_06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/loading_06.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/loading_07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/loading_07.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/loading_08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/loading_08.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/loading_09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/loading_09.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/loading_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/loading_10.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/loading_11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/loading_11.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/loading_12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/loading_12.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/libs/universal-image-loader-1.9.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/libs/universal-image-loader-1.9.3.jar
--------------------------------------------------------------------------------
/res/drawable-xhdpi/default_picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/default_picture.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/item_delete_pic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/item_delete_pic.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/select_new_picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/select_new_picture.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/pull_to_refresh_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/pull_to_refresh_icon.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/select_picture_take_picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/select_picture_take_picture.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/select_picture_grid_item_flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/select_picture_module/HEAD/res/drawable-xhdpi/select_picture_grid_item_flag.png
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/res/layout/selected_picture_choose_imageview.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 | 64dp
9 |
10 |
11 |
--------------------------------------------------------------------------------
/res/drawable/normal_state_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16px
5 |
6 | 18sp
7 |
8 |
9 |
10 | 6dp
11 |
12 |
13 | 10dp
14 |
15 |
16 | 1px
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 |
--------------------------------------------------------------------------------
/res/drawable/normal_rounderd_state_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/acitonsheet/IActionSheetListener.java:
--------------------------------------------------------------------------------
1 | package com.wuba.bangbang.uicomponents.acitonsheet;
2 |
3 | import android.support.v4.app.Fragment;
4 |
5 | /**
6 | * ActionSheet的监听
7 | * @date: 2014-8-5 下午9:41:26
8 | */
9 | public interface IActionSheetListener {
10 |
11 | /**
12 | * 隐藏时调用
13 | * @param actionSheet actionSheet
14 | * @param isCancel isCancel
15 | */
16 | void onDismiss(Fragment actionSheet, boolean isCancel);
17 |
18 | /**
19 | * 点击取消按钮是调用
20 | * @param actionSheet actionSheet
21 | * @param index index
22 | */
23 | void onOtherButtonClick(Fragment actionSheet, int index);
24 | }
--------------------------------------------------------------------------------
/src/com/example/android_select_picture_module/MyApplication.java:
--------------------------------------------------------------------------------
1 | /**
2 | * @project: 58bangbang
3 | * @file: MyApplication.java
4 | * @date: 2015-2-24 上午7:49:11
5 | * @copyright: 2015 58.com Inc. All rights reserved.
6 | */
7 | package com.example.android_select_picture_module;
8 |
9 | import android.app.Application;
10 |
11 | import com.wuba.bangbang.uicomponents.utils.ImageLoaderUtils;
12 |
13 | /**
14 | * 自定义的Application类
15 | * @author 徐宁
16 | * @date: 2015-2-24 上午7:49:11
17 | */
18 | public class MyApplication extends Application {
19 |
20 | @Override
21 | public void onCreate() {
22 |
23 | super.onCreate();
24 | ImageLoaderUtils.init(getApplicationContext());
25 | }
26 | }
--------------------------------------------------------------------------------
/res/drawable/normal_top_state_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/res/drawable/normal_bottom_state_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/res/drawable/alert_single_button_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | -
7 |
8 |
9 |
10 |
11 | -
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/res/layout/common_im_image_pager_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
12 |
13 |
19 |
20 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/pulltorefresh/internal/Utils.java:
--------------------------------------------------------------------------------
1 | package com.wuba.bangbang.uicomponents.pulltorefresh.internal;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 |
6 | public class Utils {
7 |
8 | static final String LOG_TAG = "PullToRefresh";
9 |
10 | public static void warnDeprecation(String depreacted, String replacement) {
11 | Log.w(LOG_TAG, "You're using the deprecated " + depreacted
12 | + " attr, please switch over to " + replacement);
13 | }
14 |
15 | /**
16 | * 获得手机的android版本号
17 | * @param context
18 | * @return
19 | */
20 | public static int getVersionCode(Context context){
21 |
22 | int result = 0;
23 | result = android.os.Build.VERSION.SDK_INT;
24 | return result;
25 | }
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/res/layout/common_im_image_pager.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
12 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | Android_select_picture_module
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # select_picture_module
2 | Choose custom chart component, which supports multiple specified folder pictures and supports full screen display and to delete the selected images (自定义选图组件,支持多选指定文件夹的图片,支持全屏展示和删除已选图片)
3 | 最终效果图:
4 | 点击添加图片按钮
5 | 
6 | 选择添加图片的方式
7 | 
8 | 选择图片
9 | 
10 | 
11 | 操作已选择的图片,可以点击按钮删除
12 | 
13 | 
14 | 已选择的图片支持单击查看大图
15 | 
16 |
17 |
--------------------------------------------------------------------------------
/res/anim/pull_to_refresh_slide_in_from_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/res/anim/pull_to_refresh_slide_out_to_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/res/anim/pull_to_refresh_slide_in_from_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/res/anim/pull_to_refresh_slide_out_to_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Android_select_picture_module
5 | 拍照
6 | 从相册选择
7 | 取消
8 |
9 |
10 | 下拉刷新
11 | 松开即可刷新
12 | 正在刷新
13 | 刷新成功
14 | 上拉加载更多
15 | 松开即可加载
16 | 正在加载
17 | 加载成功
18 |
19 | 只能选择%1$d张图片
20 |
21 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/utils/DensityUtil.java:
--------------------------------------------------------------------------------
1 | /**
2 | * @project: 58bangbang
3 | * @file: DensityUtil.java
4 | * @date: 2014年10月8日 下午4:52:53
5 | * @copyright: 2014 58.com Inc. All rights reserved.
6 | */
7 | package com.wuba.bangbang.uicomponents.utils;
8 |
9 | import android.content.Context;
10 |
11 | /**
12 | * TODO 添加类的功能描述.
13 | * @author 赵彦辉
14 | * @date: 2014年10月8日 下午4:52:53
15 | */
16 | public class DensityUtil {
17 | /**
18 | * 根据手机的分辨率从 dip 的单位 转成为 px(像素)
19 | */
20 | public static int dip2px(Context context, float dpValue) {
21 | final float scale = context.getResources().getDisplayMetrics().density;
22 | return (int) (dpValue * scale + 0.5f);
23 | }
24 |
25 | /**
26 | * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
27 | */
28 | public static int px2dip(Context context, float pxValue) {
29 | final float scale = context.getResources().getDisplayMetrics().density;
30 | return (int) (pxValue / scale + 0.5f);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 | #FFFFFFFF
6 | #00000000
7 | 0
8 | 3dp
9 | false
10 | #FFDDDDDD
11 | 1dp
12 |
13 |
14 | #D8D3CE
15 |
16 |
17 | #FDA01D
18 |
19 |
20 | #FFFFFF
21 |
22 | #BBB2A4
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/res/layout/item_select_picture_grid.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
16 |
17 |
24 |
25 |
--------------------------------------------------------------------------------
/src/com/example/uicomponents/IMPhotoView.java:
--------------------------------------------------------------------------------
1 | package com.example.uicomponents;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 |
6 | import com.wuba.bangbang.uicomponents.photoview.PhotoView;
7 |
8 | /**
9 | * 自定义的PhotoView
10 | * @author 徐宁
11 | * @date: 2015-2-27 上午10:53:22
12 | */
13 | public class IMPhotoView extends PhotoView {
14 |
15 | /**
16 | * Creates a new instance of IMPhotoView.
17 | *
18 | * @param context
19 | */
20 | public IMPhotoView(Context context) {
21 | super(context);
22 | }
23 |
24 | /**
25 | * Creates a new instance of IMPhotoView.
26 | *
27 | * @param context
28 | * @param attr
29 | */
30 | public IMPhotoView(Context context, AttributeSet attr) {
31 | super(context, attr);
32 | }
33 |
34 | /**
35 | * Creates a new instance of IMPhotoView.
36 | *
37 | * @param context
38 | * @param attr
39 | * @param defStyle
40 | */
41 | public IMPhotoView(Context context, AttributeSet attr, int defStyle) {
42 | super(context, attr, defStyle);
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/res/layout/item_select_picture_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
18 |
19 |
20 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/gesture/listener/OnGestureListener.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.gesture.listener;
17 |
18 | /**
19 | * 手势操作的接口
20 | * @author 徐宁
21 | * @date: 2015-2-27 上午11:08:51
22 | */
23 | public interface OnGestureListener {
24 |
25 | public void onDrag(float dx, float dy);
26 |
27 | public void onFling(float startX, float startY, float velocityX, float velocityY);
28 |
29 | public void onScale(float scaleFactor, float focusX, float focusY);
30 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/gesture/IGestureDetector.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.gesture;
17 |
18 | import android.view.MotionEvent;
19 | import com.wuba.bangbang.uicomponents.gesture.listener.OnGestureListener;
20 |
21 | /**
22 | * 不同api的手势监听器需要实现的接口
23 | * TODO 添加类的功能描述.
24 | * @author 徐宁
25 | * @date: 2015-2-27 上午11:26:15
26 | */
27 | public interface IGestureDetector {
28 |
29 | public boolean onTouchEvent(MotionEvent ev);
30 |
31 | public boolean isScaling();
32 |
33 | public void setOnGestureListener(OnGestureListener listener);
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/scrollerproxy/IcsScroller.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.scrollerproxy;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 |
21 | /**
22 | * API14及以上的Scroller
23 | * @author 徐宁
24 | * @date: 2015-2-27 下午2:00:10
25 | */
26 | @TargetApi(14)
27 | public class IcsScroller extends GingerScroller {
28 |
29 | public IcsScroller(Context context) {
30 | super(context);
31 | }
32 |
33 | @Override
34 | public boolean computeScrollOffset() {
35 | return mScroller.computeScrollOffset();
36 | }
37 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/viewpagerindicator/HackyViewPager.java:
--------------------------------------------------------------------------------
1 | package com.wuba.bangbang.uicomponents.viewpagerindicator;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.ViewPager;
5 | import android.util.AttributeSet;
6 | import android.view.MotionEvent;
7 |
8 | /**
9 | * Hacky fix for Issue #4 and
10 | * http://code.google.com/p/android/issues/detail?id=18990
11 | *
12 | * ScaleGestureDetector seems to mess up the touch events, which means that
13 | * ViewGroups which make use of onInterceptTouchEvent throw a lot of
14 | * IllegalArgumentException: pointerIndex out of range.
15 | *
16 | * There's not much I can do in my code for now, but we can mask the result by
17 | * just catching the problem and ignoring it.
18 | *
19 | * @author Chris Banes
20 | */
21 | public class HackyViewPager extends ViewPager {
22 |
23 | public HackyViewPager(Context context) {
24 | super(context);
25 | }
26 |
27 | public HackyViewPager(Context context, AttributeSet attrs) {
28 | super(context, attrs);
29 | }
30 |
31 | @Override
32 | public boolean onInterceptTouchEvent(MotionEvent ev) {
33 | try {
34 | return super.onInterceptTouchEvent(ev);
35 | } catch (IllegalArgumentException e) {
36 | e.printStackTrace();
37 | return false;
38 | }catch (ArrayIndexOutOfBoundsException e) {
39 | e.printStackTrace();
40 | return false;
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/src/com/example/uicomponents/IMCirclePageIndicator.java:
--------------------------------------------------------------------------------
1 | /**
2 | * @project: 58bangbang
3 | * @file: IMCirclePageIndicator.java
4 | * @date: 2014年10月23日 上午9:50:16
5 | * @copyright: 2014 58.com Inc. All rights reserved.
6 | */
7 | package com.example.uicomponents;
8 |
9 | import android.content.Context;
10 | import android.util.AttributeSet;
11 |
12 | import com.wuba.bangbang.uicomponents.viewpagerindicator.CirclePageIndicator;
13 |
14 | /**
15 | * ViewPager的分页指示器,继承自开源项目viewpagerindicator.
16 | * https://github.com/JakeWharton/Android-ViewPagerIndicator
17 | */
18 | public class IMCirclePageIndicator extends CirclePageIndicator {
19 |
20 | /**
21 | * Creates a new instance of IMCirclePageIndicator.
22 | *
23 | * @param context
24 | */
25 | public IMCirclePageIndicator(Context context) {
26 | super(context);
27 | }
28 |
29 | /**
30 | * Creates a new instance of IMCirclePageIndicator.
31 | *
32 | * @param context
33 | * @param attrs
34 | */
35 | public IMCirclePageIndicator(Context context, AttributeSet attrs) {
36 | super(context, attrs);
37 | }
38 |
39 | /**
40 | * Creates a new instance of IMCirclePageIndicator.
41 | *
42 | * @param context
43 | * @param attrs
44 | * @param defStyle
45 | */
46 | public IMCirclePageIndicator(Context context, AttributeSet attrs, int defStyle) {
47 | super(context, attrs, defStyle);
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/res/layout/im_select_picture_view_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
14 |
15 |
21 |
22 |
29 |
30 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/res/layout/pull_to_refresh_header_vertical.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
17 |
18 |
23 |
24 |
30 |
31 |
32 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/com/example/uicomponents/IMImageView.java:
--------------------------------------------------------------------------------
1 | /**
2 | * @project: 58bangbang
3 | * @file: IMImageView.java
4 | * @date: 2014-8-5 下午3:42:49
5 | * @copyright: 2014 58.com Inc. All rights reserved.
6 | */
7 | package com.example.uicomponents;
8 |
9 | import android.content.Context;
10 | import android.util.AttributeSet;
11 | import android.widget.ImageView;
12 |
13 |
14 | public class IMImageView extends ImageView {
15 |
16 | /**显示图片的路径*/
17 | private String url;
18 |
19 | /**
20 | * Creates a new instance of IMImageView.
21 | *
22 | * @param context
23 | * context
24 | */
25 | public IMImageView(Context context) {
26 | super(context);
27 | }
28 |
29 | /**
30 | * Creates a new instance of IMImageView.
31 | *
32 | * @param context
33 | * context
34 | * @param attrs
35 | * attrs
36 | */
37 | public IMImageView(Context context, AttributeSet attrs) {
38 | super(context, attrs);
39 | }
40 |
41 | /**
42 | * Creates a new instance of IMImageView.
43 | *
44 | * @param context
45 | * context
46 | * @param attrs
47 | * attrs
48 | * @param defStyle
49 | * defStyle
50 | */
51 | public IMImageView(Context context, AttributeSet attrs, int defStyle) {
52 | super(context, attrs, defStyle);
53 | }
54 |
55 | /**
56 | * @return the url
57 | */
58 | public String getUrl() {
59 | return url;
60 | }
61 |
62 | /**
63 | * @param url the url to set
64 | */
65 | public void setUrl(String url) {
66 | this.url = url;
67 | }
68 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/pulltorefresh/internal/EmptyViewMethodAccessor.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.pulltorefresh.internal;
17 |
18 | import android.view.View;
19 |
20 | /**
21 | * Interface that allows PullToRefreshBase to hijack the call to
22 | * AdapterView.setEmptyView()
23 | *
24 | * @author chris
25 | */
26 | public interface EmptyViewMethodAccessor {
27 |
28 | /**
29 | * Calls upto AdapterView.setEmptyView()
30 | *
31 | * @param emptyView
32 | * - to set as Empty View
33 | */
34 | public void setEmptyViewInternal(View emptyView);
35 |
36 | /**
37 | * Should call PullToRefreshBase.setEmptyView() which will then
38 | * automatically call through to setEmptyViewInternal()
39 | *
40 | * @param emptyView
41 | * - to set as Empty View
42 | */
43 | public void setEmptyView(View emptyView);
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/pulltorefresh/ILoadingLayout.java:
--------------------------------------------------------------------------------
1 | package com.wuba.bangbang.uicomponents.pulltorefresh;
2 |
3 | import android.graphics.Typeface;
4 | import android.graphics.drawable.Drawable;
5 |
6 | public interface ILoadingLayout {
7 |
8 | /**
9 | * Set the drawable used in the loading layout. This is the same as calling
10 | * setLoadingDrawable(drawable, Mode.BOTH)
11 | *
12 | * @param drawable
13 | * - Drawable to display
14 | */
15 | public void setLoadingDrawable(Drawable drawable);
16 |
17 | /**
18 | * Set Text to show when the Widget is being Pulled
19 | * setPullLabel(releaseLabel, Mode.BOTH)
20 | *
21 | * @param pullLabel
22 | * - CharSequence to display
23 | */
24 | public void setPullLabel(CharSequence pullLabel);
25 |
26 | /**
27 | * Set Text to show when the Widget is refreshing
28 | * setRefreshingLabel(releaseLabel, Mode.BOTH)
29 | *
30 | * @param refreshingLabel
31 | * - CharSequence to display
32 | */
33 | public void setRefreshingLabel(CharSequence refreshingLabel);
34 |
35 | /**
36 | * Set Text to show when the Widget is being pulled, and will refresh when
37 | * released. This is the same as calling
38 | * setReleaseLabel(releaseLabel, Mode.BOTH)
39 | *
40 | * @param releaseLabel
41 | * - CharSequence to display
42 | */
43 | public void setReleaseLabel(CharSequence releaseLabel);
44 |
45 | /**
46 | * Set's the Sets the typeface and style in which the text should be
47 | * displayed. Please see
48 | * {@link android.widget.TextView#setTypeface(Typeface)
49 | * TextView#setTypeface(Typeface)}.
50 | */
51 | public void setTextTypeface(Typeface tf);
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/pulltorefresh/internal/IMLoadingLayout.java:
--------------------------------------------------------------------------------
1 | package com.wuba.bangbang.uicomponents.pulltorefresh.internal;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.drawable.Drawable;
6 | import android.view.View;
7 |
8 | import com.example.android_select_picture_module.R;
9 | import com.wuba.bangbang.uicomponents.pulltorefresh.PullToRefreshBase.Mode;
10 |
11 | public class IMLoadingLayout extends LoadingLayout {
12 |
13 | public IMLoadingLayout(Context context, Mode mode, TypedArray attrs) {
14 | super(context, mode, attrs);
15 | }
16 |
17 | @Override
18 | protected int getDefaultDrawableResId() {
19 | return R.drawable.pull_to_refresh_icon;
20 | }
21 |
22 | @Override
23 | protected void onLoadingDrawableSet(Drawable imageDrawable) {
24 |
25 | }
26 |
27 | @Override
28 | protected void onPullImpl(float scaleOfLayout) {
29 |
30 | System.out.println("-------->onPullImpl");
31 | if(mProgressBar.getVisibility() == View.VISIBLE){
32 |
33 | mProgressBar.setVisibility(View.GONE);
34 | }
35 | if(mInnerLayout.getVisibility() != View.VISIBLE){
36 |
37 | mInnerLayout.setVisibility(View.VISIBLE);
38 | }
39 | }
40 |
41 | @Override
42 | protected void pullToRefreshImpl() {
43 | System.out.println("-------->pullToRefreshImpl");
44 | }
45 |
46 | @Override
47 | protected void refreshingImpl() {
48 | System.out.println("-------->refreshingImpl");
49 | }
50 |
51 | @Override
52 | protected void releaseToRefreshImpl() {
53 |
54 | System.out.println("-------->releaseToRefreshImpl");
55 | }
56 |
57 | @Override
58 | protected void resetImpl() {
59 |
60 | System.out.println("--------->resetImpl");
61 | mHeaderText.setText(mFinishLabel);
62 | }
63 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/gesture/VersionedGestureGenerator.java:
--------------------------------------------------------------------------------
1 | package com.wuba.bangbang.uicomponents.gesture;
2 |
3 | /*******************************************************************************
4 | * Copyright 2011, 2012 Chris Banes.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *******************************************************************************/
18 |
19 | import android.content.Context;
20 | import android.os.Build;
21 |
22 | import com.wuba.bangbang.uicomponents.gesture.listener.OnGestureListener;
23 |
24 | /**
25 | * 根据不同的sdk版本,生成手势监听器
26 | * @author 徐宁
27 | * @date: 2015-2-27 上午11:01:57
28 | */
29 | public final class VersionedGestureGenerator {
30 |
31 | public static IGestureDetector newInstance(Context context, OnGestureListener listener) {
32 |
33 | final int sdkVersion = Build.VERSION.SDK_INT;
34 | IGestureDetector detector;
35 |
36 | if (sdkVersion < Build.VERSION_CODES.ECLAIR) { //api5
37 | detector = new CupcakeGestureDetector(context);
38 | } else if (sdkVersion < Build.VERSION_CODES.FROYO) { //api8
39 | detector = new EclairGestureDetector(context);
40 | } else {
41 | detector = new FroyoGestureDetector(context);
42 | }
43 | detector.setOnGestureListener(listener);
44 | return detector;
45 | }
46 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/viewpagerindicator/PageIndicator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 Patrik Akerfeldt
3 | * Copyright (C) 2011 Jake Wharton
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.wuba.bangbang.uicomponents.viewpagerindicator;
19 |
20 | import android.support.v4.view.ViewPager;
21 |
22 | /**
23 | * A PageIndicator is responsible to show an visual indicator on the total views
24 | * number and the current visible view.
25 | */
26 | public interface PageIndicator extends ViewPager.OnPageChangeListener {
27 | /**
28 | * Bind the indicator to a ViewPager.
29 | *
30 | * @param view
31 | */
32 | void setViewPager(ViewPager view);
33 |
34 | /**
35 | * Bind the indicator to a ViewPager.
36 | *
37 | * @param view
38 | * @param initialPosition
39 | */
40 | void setViewPager(ViewPager view, int initialPosition);
41 |
42 | /**
43 | * Set the current page of both the ViewPager and indicator.
44 | *
45 | * This must be used if you need to set the page before
46 | * the views are drawn on screen (e.g., default start page).
47 | *
48 | * @param item
49 | */
50 | void setCurrentItem(int item);
51 |
52 | /**
53 | * Set a page change listener which will receive forwarded events.
54 | *
55 | * @param listener
56 | */
57 | void setOnPageChangeListener(ViewPager.OnPageChangeListener listener);
58 |
59 | /**
60 | * Notify the indicator that the fragment list has changed.
61 | */
62 | void notifyDataSetChanged();
63 | }
64 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/pulltorefresh/LoadingLayoutProxy.java:
--------------------------------------------------------------------------------
1 | package com.wuba.bangbang.uicomponents.pulltorefresh;
2 |
3 | import java.util.HashSet;
4 |
5 | import android.graphics.Typeface;
6 | import android.graphics.drawable.Drawable;
7 |
8 | import com.wuba.bangbang.uicomponents.pulltorefresh.internal.LoadingLayout;
9 |
10 | public class LoadingLayoutProxy implements ILoadingLayout {
11 |
12 | private final HashSet mLoadingLayouts;
13 |
14 | LoadingLayoutProxy() {
15 | mLoadingLayouts = new HashSet();
16 | }
17 |
18 | /**
19 | * This allows you to add extra LoadingLayout instances to this proxy. This
20 | * is only necessary if you keep your own instances, and want to have them
21 | * included in any
22 | * {@link PullToRefreshBase#createLoadingLayoutProxy(boolean, boolean)
23 | * createLoadingLayoutProxy(...)} calls.
24 | *
25 | * @param layout
26 | * - LoadingLayout to have included.
27 | */
28 | public void addLayout(LoadingLayout layout) {
29 | if (null != layout) {
30 | mLoadingLayouts.add(layout);
31 | }
32 | }
33 |
34 | @Override
35 | public void setLoadingDrawable(Drawable drawable) {
36 | for (LoadingLayout layout : mLoadingLayouts) {
37 | layout.setLoadingDrawable(drawable);
38 | }
39 | }
40 |
41 | @Override
42 | public void setRefreshingLabel(CharSequence refreshingLabel) {
43 | for (LoadingLayout layout : mLoadingLayouts) {
44 | layout.setRefreshingLabel(refreshingLabel);
45 | }
46 | }
47 |
48 | @Override
49 | public void setPullLabel(CharSequence label) {
50 | for (LoadingLayout layout : mLoadingLayouts) {
51 | layout.setPullLabel(label);
52 | }
53 | }
54 |
55 | @Override
56 | public void setReleaseLabel(CharSequence label) {
57 | for (LoadingLayout layout : mLoadingLayouts) {
58 | layout.setReleaseLabel(label);
59 | }
60 | }
61 |
62 | public void setTextTypeface(Typeface tf) {
63 | for (LoadingLayout layout : mLoadingLayouts) {
64 | layout.setTextTypeface(tf);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/utils/CompatUtil.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.utils;
17 |
18 | import android.annotation.TargetApi;
19 | import android.os.Build;
20 | import android.os.Build.VERSION;
21 | import android.view.MotionEvent;
22 | import android.view.View;
23 |
24 |
25 |
26 | /**
27 | * 适配的工具类
28 | * @author 徐宁
29 | * @date: 2015-2-26 下午6:09:37
30 | */
31 | public class CompatUtil {
32 |
33 | private static final int SIXTY_FPS_INTERVAL = 1000 / 60;
34 | private static final int VERSION_CODES_HONEYCOMB = 11;
35 |
36 | public static void postOnAnimation(View view, Runnable runnable) {
37 |
38 | view.postDelayed(runnable, SIXTY_FPS_INTERVAL);
39 | }
40 |
41 |
42 | public static int getPointerIndex(int action) {
43 | if (VERSION.SDK_INT >= VERSION_CODES_HONEYCOMB)
44 | return getPointerIndexHoneyComb(action);
45 | else
46 | return getPointerIndexEclair(action);
47 | }
48 |
49 | @TargetApi(Build.VERSION_CODES.ECLAIR)
50 | private static int getPointerIndexEclair(int action) {
51 | return (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
52 | }
53 |
54 | @TargetApi(CompatUtil.VERSION_CODES_HONEYCOMB)
55 | private static int getPointerIndexHoneyComb(int action) {
56 | return (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
57 | }
58 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/scrollerproxy/PreGingerScroller.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.scrollerproxy;
17 |
18 | import android.content.Context;
19 | import android.widget.Scroller;
20 |
21 | import com.wuba.bangbang.uicomponents.photoview.ScrollerProxy;
22 |
23 | /**
24 | * 支持API9以下的Scroller
25 | * @author 徐宁
26 | * @date: 2015-2-27 下午1:57:51
27 | */
28 | public class PreGingerScroller extends ScrollerProxy {
29 |
30 | private final Scroller mScroller;
31 |
32 | public PreGingerScroller(Context context) {
33 | mScroller = new Scroller(context);
34 | }
35 |
36 | @Override
37 | public boolean computeScrollOffset() {
38 | return mScroller.computeScrollOffset();
39 | }
40 |
41 | @Override
42 | public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY,
43 | int overX, int overY) {
44 | mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
45 | }
46 |
47 | @Override
48 | public void forceFinished(boolean finished) {
49 | mScroller.forceFinished(finished);
50 | }
51 |
52 | public boolean isFinished() {
53 | return mScroller.isFinished();
54 | }
55 |
56 | @Override
57 | public int getCurrX() {
58 | return mScroller.getCurrX();
59 | }
60 |
61 | @Override
62 | public int getCurrY() {
63 | return mScroller.getCurrY();
64 | }
65 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/photoview/ScrollerProxy.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.photoview;
17 |
18 | import android.content.Context;
19 | import android.os.Build.VERSION;
20 | import android.os.Build.VERSION_CODES;
21 |
22 | import com.wuba.bangbang.uicomponents.scrollerproxy.GingerScroller;
23 | import com.wuba.bangbang.uicomponents.scrollerproxy.IcsScroller;
24 | import com.wuba.bangbang.uicomponents.scrollerproxy.PreGingerScroller;
25 |
26 | /**
27 | * Scroller的抽象代理类
28 | * @author 徐宁
29 | * @date: 2015-2-27 下午1:54:30
30 | */
31 | public abstract class ScrollerProxy {
32 |
33 | private static final int VERSION_CODES_ICE_CREAM_SANDWICH = 14;
34 |
35 | public static ScrollerProxy getScroller(Context context) {
36 | if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) {
37 | return new PreGingerScroller(context);
38 | } else if (VERSION.SDK_INT < VERSION_CODES_ICE_CREAM_SANDWICH) {
39 | return new GingerScroller(context);
40 | } else {
41 | return new IcsScroller(context);
42 | }
43 | }
44 |
45 | public abstract boolean computeScrollOffset();
46 |
47 | public abstract void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, int overX, int overY);
48 |
49 | public abstract void forceFinished(boolean finished);
50 |
51 | public abstract boolean isFinished();
52 |
53 | public abstract int getCurrX();
54 |
55 | public abstract int getCurrY();
56 | }
57 |
--------------------------------------------------------------------------------
/res/layout/activity_select_picture.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
13 |
14 |
22 |
23 |
24 |
25 |
26 |
34 |
35 |
41 |
42 |
48 |
49 |
50 |
51 |
55 |
56 |
57 |
58 |
63 |
64 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/scrollerproxy/GingerScroller.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.scrollerproxy;
17 |
18 | import com.wuba.bangbang.uicomponents.photoview.ScrollerProxy;
19 |
20 | import android.annotation.TargetApi;
21 | import android.content.Context;
22 | import android.widget.OverScroller;
23 |
24 | /**
25 | * 支持API 9~14 的Scroller
26 | * @author 徐宁
27 | * @date: 2015-2-27 下午1:58:48
28 | */
29 | @TargetApi(9)
30 | public class GingerScroller extends ScrollerProxy {
31 |
32 | protected final OverScroller mScroller;
33 | private boolean mFirstScroll = false;
34 |
35 | public GingerScroller(Context context) {
36 | mScroller = new OverScroller(context);
37 | }
38 |
39 | @Override
40 | public boolean computeScrollOffset() {
41 | // Workaround for first scroll returning 0 for the direction of the edge it hits.
42 | // Simply recompute values.
43 | if (mFirstScroll) {
44 | mScroller.computeScrollOffset();
45 | mFirstScroll = false;
46 | }
47 | return mScroller.computeScrollOffset();
48 | }
49 |
50 | @Override
51 | public void fling(int startX, int startY, int velocityX, int velocityY,
52 | int minX, int maxX, int minY, int maxY, int overX, int overY) {
53 | mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, overX, overY);
54 | }
55 |
56 | @Override
57 | public void forceFinished(boolean finished) {
58 | mScroller.forceFinished(finished);
59 | }
60 |
61 | @Override
62 | public boolean isFinished() {
63 | return mScroller.isFinished();
64 | }
65 |
66 | @Override
67 | public int getCurrX() {
68 | return mScroller.getCurrX();
69 | }
70 |
71 | @Override
72 | public int getCurrY() {
73 | return mScroller.getCurrY();
74 | }
75 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/gesture/FroyoGestureDetector.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.gesture;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 | import android.view.MotionEvent;
21 | import android.view.ScaleGestureDetector;
22 |
23 | /**
24 | * API2.2手势监听器
25 | * @author 徐宁
26 | * @date: 2015-2-27 上午11:25:18
27 | */
28 | @TargetApi(8)
29 | public class FroyoGestureDetector extends EclairGestureDetector {
30 |
31 | protected final ScaleGestureDetector mDetector;
32 |
33 | /**
34 | * API2.2手势监听器
35 | * @param context
36 | */
37 | public FroyoGestureDetector(Context context) {
38 | super(context);
39 | ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() {
40 |
41 | @Override
42 | public boolean onScale(ScaleGestureDetector detector) {
43 | float scaleFactor = detector.getScaleFactor();
44 |
45 | if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor))
46 | return false;
47 |
48 | mListener.onScale(scaleFactor,
49 | detector.getFocusX(), detector.getFocusY());
50 | return true;
51 | }
52 |
53 | @Override
54 | public boolean onScaleBegin(ScaleGestureDetector detector) {
55 | return true;
56 | }
57 |
58 | @Override
59 | public void onScaleEnd(ScaleGestureDetector detector) {
60 | // NO-OP
61 | }
62 | };
63 | mDetector = new ScaleGestureDetector(context, mScaleListener);
64 | }
65 |
66 | @Override
67 | public boolean isScaling() {
68 | return mDetector.isInProgress();
69 | }
70 |
71 | @Override
72 | public boolean onTouchEvent(MotionEvent ev) {
73 | mDetector.onTouchEvent(ev);
74 | return super.onTouchEvent(ev);
75 | }
76 | }
--------------------------------------------------------------------------------
/res/drawable/im_loading_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 | -
7 |
11 |
12 | -
13 |
17 |
18 | -
19 |
23 |
24 | -
25 |
29 |
30 | -
31 |
35 |
36 | -
37 |
41 |
42 | -
43 |
47 |
48 | -
49 |
53 |
54 | -
55 |
59 |
60 | -
61 |
65 |
66 | -
67 |
71 |
72 | -
73 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/pulltorefresh/PullToRefreshGridView.java:
--------------------------------------------------------------------------------
1 | /**
2 | * @project: 58bangbang
3 | * @file: PullToRefreshGridView.java
4 | * @date: 2014-11-28 上午7:04:32
5 | * @copyright: 2014 58.com Inc. All rights reserved.
6 | */
7 | package com.wuba.bangbang.uicomponents.pulltorefresh;
8 |
9 | import android.annotation.TargetApi;
10 | import android.content.Context;
11 | import android.os.Build.VERSION;
12 | import android.os.Build.VERSION_CODES;
13 | import android.util.AttributeSet;
14 | import android.view.View;
15 | import android.widget.GridView;
16 |
17 | import com.example.android_select_picture_module.R;
18 | import com.wuba.bangbang.uicomponents.pulltorefresh.internal.EmptyViewMethodAccessor;
19 |
20 | /**
21 | * 下拉刷新GridView
22 | * @author Jack
23 | * @version 创建时间:2014-11-28 上午7:04:32
24 | */
25 | public class PullToRefreshGridView extends PullToRefreshAdapterViewBase {
26 |
27 | public PullToRefreshGridView(Context context) {
28 | super(context);
29 | }
30 |
31 | public PullToRefreshGridView(Context context, AttributeSet attrs) {
32 | super(context, attrs);
33 | }
34 |
35 | public PullToRefreshGridView(Context context, Mode mode) {
36 | super(context, mode);
37 | }
38 |
39 | public PullToRefreshGridView(Context context, Mode mode, AnimationStyle style) {
40 | super(context, mode, style);
41 | }
42 |
43 | @Override
44 | public final Orientation getPullToRefreshScrollDirection() {
45 | return Orientation.VERTICAL;
46 | }
47 |
48 | @Override
49 | protected final GridView createRefreshableView(Context context, AttributeSet attrs) {
50 | final GridView gv;
51 | if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
52 | gv = new InternalGridViewSDK9(context, attrs);
53 | } else {
54 | gv = new InternalGridView(context, attrs);
55 | }
56 |
57 | gv.setId(R.id.gridview);
58 | return gv;
59 | }
60 |
61 | class InternalGridView extends GridView implements EmptyViewMethodAccessor {
62 |
63 | public InternalGridView(Context context, AttributeSet attrs) {
64 | super(context, attrs);
65 | }
66 |
67 | @Override
68 | public void setEmptyView(View emptyView) {
69 | PullToRefreshGridView.this.setEmptyView(emptyView);
70 | }
71 |
72 | @Override
73 | public void setEmptyViewInternal(View emptyView) {
74 | super.setEmptyView(emptyView);
75 | }
76 | }
77 |
78 | @TargetApi(9)
79 | final class InternalGridViewSDK9 extends InternalGridView {
80 |
81 | public InternalGridViewSDK9(Context context, AttributeSet attrs) {
82 | super(context, attrs);
83 | }
84 |
85 | @Override
86 | protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
87 | int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
88 |
89 | final boolean returnValue = super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
90 | scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
91 |
92 | OverscrollHelper.overScrollBy(PullToRefreshGridView.this, deltaX, scrollX, deltaY, scrollY, isTouchEvent);
93 |
94 | return returnValue;
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/pulltorefresh/internal/ViewCompat.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.pulltorefresh.internal;
17 |
18 | import java.lang.reflect.Method;
19 |
20 | import android.annotation.TargetApi;
21 | import android.graphics.drawable.Drawable;
22 | import android.os.Build.VERSION;
23 | import android.util.Log;
24 | import android.view.View;
25 |
26 |
27 | public class ViewCompat {
28 |
29 | private static final int VERSION_CODES_JELLY_BEAN = 16,
30 | VERSION_CODES_HONEYCOMB = 11;
31 |
32 | public static void postOnAnimation(View view, Runnable runnable) {
33 | if (VERSION.SDK_INT >= VERSION_CODES_JELLY_BEAN) {
34 | SDK16.postOnAnimation(view, runnable);
35 | } else {
36 | view.postDelayed(runnable, 16);
37 | }
38 | }
39 |
40 | public static void setBackground(View view, Drawable background) {
41 | if (VERSION.SDK_INT >= VERSION_CODES_JELLY_BEAN) {
42 | SDK16.setBackground(view, background);
43 | } else {
44 | view.setBackgroundDrawable(background);
45 | }
46 | }
47 |
48 | public static void setLayerType(View view, int layerType) {
49 | if (VERSION.SDK_INT >= VERSION_CODES_HONEYCOMB) {
50 | SDK11.setLayerType(view, layerType);
51 | }
52 | }
53 |
54 | @TargetApi(11)
55 | static class SDK11 {
56 |
57 | public static void setLayerType(View view, int layerType) {
58 | Log.e("jack", "-----------------");
59 | try{
60 | Class> clazz = view.getClass();
61 | Method method = clazz.getMethod("setLayerType", new Class>[] {int.class,Object.class});
62 | method.invoke(clazz, layerType,null);
63 | } catch (Exception e) {
64 | Log.e("zhaobo", "-----------------Exception",e);
65 | }
66 | //view.setLayerType(layerType, null);
67 | }
68 | }
69 |
70 |
71 | @TargetApi(16)
72 | static class SDK16 {
73 |
74 | public static void postOnAnimation(View view, Runnable runnable) {
75 | view.post(runnable);
76 | }
77 |
78 | public static void setBackground(View view, Drawable background) {
79 | view.setBackgroundDrawable(background);
80 | }
81 | }
82 | }
--------------------------------------------------------------------------------
/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
35 |
36 |
49 |
50 |
51 |
54 |
55 |
56 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/photoview/DefaultOnDoubleTapListener.java:
--------------------------------------------------------------------------------
1 | package com.wuba.bangbang.uicomponents.photoview;
2 |
3 | import android.graphics.RectF;
4 | import android.view.GestureDetector;
5 | import android.view.MotionEvent;
6 | import android.widget.ImageView;
7 |
8 | /**
9 | * Provided default implementation of GestureDetector.OnDoubleTapListener,
10 | * to be overriden with custom behavior, if needed
11 | *
12 | * To be used via {@link uk.co.senab.photoview.PhotoViewAttacher#setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener)}
13 | */
14 | public class DefaultOnDoubleTapListener implements GestureDetector.OnDoubleTapListener {
15 |
16 | /**支持图片缩放的显示类*/
17 | private PhotoViewAttacher photoViewAttacher;
18 |
19 | /**
20 | * Default constructor
21 | *
22 | * @param photoViewAttacher PhotoViewAttacher to bind to
23 | */
24 | public DefaultOnDoubleTapListener(PhotoViewAttacher photoViewAttacher) {
25 | setPhotoViewAttacher(photoViewAttacher);
26 | }
27 |
28 | /**
29 | * Allows to change PhotoViewAttacher within range of single instance
30 | *
31 | * @param newPhotoViewAttacher PhotoViewAttacher to bind to
32 | */
33 | public void setPhotoViewAttacher(PhotoViewAttacher newPhotoViewAttacher) {
34 | this.photoViewAttacher = newPhotoViewAttacher;
35 | }
36 |
37 | @Override
38 | public boolean onSingleTapConfirmed(MotionEvent e) {
39 | if (this.photoViewAttacher == null)
40 | return false;
41 |
42 | ImageView imageView = photoViewAttacher.getImageView();
43 |
44 | if (null != photoViewAttacher.getOnPhotoTapListener()) {
45 | final RectF displayRect = photoViewAttacher.getDisplayRect();
46 |
47 | if (null != displayRect) {
48 | final float x = e.getX(), y = e.getY();
49 |
50 | // Check to see if the user tapped on the photo
51 | if (displayRect.contains(x, y)) {
52 |
53 | float xResult = (x - displayRect.left) / displayRect.width();
54 | float yResult = (y - displayRect.top) / displayRect.height();
55 | photoViewAttacher.getOnPhotoTapListener().onPhotoTap(imageView, xResult, yResult);
56 | return true;
57 | }
58 | }
59 | }
60 | if (null != photoViewAttacher.getOnViewTapListener()) {
61 | photoViewAttacher.getOnViewTapListener().onViewTap(imageView, e.getX(), e.getY());
62 | }
63 |
64 | return false;
65 | }
66 |
67 | @Override
68 | public boolean onDoubleTap(MotionEvent ev) {
69 | if (photoViewAttacher == null)
70 | return false;
71 |
72 | try {
73 | float scale = photoViewAttacher.getScale();
74 | float x = ev.getX();
75 | float y = ev.getY();
76 |
77 | if (scale < photoViewAttacher.getMediumScale()) {
78 | photoViewAttacher.setScale(photoViewAttacher.getMediumScale(), x, y, true);
79 | } else if (scale >= photoViewAttacher.getMediumScale() && scale < photoViewAttacher.getMaximumScale()) {
80 | photoViewAttacher.setScale(photoViewAttacher.getMaximumScale(), x, y, true);
81 | } else {
82 | photoViewAttacher.setScale(photoViewAttacher.getMinimumScale(), x, y, true);
83 | }
84 | } catch (ArrayIndexOutOfBoundsException e) {
85 | // Can sometimes happen when getX() and getY() is called
86 | }
87 | return true;
88 | }
89 |
90 | @Override
91 | public boolean onDoubleTapEvent(MotionEvent e) {
92 | // Wait for the confirmed onDoubleTap() instead
93 | return false;
94 | }
95 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/gesture/EclairGestureDetector.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.gesture;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 | import android.view.MotionEvent;
21 |
22 | import com.wuba.bangbang.uicomponents.utils.CompatUtil;
23 |
24 | /**
25 | * API2.0手势监听器
26 | * @author 徐宁
27 | * @date: 2015-2-27 上午11:24:36
28 | */
29 | @TargetApi(5)
30 | public class EclairGestureDetector extends CupcakeGestureDetector {
31 |
32 | private static final int INVALID_POINTER_ID = -1;
33 | private int mActivePointerId = INVALID_POINTER_ID;
34 | private int mActivePointerIndex = 0;
35 |
36 | /**
37 | * API2.0手势监听器
38 | * @param context
39 | */
40 | public EclairGestureDetector(Context context) {
41 | super(context);
42 | }
43 |
44 | @Override
45 | float getActiveX(MotionEvent ev) {
46 | try {
47 | return ev.getX(mActivePointerIndex);
48 | } catch (Exception e) {
49 | return ev.getX();
50 | }
51 | }
52 |
53 | @Override
54 | float getActiveY(MotionEvent ev) {
55 | try {
56 | return ev.getY(mActivePointerIndex);
57 | } catch (Exception e) {
58 | return ev.getY();
59 | }
60 | }
61 |
62 | @Override
63 | public boolean onTouchEvent(MotionEvent ev) {
64 | final int action = ev.getAction();
65 | switch (action & MotionEvent.ACTION_MASK) {
66 | case MotionEvent.ACTION_DOWN:
67 | mActivePointerId = ev.getPointerId(0);
68 | break;
69 | case MotionEvent.ACTION_CANCEL:
70 | case MotionEvent.ACTION_UP:
71 | mActivePointerId = INVALID_POINTER_ID;
72 | break;
73 | case MotionEvent.ACTION_POINTER_UP:
74 | // Ignore deprecation, ACTION_POINTER_ID_MASK and
75 | // ACTION_POINTER_ID_SHIFT has same value and are deprecated
76 | // You can have either deprecation or lint target api warning
77 | final int pointerIndex = CompatUtil.getPointerIndex(ev.getAction());
78 | final int pointerId = ev.getPointerId(pointerIndex);
79 | if (pointerId == mActivePointerId) {
80 | // This was our active pointer going up. Choose a new
81 | // active pointer and adjust accordingly.
82 | final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
83 | mActivePointerId = ev.getPointerId(newPointerIndex);
84 | mLastTouchX = ev.getX(newPointerIndex);
85 | mLastTouchY = ev.getY(newPointerIndex);
86 | }
87 | break;
88 | }
89 |
90 | mActivePointerIndex = ev
91 | .findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId
92 | : 0);
93 | return super.onTouchEvent(ev);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/gesture/CupcakeGestureDetector.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.gesture;
17 |
18 | import android.content.Context;
19 | import android.util.Log;
20 | import android.view.MotionEvent;
21 | import android.view.VelocityTracker;
22 | import android.view.ViewConfiguration;
23 |
24 | import com.wuba.bangbang.uicomponents.gesture.listener.OnGestureListener;
25 |
26 | /**
27 | * API1.5手势监听器
28 | * @author 徐宁
29 | * @date: 2015-2-27 上午10:32:07
30 | */
31 | public class CupcakeGestureDetector implements IGestureDetector {
32 |
33 | protected OnGestureListener mListener;
34 | private static final String LOG_TAG = "CupcakeGestureDetector";
35 | protected float mLastTouchX;
36 | protected float mLastTouchY;
37 | private final float mTouchSlop;
38 | private final float mMinimumVelocity;
39 | private VelocityTracker mVelocityTracker;
40 | private boolean mIsDragging;
41 |
42 | /**
43 | * API1.5手势监听器
44 | * @param context
45 | */
46 | public CupcakeGestureDetector(Context context) {
47 | final ViewConfiguration configuration = ViewConfiguration.get(context);
48 | mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
49 | mTouchSlop = configuration.getScaledTouchSlop();
50 | }
51 |
52 | float getActiveX(MotionEvent ev) {
53 | return ev.getX();
54 | }
55 |
56 | float getActiveY(MotionEvent ev) {
57 | return ev.getY();
58 | }
59 |
60 | @Override
61 | public boolean onTouchEvent(MotionEvent ev) {
62 | switch (ev.getAction()) {
63 | case MotionEvent.ACTION_DOWN: {
64 | mVelocityTracker = VelocityTracker.obtain();
65 | if (null != mVelocityTracker) {
66 | mVelocityTracker.addMovement(ev);
67 | } else {
68 | Log.i(LOG_TAG, "Velocity tracker is null");
69 | }
70 |
71 | mLastTouchX = getActiveX(ev);
72 | mLastTouchY = getActiveY(ev);
73 | mIsDragging = false;
74 | break;
75 | }
76 |
77 | case MotionEvent.ACTION_MOVE: {
78 | final float x = getActiveX(ev);
79 | final float y = getActiveY(ev);
80 | final float dx = x - mLastTouchX, dy = y - mLastTouchY;
81 |
82 | if (!mIsDragging) {
83 | // Use Pythagoras to see if drag length is larger than touch slop
84 | mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
85 | }
86 |
87 | if (mIsDragging) {
88 | mListener.onDrag(dx, dy);
89 | mLastTouchX = x;
90 | mLastTouchY = y;
91 |
92 | if (null != mVelocityTracker) {
93 | mVelocityTracker.addMovement(ev);
94 | }
95 | }
96 | break;
97 | }
98 |
99 | case MotionEvent.ACTION_CANCEL: {
100 | // Recycle Velocity Tracker
101 | if (null != mVelocityTracker) {
102 | mVelocityTracker.recycle();
103 | mVelocityTracker = null;
104 | }
105 | break;
106 | }
107 |
108 | case MotionEvent.ACTION_UP: {
109 | if (mIsDragging) {
110 | if (null != mVelocityTracker) {
111 | mLastTouchX = getActiveX(ev);
112 | mLastTouchY = getActiveY(ev);
113 |
114 | // Compute velocity within the last 1000ms
115 | mVelocityTracker.addMovement(ev);
116 | mVelocityTracker.computeCurrentVelocity(1000);
117 |
118 | final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker.getYVelocity();
119 |
120 | // If the velocity is greater than minVelocity, call listener
121 | if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) {
122 | mListener.onFling(mLastTouchX, mLastTouchY, -vX, -vY);
123 | }
124 | }
125 | }
126 |
127 | // Recycle Velocity Tracker
128 | if (null != mVelocityTracker) {
129 | mVelocityTracker.recycle();
130 | mVelocityTracker = null;
131 | }
132 | break;
133 | }
134 | }
135 | return true;
136 | }
137 |
138 | public boolean isScaling() {
139 | return false;
140 | }
141 |
142 | @Override
143 | public void setOnGestureListener(OnGestureListener listener) {
144 | this.mListener = listener;
145 | }
146 | }
--------------------------------------------------------------------------------
/src/com/example/uicomponents/IMLocalImageViewFragment.java:
--------------------------------------------------------------------------------
1 | package com.example.uicomponents;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import android.content.Context;
6 | import android.graphics.Color;
7 | import android.os.Bundle;
8 | import android.support.v4.app.Fragment;
9 | import android.support.v4.app.FragmentManager;
10 | import android.support.v4.app.FragmentTransaction;
11 | import android.view.LayoutInflater;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.view.animation.AlphaAnimation;
15 | import android.view.animation.Animation;
16 | import android.view.inputmethod.InputMethodManager;
17 | import android.widget.LinearLayout;
18 | import android.widget.RelativeLayout;
19 |
20 | /**
21 | * 在当前界面弹出的图片查看的Fragment
22 | * @author 徐宁
23 | * @date: 2015-2-27 上午8:52:26
24 | */
25 | public class IMLocalImageViewFragment extends Fragment implements View.OnClickListener {
26 |
27 | private boolean mDismissed = true;
28 | private IMLocalImagePager mImageView;
29 | private List mData = new ArrayList();
30 | private ViewGroup mGroup;
31 | private View mView;
32 | /**初始化的位置*/
33 | private int mPosition;
34 | private final String TAG = "IMLocalImageView";
35 |
36 | /**
37 | * 显示视图
38 | * @param manager FragmentManager
39 | */
40 | public void show(FragmentManager manager) {
41 | if (!mDismissed) {
42 | return;
43 | }
44 |
45 | mDismissed = false;
46 |
47 | FragmentTransaction ft = manager.beginTransaction();
48 | ft.add(this, TAG);
49 | ft.addToBackStack(null);
50 | ft.commit();
51 | }
52 |
53 | /**
54 | * 隐藏视图
55 | */
56 | public void dismiss() {
57 | if (mDismissed) {
58 | return;
59 | }
60 |
61 | mDismissed = true;
62 | getFragmentManager().popBackStack();
63 | FragmentTransaction ft = getFragmentManager().beginTransaction();
64 | ft.remove(this);
65 | ft.commit();
66 | }
67 |
68 | /**
69 | * 设置数据
70 | * @param data 图片数据
71 | */
72 | public void setData(List data) {
73 | mData.clear();
74 | mData.addAll(data);
75 | if (mImageView != null) {
76 | mImageView.setImages(mData);
77 | }
78 | }
79 |
80 | @Override
81 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
82 | hideKeyboard();
83 |
84 | mView = createView();
85 |
86 | mGroup = (ViewGroup) getActivity().getWindow().getDecorView();
87 | mGroup.addView(mView);
88 | mGroup.setOnClickListener(this);
89 |
90 | mView.startAnimation(createAlphaInAnimation());
91 | setPosition(mPosition);
92 | return super.onCreateView(inflater, container, savedInstanceState);
93 | }
94 |
95 | @Override
96 | public void onDestroyView() {
97 | mView.startAnimation(createAlphaOutAnimation());
98 | mView.postDelayed(new Runnable() {
99 | @Override
100 | public void run() {
101 | mGroup.removeView(mView);
102 | }
103 | }, 100);
104 | super.onDestroyView();
105 | }
106 |
107 | private View createView() {
108 |
109 | RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
110 | RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
111 | RelativeLayout panel = new RelativeLayout(getActivity());
112 | panel.setLayoutParams(params);
113 |
114 | View background = new View(getActivity());
115 | background.setBackgroundColor(Color.rgb(0, 0, 0));
116 | background.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
117 | LinearLayout.LayoutParams.MATCH_PARENT));
118 |
119 | RelativeLayout.LayoutParams ImageViewParams = new RelativeLayout.LayoutParams(
120 | RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
121 | ImageViewParams.addRule(RelativeLayout.CENTER_IN_PARENT);
122 | mImageView = new IMLocalImagePager(getActivity());
123 | mImageView.setLayoutParams(ImageViewParams);
124 | if (mData != null) {
125 | mImageView.setImages(mData);
126 | }
127 | mImageView.setOnClickListener(this);
128 |
129 | panel.addView(background);
130 | panel.addView(mImageView);
131 |
132 | return panel;
133 | }
134 |
135 |
136 | /**
137 | * 隐藏键盘
138 | * @author 徐宁
139 | */
140 | private void hideKeyboard() {
141 | InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
142 | if (imm.isActive()) {
143 | View focusView = getActivity().getCurrentFocus();
144 | if (focusView != null) {
145 | imm.hideSoftInputFromWindow(focusView.getWindowToken(), 0);
146 | }
147 | }
148 | }
149 |
150 | private Animation createAlphaInAnimation() {
151 | AlphaAnimation an = new AlphaAnimation(0, 1);
152 | an.setDuration(300);
153 | return an;
154 | }
155 |
156 | private Animation createAlphaOutAnimation() {
157 | AlphaAnimation an = new AlphaAnimation(1, 0);
158 | an.setDuration(300);
159 | an.setFillAfter(true);
160 | return an;
161 | }
162 |
163 | @Override
164 | public void onClick(View v) {
165 | dismiss();
166 | }
167 |
168 | public void setPosition(int position){
169 |
170 | if(mImageView == null){
171 |
172 | mImageView = new IMLocalImagePager(getActivity());
173 | }
174 | mImageView.setImagePosition(position);
175 | }
176 |
177 | public void setmPosition(int mPosition) {
178 | this.mPosition = mPosition;
179 | }
180 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/imselectpicture/IMSelectPictureGridAdapter.java:
--------------------------------------------------------------------------------
1 | package com.wuba.bangbang.uicomponents.imselectpicture;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import android.app.Activity;
7 | import android.content.Context;
8 | import android.text.TextUtils;
9 | import android.util.DisplayMetrics;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.View.OnClickListener;
13 | import android.view.ViewGroup;
14 | import android.widget.BaseAdapter;
15 |
16 | import com.example.android_select_picture_module.R;
17 | import com.example.uicomponents.IMImageView;
18 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
19 | import com.nostra13.universalimageloader.core.ImageLoader;
20 | import com.wuba.bangbang.uicomponents.utils.ImageLoaderUtils;
21 |
22 | /**
23 | * 选择本地图片的adapter
24 | */
25 | public class IMSelectPictureGridAdapter extends BaseAdapter implements OnClickListener {
26 |
27 | private Context mContext;
28 | /**全部的图片*/
29 | private List dataList;
30 | /**已选择的图片*/
31 | private List mSelectedDataList;
32 | private DisplayMetrics dm;
33 | private DisplayImageOptions mOption;
34 | private OnItemClickListener mOnItemClickListener;
35 |
36 |
37 | public IMSelectPictureGridAdapter(Context c, List dataList, List selectedDataList) {
38 |
39 | mContext = c;
40 | this.dataList = dataList;
41 | this.mSelectedDataList = selectedDataList;
42 | dm = new DisplayMetrics();
43 | ((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm);
44 | mOption = ImageLoaderUtils.getAllImagesOptions();
45 | }
46 |
47 | public void notifyDataSetChanged(ArrayList subDataList){
48 |
49 | this.dataList = subDataList;
50 | notifyDataSetChanged();
51 | }
52 |
53 | @Override
54 | public int getCount() {
55 |
56 | return dataList.size();
57 | }
58 |
59 | @Override
60 | public Object getItem(int position) {
61 |
62 | return dataList.get(position).path;
63 | }
64 |
65 | @Override
66 | public long getItemId(int position) {
67 |
68 | return position;
69 | }
70 |
71 | private class ViewHolder {
72 |
73 | public IMImageView imageView, check;
74 | }
75 |
76 | @Override
77 | public View getView(int position, View convertView, ViewGroup parent) {
78 |
79 | ViewHolder viewHolder;
80 | if (convertView == null) {
81 |
82 | viewHolder = new ViewHolder();
83 | convertView = LayoutInflater.from(mContext).inflate(R.layout.item_select_picture_grid, parent, false);
84 | viewHolder.imageView = (IMImageView) convertView.findViewById(R.id.select_picture_grid_item_image);
85 | viewHolder.check = (IMImageView) convertView.findViewById(R.id.select_picture_grid_item_check);
86 | convertView.setTag(viewHolder);
87 | } else {
88 |
89 | viewHolder = (ViewHolder) convertView.getTag();
90 | }
91 | viewHolder.imageView.setImageResource(R.drawable.default_picture);
92 | String path = "file://" + dataList.get(position).getPath();
93 | ImageLoader.getInstance().displayImage(path, viewHolder.imageView, mOption);
94 | viewHolder.check.setTag(position);
95 | if (isInSelectedDataList(dataList.get(position).path)) {
96 |
97 | viewHolder.check.setVisibility(View.VISIBLE);
98 | } else {
99 |
100 | viewHolder.check.setVisibility(View.GONE);
101 | }
102 | convertView.setOnClickListener(this);
103 | return convertView;
104 | }
105 |
106 | /**
107 | * 判断图片是否选择
108 | * @param selectedString
109 | * @return
110 | */
111 | private boolean isInSelectedDataList(String selectedString) {
112 |
113 | if(mSelectedDataList != null && mSelectedDataList.size() > 0 && !TextUtils.isEmpty(selectedString)){
114 |
115 | for (int i = 0; i < mSelectedDataList.size(); i++) {
116 |
117 | if (mSelectedDataList.get(i).equals(selectedString)) {
118 |
119 | return true;
120 | }
121 | }
122 | }
123 | return false;
124 | }
125 |
126 | @Override
127 | public void onClick(View view) {
128 | ViewHolder viewHolder = (ViewHolder) view.getTag();
129 |
130 | if (viewHolder == null) {
131 | return;
132 | }
133 |
134 | int position = (Integer) viewHolder.check.getTag();
135 | if (viewHolder.check.getVisibility() == View.VISIBLE) {
136 | if (mOnItemClickListener.onItemClick(position, dataList.get(position).path, false)) {
137 | viewHolder.check.setVisibility(View.GONE);
138 | }
139 | } else {
140 | if (mOnItemClickListener.onItemClick(position, dataList.get(position).path, true)) {
141 | viewHolder.check.setVisibility(View.VISIBLE);
142 | }
143 | }
144 | }
145 |
146 | public void setOnItemClickListener(OnItemClickListener l) {
147 |
148 | mOnItemClickListener = l;
149 | }
150 |
151 | /**
152 | * 单击某一项的监听
153 | */
154 | public interface OnItemClickListener {
155 |
156 | /**
157 | * 单击某一个item
158 | * @author 徐宁
159 | * @param position item的位置
160 | * @param path 显示图片的路径
161 | * @param isSelected 图片是否已选中
162 | * @return
163 | */
164 | public boolean onItemClick(int position, String path, boolean isSelected);
165 | }
166 |
167 | /**
168 | * @return the mSelectedDataList
169 | */
170 | public List getmSelectedDataList() {
171 | return mSelectedDataList;
172 | }
173 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/pulltorefresh/internal/IndicatorLayout.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.pulltorefresh.internal;
17 |
18 | import android.annotation.SuppressLint;
19 | import android.content.Context;
20 | import android.graphics.Matrix;
21 | import android.graphics.drawable.Drawable;
22 | import android.view.View;
23 | import android.view.animation.Animation;
24 | import android.view.animation.Animation.AnimationListener;
25 | import android.view.animation.AnimationUtils;
26 | import android.view.animation.Interpolator;
27 | import android.view.animation.LinearInterpolator;
28 | import android.view.animation.RotateAnimation;
29 | import android.widget.FrameLayout;
30 | import android.widget.ImageView;
31 | import android.widget.ImageView.ScaleType;
32 |
33 | import com.example.android_select_picture_module.R;
34 | import com.wuba.bangbang.uicomponents.pulltorefresh.PullToRefreshBase;
35 |
36 | @SuppressLint("ViewConstructor")
37 | public class IndicatorLayout extends FrameLayout implements AnimationListener {
38 |
39 | static final int DEFAULT_ROTATION_ANIMATION_DURATION = 150;
40 |
41 | private Animation mInAnim, mOutAnim;
42 | private ImageView mArrowImageView;
43 |
44 | private final Animation mRotateAnimation, mResetRotateAnimation;
45 |
46 | public IndicatorLayout(Context context, PullToRefreshBase.Mode mode) {
47 | super(context);
48 | mArrowImageView = new ImageView(context);
49 |
50 | Drawable arrowD = getResources().getDrawable(R.drawable.pull_to_refresh_icon);
51 | mArrowImageView.setImageDrawable(arrowD);
52 |
53 | final int padding = getResources().getDimensionPixelSize(
54 | R.dimen.normal_padding);
55 | mArrowImageView.setPadding(padding, padding, padding, padding);
56 | addView(mArrowImageView);
57 |
58 | int inAnimResId, outAnimResId;
59 | switch (mode) {
60 | case PULL_FROM_END:
61 | inAnimResId = R.anim.pull_to_refresh_slide_in_from_bottom;
62 | outAnimResId = R.anim.pull_to_refresh_slide_out_to_bottom;
63 | // setBackgroundResource(R.drawable.indicator_bg_bottom);
64 |
65 | // Rotate Arrow so it's pointing the correct way
66 | mArrowImageView.setScaleType(ScaleType.MATRIX);
67 | Matrix matrix = new Matrix();
68 | matrix.setRotate(180f, arrowD.getIntrinsicWidth() / 2f,
69 | arrowD.getIntrinsicHeight() / 2f);
70 | mArrowImageView.setImageMatrix(matrix);
71 | break;
72 | default:
73 | case PULL_FROM_START:
74 | inAnimResId = R.anim.pull_to_refresh_slide_in_from_top;
75 | outAnimResId = R.anim.pull_to_refresh_slide_out_to_top;
76 | // setBackgroundResource(R.drawable.indicator_bg_top);
77 | break;
78 | }
79 |
80 | mInAnim = AnimationUtils.loadAnimation(context, inAnimResId);
81 | mInAnim.setAnimationListener(this);
82 |
83 | mOutAnim = AnimationUtils.loadAnimation(context, outAnimResId);
84 | mOutAnim.setAnimationListener(this);
85 |
86 | final Interpolator interpolator = new LinearInterpolator();
87 | mRotateAnimation = new RotateAnimation(0, -180,
88 | Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
89 | 0.5f);
90 | mRotateAnimation.setInterpolator(interpolator);
91 | mRotateAnimation.setDuration(DEFAULT_ROTATION_ANIMATION_DURATION);
92 | mRotateAnimation.setFillAfter(true);
93 |
94 | mResetRotateAnimation = new RotateAnimation(-180, 0,
95 | Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
96 | 0.5f);
97 | mResetRotateAnimation.setInterpolator(interpolator);
98 | mResetRotateAnimation.setDuration(DEFAULT_ROTATION_ANIMATION_DURATION);
99 | mResetRotateAnimation.setFillAfter(true);
100 |
101 | }
102 |
103 | public final boolean isVisible() {
104 | Animation currentAnim = getAnimation();
105 | if (null != currentAnim) {
106 | return mInAnim == currentAnim;
107 | }
108 |
109 | return getVisibility() == View.VISIBLE;
110 | }
111 |
112 | public void hide() {
113 | startAnimation(mOutAnim);
114 | }
115 |
116 | public void show() {
117 | mArrowImageView.clearAnimation();
118 | startAnimation(mInAnim);
119 | }
120 |
121 | @Override
122 | public void onAnimationEnd(Animation animation) {
123 | if (animation == mOutAnim) {
124 | mArrowImageView.clearAnimation();
125 | setVisibility(View.GONE);
126 | } else if (animation == mInAnim) {
127 | setVisibility(View.VISIBLE);
128 | }
129 |
130 | clearAnimation();
131 | }
132 |
133 | @Override
134 | public void onAnimationRepeat(Animation animation) {
135 | // NO-OP
136 | }
137 |
138 | @Override
139 | public void onAnimationStart(Animation animation) {
140 | setVisibility(View.VISIBLE);
141 | }
142 |
143 | public void releaseToRefresh() {
144 | mArrowImageView.startAnimation(mRotateAnimation);
145 | }
146 |
147 | public void pullToRefresh() {
148 | mArrowImageView.startAnimation(mResetRotateAnimation);
149 | }
150 |
151 | }
152 |
--------------------------------------------------------------------------------
/res/values/vpi__attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/utils/ImageLoaderUtils.java:
--------------------------------------------------------------------------------
1 | /**
2 | * @project: 58bangbang
3 | * @file: ImageLoaderUtils.java
4 | * @date: 2014-10-22 上午9:50:43
5 | * @copyright: 2014 58.com Inc. All rights reserved.
6 | */
7 | package com.wuba.bangbang.uicomponents.utils;
8 |
9 | import android.content.Context;
10 | import android.graphics.Bitmap;
11 | import android.widget.ListView;
12 |
13 | import com.example.android_select_picture_module.R;
14 | import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
15 | import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache;
16 | import com.nostra13.universalimageloader.cache.memory.impl.WeakMemoryCache;
17 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
18 | import com.nostra13.universalimageloader.core.ImageLoader;
19 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
20 | import com.nostra13.universalimageloader.core.assist.ImageScaleType;
21 | import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
22 | import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
23 | import com.nostra13.universalimageloader.core.listener.PauseOnScrollListener;
24 |
25 | /**
26 | * IamgeLaoder设置相应属性的工具类
27 | * @author Jack
28 | * @version 创建时间:2014-10-22 上午9:50:43
29 | */
30 | public class ImageLoaderUtils {
31 |
32 | /**
33 | * 初始化ImageLoader(需要在应用入口调用 )
34 | */
35 | public static void init(Context context) {
36 | if (ImageLoader.getInstance().isInited()) {
37 | return;
38 | }
39 | ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
40 | .threadPriority(Thread.NORM_PRIORITY - 2)
41 | .denyCacheImageMultipleSizesInMemory()
42 | .diskCacheFileNameGenerator(new Md5FileNameGenerator())
43 | .memoryCache(new WeakMemoryCache()) //防止内存OOM
44 | .memoryCacheSize(4 * 1024 * 1024)
45 | .diskCacheSize(50 * 1024 * 1024) // 50 Mb
46 | .tasksProcessingOrder(QueueProcessingType.LIFO)
47 | .writeDebugLogs() // Remove for release app
48 | .build();
49 | ImageLoader.getInstance().init(config); // Initialize ImageLoader with configuration.
50 | }
51 |
52 | /**
53 | * 在Activity的onStop阶段停止加载图片
54 | */
55 | public static void stopLoadPic(){
56 |
57 | ImageLoader.getInstance().stop();
58 | }
59 |
60 |
61 | /**
62 | * 清除ImageLoader的缓存
63 | */
64 | public static void clearImageCache() {
65 |
66 | ImageLoader.getInstance().clearDiskCache();
67 | ImageLoader.getInstance().clearMemoryCache();
68 | }
69 |
70 | // TODO 根据自己的图片加载业务情况自定义不同的DisplayImageOptions
71 |
72 | /**
73 | * 获得默认图片的加载options
74 | *
75 | * @return
76 | */
77 | @SuppressWarnings("deprecation")
78 | public static DisplayImageOptions getDefaultOptions() {
79 | DisplayImageOptions options = new DisplayImageOptions.Builder()
80 | .cacheInMemory(true).cacheOnDisk(true)
81 | .resetViewBeforeLoading(true)
82 | .displayer(new FadeInBitmapDisplayer(300))
83 | .bitmapConfig(Bitmap.Config.ARGB_8888)
84 | .imageScaleType(ImageScaleType.EXACTLY)
85 | .showImageForEmptyUri(R.drawable.default_picture)
86 | .showImageOnFail(R.drawable.default_picture)
87 | .showStubImage(R.drawable.default_picture).build();
88 |
89 | return options;
90 | }
91 |
92 |
93 | /**
94 | * 在快滑的时候停止listview中的item使用ImageLoader的实例加载图片
95 | * @param listView
96 | */
97 | public static void setPauseLoadingImageOnFly(ListView listView) {
98 |
99 | boolean pauseOnScroll = false; // scroll时加载
100 | boolean pauseOnFling = true; // fly时不加载
101 | PauseOnScrollListener listener = new PauseOnScrollListener(
102 | ImageLoader.getInstance(), pauseOnScroll, pauseOnFling);
103 | listView.setOnScrollListener(listener);
104 | }
105 |
106 | public static DisplayImageOptions getCarDetailOptions() {
107 | DisplayImageOptions options = new DisplayImageOptions.Builder()
108 | .showImageForEmptyUri(R.drawable.default_picture)
109 | .showImageOnFail(R.drawable.default_picture)
110 | .resetViewBeforeLoading(true).cacheOnDisk(true)
111 | .cacheInMemory(true)
112 | .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
113 | .bitmapConfig(Bitmap.Config.RGB_565)
114 | .displayer(new FadeInBitmapDisplayer(300)).build();
115 | return options;
116 | }
117 |
118 | /**
119 | * 从相册多选图options
120 | * @return
121 | * @author 牟沛文
122 | */
123 | public static DisplayImageOptions getAllImagesOptions() {
124 | DisplayImageOptions options = new DisplayImageOptions.Builder()
125 | .considerExifParams(true)
126 | .cacheInMemory(true)
127 | .cacheOnDisk(false)
128 | .resetViewBeforeLoading(true)
129 | .bitmapConfig(Bitmap.Config.RGB_565)
130 | .imageScaleType(ImageScaleType.EXACTLY)
131 | .showImageForEmptyUri(R.drawable.default_picture)
132 | .showImageOnFail(R.drawable.default_picture)
133 | .showStubImage(R.drawable.default_picture)
134 | .build();
135 |
136 | return options;
137 | }
138 |
139 |
140 | /**
141 | * 默认的configure,注意和bangbang保持一致
142 | * @param context
143 | * @return
144 | */
145 | public static ImageLoaderConfiguration getDefaultConfigure(Context context) {
146 | ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
147 | .threadPriority(Thread.NORM_PRIORITY - 2)
148 | .denyCacheImageMultipleSizesInMemory()
149 | .diskCacheFileNameGenerator(new Md5FileNameGenerator())
150 | .memoryCache(new WeakMemoryCache()) //防止内存OOM
151 | .memoryCacheSize(4 * 1024 * 1024)
152 | .diskCacheSize(50 * 1024 * 1024) // 50 Mb
153 | .tasksProcessingOrder(QueueProcessingType.LIFO)
154 | .writeDebugLogs() // Remove for release app
155 | .build();
156 | return config;
157 | }
158 |
159 | /**
160 | * 从相册选图configure
161 | * @return
162 | */
163 | public static ImageLoaderConfiguration getAllImagesConfigure(Context context) {
164 | ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
165 | .threadPriority(Thread.NORM_PRIORITY - 2)
166 | .denyCacheImageMultipleSizesInMemory()
167 | .memoryCache(new LRULimitedMemoryCache(4 * 1024 * 1024))
168 | .diskCacheFileNameGenerator(new Md5FileNameGenerator())
169 | .memoryCacheExtraOptions(200, 200)
170 | .memoryCacheSize(4 * 1024 * 1024)
171 | .tasksProcessingOrder(QueueProcessingType.FIFO)
172 | .writeDebugLogs() // Remove for release app
173 | .build();
174 | return config;
175 | }
176 | }
--------------------------------------------------------------------------------
/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
--------------------------------------------------------------------------------
/src/com/example/uicomponents/IMLocalImagePager.java:
--------------------------------------------------------------------------------
1 | /**
2 | * @project: 58bangbang
3 | * @file: IMLocalImagePager.java
4 | * @date: 2014年10月23日 上午11:23:54
5 | * @copyright: 2014 58.com Inc. All rights reserved.
6 | */
7 | package com.example.uicomponents;
8 |
9 | import java.util.List;
10 |
11 | import android.content.Context;
12 | import android.os.Parcelable;
13 | import android.support.v4.view.PagerAdapter;
14 | import android.support.v4.view.ViewPager;
15 | import android.util.AttributeSet;
16 | import android.view.LayoutInflater;
17 | import android.view.View;
18 | import android.view.ViewGroup;
19 | import android.widget.FrameLayout;
20 | import android.widget.ProgressBar;
21 | import android.widget.Toast;
22 |
23 | import com.example.android_select_picture_module.R;
24 | import com.nostra13.universalimageloader.core.ImageLoader;
25 | import com.wuba.bangbang.uicomponents.photoview.PhotoViewAttacher;
26 | import com.wuba.bangbang.uicomponents.utils.ImageLoaderUtils;
27 | import com.wuba.bangbang.uicomponents.viewpagerindicator.CirclePageIndicator;
28 | import com.wuba.bangbang.uicomponents.viewpagerindicator.HackyViewPager;
29 | import com.wuba.bangbang.uicomponents.viewpagerindicator.PageIndicator;
30 |
31 | /**
32 | * 本地图片浏览器。依赖开源项目PhotoView、ViewPagerIndicator。
33 | * @author Jack
34 | */
35 | public class IMLocalImagePager extends FrameLayout {
36 |
37 | /** 支持滑块的ViewPager */
38 | private HackyViewPager mHackyViewPager;
39 | /** ViewPager适配器 */
40 | private ImagePagerAdapter mPageAdapter;
41 | private LayoutInflater mInflater;
42 | /** 显示图片的数据源 */
43 | private List images;
44 | /** 点击事件的回调函数 */
45 | private OnClickListener mOnClickListener;
46 |
47 | /**
48 | * Creates a new instance of IMImagePager.
49 | * @param context
50 | */
51 | public IMLocalImagePager(Context context) {
52 | this(context, null);
53 | }
54 |
55 | /**
56 | * Creates a new instance of IMImagePager.
57 | * @param context
58 | * @param attrs
59 | * @param defStyleAttr
60 | */
61 | public IMLocalImagePager(Context context, AttributeSet attrs, int defStyleAttr) {
62 | super(context, attrs, defStyleAttr);
63 | }
64 |
65 | /**
66 | * Creates a new instance of IMImagePager.
67 | * @param context
68 | * @param attrs
69 | */
70 | public IMLocalImagePager(Context context, AttributeSet attrs) {
71 |
72 | super(context, attrs);
73 | mInflater = LayoutInflater.from(context);
74 | mInflater.inflate(R.layout.common_im_image_pager, this);
75 |
76 | //ViewPager
77 | mHackyViewPager = (HackyViewPager) findViewById(R.id.common_im_image_pager_viewpager);
78 | mPageAdapter = new ImagePagerAdapter(context);
79 | mHackyViewPager.setAdapter(mPageAdapter);
80 | mHackyViewPager.setCurrentItem(0);
81 | //导航滑块设置
82 | PageIndicator indicator = (CirclePageIndicator) findViewById(R.id.common_im_image_pager_indicator);
83 | indicator.setViewPager(mHackyViewPager);
84 | }
85 |
86 | /**
87 | * 添加图片点击处理
88 | * 注意:这里会造成循环引用,需要在上级destory时删除
89 | */
90 | @Override
91 | public void setOnClickListener(OnClickListener l) {
92 |
93 | mOnClickListener = l;
94 | }
95 |
96 | /**
97 | * 设置图片数据源,会触发重新渲染
98 | * @param images
99 | */
100 | public void setImages(List images) {
101 |
102 | this.images = images;
103 | if (mPageAdapter != null) {
104 |
105 | mPageAdapter.update(images);
106 | }
107 | }
108 |
109 | /**
110 | * 设置当前滚动到的位置
111 | * @param position
112 | * @author lijc setImagePosition:(这里用一句话描述这个方法的作用).
113 | */
114 | public void setImagePosition(int position) {
115 |
116 | if (mHackyViewPager != null && images != null && images.size() > position) {
117 |
118 | mHackyViewPager.setCurrentItem(position);
119 | }
120 | }
121 |
122 | /**
123 | * ViewPager适配器
124 | */
125 | private class ImagePagerAdapter extends PagerAdapter {
126 |
127 | /** 数据源 */
128 | private List mImages;
129 | private Context mContext;
130 |
131 | ImagePagerAdapter(Context context) {
132 | this.mContext = context;
133 | }
134 |
135 | @Override
136 | public void destroyItem(ViewGroup container, int position, Object object) {
137 | ((ViewPager) container).removeView((View) object);
138 | }
139 |
140 | @Override
141 | public void finishUpdate(View container) {
142 | }
143 |
144 | @Override
145 | public int getCount() {
146 | if (mImages != null) {
147 | return mImages.size();
148 | } else {
149 | return 0;
150 | }
151 | }
152 |
153 | @Override
154 | public Object instantiateItem(ViewGroup view, int position) {
155 | View imageLayout = mInflater.inflate(R.layout.common_im_image_pager_item, view, false);
156 |
157 | IMPhotoView imageView = (IMPhotoView) imageLayout.findViewById(R.id.common_im_image_pager_item_photoview);
158 | //点击事件的响应
159 | if (mOnClickListener != null) {
160 | imageView.setOnViewTapListener(new PhotoViewAttacher.OnViewTapListener() {
161 |
162 | @Override
163 | public void onViewTap(View view, float x, float y) {
164 | if (mOnClickListener != null) {
165 | mOnClickListener.onClick(view);
166 | }
167 | }
168 | });
169 | }
170 |
171 | final ProgressBar spinner = (ProgressBar) imageLayout.findViewById(R.id.common_im_image_pager_item_loading);
172 | spinner.setVisibility(View.GONE);
173 | try {
174 |
175 | String url = mImages.get(position);
176 | String[] temp = url.split("/");
177 |
178 | if(temp != null && temp.length > 0 && !temp[temp.length - 1].contains(".")){ //加载手机拍摄的图片
179 |
180 | url = "content://media/" + url;
181 | }else{
182 |
183 | if(mImages.get(position).startsWith("http://")){ //加载网络图片,防止过大造成OOM
184 |
185 | url = mImages.get(position);
186 | url = url.replace("//tiny//", "//big//");
187 | }else{ //加载本地相册的图片
188 |
189 | url = "file://" + url;
190 | }
191 | }
192 | ImageLoader.getInstance().displayImage(url, imageView, ImageLoaderUtils.getDefaultOptions());
193 | } catch (Exception e) {
194 | e.printStackTrace();
195 | String message = "图片加载失败";
196 | Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
197 | }
198 | ((ViewPager) view).addView(imageLayout, 0);
199 | return imageLayout;
200 | }
201 |
202 | @Override
203 | public boolean isViewFromObject(View view, Object object) {
204 | return view.equals(object);
205 | }
206 |
207 | @Override
208 | public void restoreState(Parcelable state, ClassLoader loader) {
209 | }
210 |
211 | @Override
212 | public Parcelable saveState() {
213 | return null;
214 | }
215 |
216 | @Override
217 | public void startUpdate(View container) {
218 | }
219 |
220 | /**
221 | * 更新列表
222 | * @param images 数据源
223 | */
224 | public void update(List images) {
225 | this.mImages = images;
226 | this.notifyDataSetChanged();
227 | }
228 | }
229 |
230 | public List getImages() {
231 | return images;
232 | }
233 | }
--------------------------------------------------------------------------------
/src/com/example/android_select_picture_module/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.android_select_picture_module;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.ArrayList;
5 | import java.util.Date;
6 | import java.util.List;
7 | import java.util.Locale;
8 |
9 | import android.app.Activity;
10 | import android.content.ContentValues;
11 | import android.content.Intent;
12 | import android.net.Uri;
13 | import android.os.Bundle;
14 | import android.provider.MediaStore;
15 | import android.provider.MediaStore.Images.Media;
16 | import android.support.v4.app.Fragment;
17 | import android.support.v4.app.FragmentActivity;
18 | import android.text.TextUtils;
19 | import android.view.View;
20 |
21 | import com.example.uicomponents.IMImageView;
22 | import com.example.uicomponents.IMLocalImageViewFragment;
23 | import com.wuba.bangbang.uicomponents.acitonsheet.ActionSheet;
24 | import com.wuba.bangbang.uicomponents.acitonsheet.IActionSheetListener;
25 | import com.wuba.bangbang.uicomponents.imselectpicture.IMSelectPictureActivity;
26 | import com.wuba.bangbang.uicomponents.imselectpicture.IMSelectPictureView;
27 |
28 |
29 | public class MainActivity extends FragmentActivity implements IActionSheetListener{
30 |
31 | /**提示框显示的内容*/
32 | private String[] mActionSheetTitle;
33 | /**显示图片的控件*/
34 | private IMSelectPictureView mSelectPictureView;
35 | /**已选择的图片路径集合*/
36 | private ArrayList mPicRawPath; //TODO 拿到图片名称列表后可以进行操作
37 | /**拍照、选择本地图片的标识*/
38 | private final int TAKE_PICTURE = 0X1, FROM_LOCAL = 0X2;
39 | /**拍摄照片后添加到的位置*/
40 | private final int TAKE_PICTURE_POSITION = 0;
41 | /**可以选择的最大照片数*/
42 | private final int MAX_COUNT = 12; //TODO 设置还可以选择的照片个数
43 | /**拍摄照片的路径uri*/
44 | private Uri mPhotoUri;
45 | private final String DATALIST = "dataList", SELECTDATA = "selectdata", SIZE = "size";
46 |
47 |
48 |
49 | @Override
50 | protected void onCreate(Bundle savedInstanceState) {
51 |
52 | super.onCreate(savedInstanceState);
53 | setContentView(R.layout.activity_main);
54 |
55 | mSelectPictureView = (IMSelectPictureView)findViewById(R.id.selectPictureView);
56 | mSelectPictureView.setFragmentManager(getSupportFragmentManager());
57 | mSelectPictureView.setMaxPictureCount(MAX_COUNT);
58 | mSelectPictureView.setListener(new IMSelectPictureView.ISelectPictureListener() {
59 |
60 | @Override
61 | public void onSelectPicture() {
62 |
63 | Intent intent = new Intent(MainActivity.this, IMSelectPictureActivity.class);
64 | Bundle bundle = new Bundle();
65 | bundle.putStringArrayList(DATALIST, new ArrayList());
66 | bundle.putStringArrayList(SELECTDATA, mSelectPictureView.getPictureData()); //传递已选择的照片
67 | bundle.putInt(SIZE, MAX_COUNT);
68 | intent.putExtras(bundle);
69 | startActivityForResult(intent, FROM_LOCAL);
70 | }
71 |
72 | @Override
73 | public void onClickTackPicture() { //单击拍照后生成指定文件名的图片,针对返回的data为空。
74 |
75 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
76 | SimpleDateFormat timeStampFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss", Locale.CHINA);
77 | String filename = timeStampFormat.format(new Date());
78 | ContentValues values = new ContentValues();
79 | values.put(Media.TITLE, filename);
80 | mPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
81 | intent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoUri);
82 | startActivityForResult(intent, TAKE_PICTURE);
83 | }
84 |
85 | @Override
86 | public void onClickPicture(List pictures, IMImageView imageView) {
87 |
88 | IMLocalImageViewFragment myView = new IMLocalImageViewFragment();
89 | myView.setData(pictures);
90 | String url = imageView.getUrl();
91 | int position = 0;
92 | position = mSelectPictureView.getPosition(url, pictures);
93 | myView.setmPosition(position);
94 | myView.show(getSupportFragmentManager());
95 | }
96 | });
97 |
98 |
99 | mActionSheetTitle = new String[]{getString(R.string.take_photo), getString(R.string.upload_from_album)};
100 |
101 | findViewById(R.id.textView).setOnClickListener(new View.OnClickListener() {
102 |
103 | @Override
104 | public void onClick(View arg0) {
105 |
106 | ActionSheet.createBuilder(MainActivity.this, getSupportFragmentManager())
107 | .setCancelButtonTitle(R.string.cancel)
108 | .setOtherButtonTitles(mActionSheetTitle)
109 | .setCancelableOnTouchOutside(true)
110 | .setListener(MainActivity.this)
111 | .show();
112 | }
113 | });
114 | }
115 |
116 | /**
117 | * @see com.wuba.bangbang.uicomponents.acitonsheet.IActionSheetListener#onOtherButtonClick(android.support.v4.app.Fragment, int)
118 | * @param actionSheet
119 | * @param index
120 | */
121 | @Override
122 | public void onOtherButtonClick(Fragment actionSheet, int index) {
123 |
124 | String title = mActionSheetTitle[index];
125 | if(TextUtils.equals(title, getString(R.string.take_photo))){ //拍照片
126 |
127 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
128 | SimpleDateFormat timeStampFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss", Locale.CHINA);
129 | String filename = timeStampFormat.format(new Date());
130 | ContentValues values = new ContentValues();
131 | values.put(Media.TITLE, filename);
132 | mPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
133 | intent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoUri);
134 | startActivityForResult(intent, TAKE_PICTURE);
135 | }else{ //从相册选图
136 |
137 | Intent intent = new Intent(MainActivity.this, IMSelectPictureActivity.class);
138 | Bundle bundle = new Bundle();
139 | bundle.putStringArrayList("dataList", new ArrayList());
140 | bundle.putStringArrayList("selectdata", mSelectPictureView.getPictureData()); //传递已选择的照片
141 | bundle.putInt("size", MAX_COUNT); //设置还可以选择的照片个数
142 | intent.putExtras(bundle);
143 | startActivityForResult(intent, FROM_LOCAL);
144 | }
145 | }
146 |
147 | /**
148 | * @see android.support.v4.app.FragmentActivity#onActivityResult(int, int, android.content.Intent)
149 | * @param arg0
150 | * @param arg1
151 | * @param arg2
152 | */
153 | @Override
154 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
155 | super.onActivityResult(requestCode, resultCode, data);
156 | if (resultCode == Activity.RESULT_OK) {
157 | if(data != null){ //选择图片完成后返回
158 |
159 | Bundle bundle = data.getExtras();
160 | mPicRawPath = bundle.getStringArrayList("dataList");
161 | if(mSelectPictureView.getMaxPictureCount() > mPicRawPath.size()) {
162 | mPicRawPath.add(TAKE_PICTURE_POSITION, IMSelectPictureView.DEFAULT_TAG);
163 | }
164 | mSelectPictureView.addPictureData(mPicRawPath, true);
165 | }else if(data == null && mPhotoUri != null){ //拍照片
166 |
167 | if(mPicRawPath == null){
168 |
169 | mPicRawPath = new ArrayList();
170 | }
171 | if(mPicRawPath.size() > 0){
172 |
173 | mPicRawPath.remove(TAKE_PICTURE_POSITION);
174 | }
175 | mPicRawPath.add(0, mPhotoUri.getPath());
176 | mSelectPictureView.addPictureData(mPicRawPath, true);
177 | }
178 | }
179 | }
180 |
181 | @Override
182 | public void onDismiss(Fragment actionSheet, boolean isCancel) {
183 | }
184 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/photoview/PhotoView.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.photoview;
17 |
18 | import android.content.Context;
19 | import android.graphics.Bitmap;
20 | import android.graphics.Matrix;
21 | import android.graphics.RectF;
22 | import android.graphics.drawable.Drawable;
23 | import android.net.Uri;
24 | import android.util.AttributeSet;
25 | import android.view.GestureDetector;
26 | import android.widget.ImageView;
27 |
28 | import com.wuba.bangbang.uicomponents.photoview.PhotoViewAttacher.OnMatrixChangedListener;
29 | import com.wuba.bangbang.uicomponents.photoview.PhotoViewAttacher.OnPhotoTapListener;
30 | import com.wuba.bangbang.uicomponents.photoview.PhotoViewAttacher.OnViewTapListener;
31 |
32 | /**
33 | * 支持手势缩放的ImageView
34 | * 图片浏览器,继承自开源项目PhotoView
35 | * https://github.com/chrisbanes/PhotoView
36 | * @author 徐宁
37 | * @date: 2015-2-27 下午1:20:47
38 | */
39 | public class PhotoView extends ImageView implements IPhotoView {
40 |
41 | private final PhotoViewAttacher mAttacher;
42 | private ScaleType mPendingScaleType;
43 |
44 | public PhotoView(Context context) {
45 | this(context, null);
46 | }
47 |
48 | public PhotoView(Context context, AttributeSet attr) {
49 | this(context, attr, 0);
50 | }
51 |
52 | public PhotoView(Context context, AttributeSet attr, int defStyle) {
53 |
54 | super(context, attr, defStyle);
55 | super.setScaleType(ScaleType.MATRIX);
56 | mAttacher = new PhotoViewAttacher(this);
57 | if (null != mPendingScaleType) {
58 | setScaleType(mPendingScaleType);
59 | mPendingScaleType = null;
60 | }
61 | }
62 |
63 | /**
64 | * @deprecated use {@link #setRotationTo(float)}
65 | */
66 | @Override
67 | public void setPhotoViewRotation(float rotationDegree) {
68 | mAttacher.setRotationTo(rotationDegree);
69 | }
70 |
71 | @Override
72 | public void setRotationTo(float rotationDegree) {
73 | mAttacher.setRotationTo(rotationDegree);
74 | }
75 |
76 | @Override
77 | public void setRotationBy(float rotationDegree) {
78 | mAttacher.setRotationBy(rotationDegree);
79 | }
80 |
81 | @Override
82 | public boolean canZoom() {
83 | return mAttacher.canZoom();
84 | }
85 |
86 | @Override
87 | public RectF getDisplayRect() {
88 | return mAttacher.getDisplayRect();
89 | }
90 |
91 | @Override
92 | public Matrix getDisplayMatrix() {
93 | return mAttacher.getDrawMatrix();
94 | }
95 |
96 | @Override
97 | public boolean setDisplayMatrix(Matrix finalRectangle) {
98 | return mAttacher.setDisplayMatrix(finalRectangle);
99 | }
100 |
101 | @Override
102 | @Deprecated
103 | public float getMinScale() {
104 | return getMinimumScale();
105 | }
106 |
107 | @Override
108 | public float getMinimumScale() {
109 | return mAttacher.getMinimumScale();
110 | }
111 |
112 | @Override
113 | @Deprecated
114 | public float getMidScale() {
115 | return getMediumScale();
116 | }
117 |
118 | @Override
119 | public float getMediumScale() {
120 | return mAttacher.getMediumScale();
121 | }
122 |
123 | @Override
124 | @Deprecated
125 | public float getMaxScale() {
126 | return getMaximumScale();
127 | }
128 |
129 | @Override
130 | public float getMaximumScale() {
131 | return mAttacher.getMaximumScale();
132 | }
133 |
134 | @Override
135 | public float getScale() {
136 | return mAttacher.getScale();
137 | }
138 |
139 | @Override
140 | public ScaleType getScaleType() {
141 | return mAttacher.getScaleType();
142 | }
143 |
144 | @Override
145 | public void setAllowParentInterceptOnEdge(boolean allow) {
146 | mAttacher.setAllowParentInterceptOnEdge(allow);
147 | }
148 |
149 | @Override
150 | @Deprecated
151 | public void setMinScale(float minScale) {
152 | setMinimumScale(minScale);
153 | }
154 |
155 | @Override
156 | public void setMinimumScale(float minimumScale) {
157 | mAttacher.setMinimumScale(minimumScale);
158 | }
159 |
160 | @Override
161 | @Deprecated
162 | public void setMidScale(float midScale) {
163 | setMediumScale(midScale);
164 | }
165 |
166 | @Override
167 | public void setMediumScale(float mediumScale) {
168 | mAttacher.setMediumScale(mediumScale);
169 | }
170 |
171 | @Override
172 | @Deprecated
173 | public void setMaxScale(float maxScale) {
174 | setMaximumScale(maxScale);
175 | }
176 |
177 | @Override
178 | public void setMaximumScale(float maximumScale) {
179 | mAttacher.setMaximumScale(maximumScale);
180 | }
181 |
182 | @Override
183 | // setImageBitmap calls through to this method
184 | public void setImageDrawable(Drawable drawable) {
185 | super.setImageDrawable(drawable);
186 | if (null != mAttacher) {
187 | mAttacher.update();
188 | }
189 | }
190 |
191 | @Override
192 | public void setImageResource(int resId) {
193 | super.setImageResource(resId);
194 | if (null != mAttacher) {
195 | mAttacher.update();
196 | }
197 | }
198 |
199 | @Override
200 | public void setImageURI(Uri uri) {
201 | super.setImageURI(uri);
202 | if (null != mAttacher) {
203 | mAttacher.update();
204 | }
205 | }
206 |
207 | @Override
208 | public void setOnMatrixChangeListener(OnMatrixChangedListener listener) {
209 | mAttacher.setOnMatrixChangeListener(listener);
210 | }
211 |
212 | @Override
213 | public void setOnLongClickListener(OnLongClickListener l) {
214 | mAttacher.setOnLongClickListener(l);
215 | }
216 |
217 | @Override
218 | public void setOnPhotoTapListener(OnPhotoTapListener listener) {
219 | mAttacher.setOnPhotoTapListener(listener);
220 | }
221 |
222 | @Override
223 | public OnPhotoTapListener getOnPhotoTapListener() {
224 | return mAttacher.getOnPhotoTapListener();
225 | }
226 |
227 | @Override
228 | public void setOnViewTapListener(OnViewTapListener listener) {
229 | mAttacher.setOnViewTapListener(listener);
230 | }
231 |
232 | @Override
233 | public OnViewTapListener getOnViewTapListener() {
234 | return mAttacher.getOnViewTapListener();
235 | }
236 |
237 | @Override
238 | public void setScale(float scale) {
239 | mAttacher.setScale(scale);
240 | }
241 |
242 | @Override
243 | public void setScale(float scale, boolean animate) {
244 | mAttacher.setScale(scale, animate);
245 | }
246 |
247 | @Override
248 | public void setScale(float scale, float focalX, float focalY, boolean animate) {
249 | mAttacher.setScale(scale, focalX, focalY, animate);
250 | }
251 |
252 | @Override
253 | public void setScaleType(ScaleType scaleType) {
254 | if (null != mAttacher) {
255 | mAttacher.setScaleType(scaleType);
256 | } else {
257 | mPendingScaleType = scaleType;
258 | }
259 | }
260 |
261 | @Override
262 | public void setZoomable(boolean zoomable) {
263 | mAttacher.setZoomable(zoomable);
264 | }
265 |
266 | @Override
267 | public Bitmap getVisibleRectangleBitmap() {
268 | return mAttacher.getVisibleRectangleBitmap();
269 | }
270 |
271 | @Override
272 | public void setZoomTransitionDuration(int milliseconds) {
273 | mAttacher.setZoomTransitionDuration(milliseconds);
274 | }
275 |
276 | @Override
277 | public IPhotoView getIPhotoViewImplementation() {
278 | return mAttacher;
279 | }
280 |
281 | @Override
282 | public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
283 | mAttacher.setOnDoubleTapListener(newOnDoubleTapListener);
284 | }
285 |
286 | @Override
287 | protected void onDetachedFromWindow() {
288 | mAttacher.cleanup();
289 | super.onDetachedFromWindow();
290 | }
291 | }
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/pulltorefresh/IPullToRefresh.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.pulltorefresh;
17 |
18 | import android.view.View;
19 | import android.view.animation.Interpolator;
20 |
21 | import com.wuba.bangbang.uicomponents.pulltorefresh.PullToRefreshBase.Mode;
22 | import com.wuba.bangbang.uicomponents.pulltorefresh.PullToRefreshBase.OnPullEventListener;
23 | import com.wuba.bangbang.uicomponents.pulltorefresh.PullToRefreshBase.OnRefreshListener;
24 | import com.wuba.bangbang.uicomponents.pulltorefresh.PullToRefreshBase.OnRefreshListener2;
25 | import com.wuba.bangbang.uicomponents.pulltorefresh.PullToRefreshBase.State;
26 |
27 | public interface IPullToRefresh {
28 |
29 | /**
30 | * Demos the Pull-to-Refresh functionality to the user so that they are
31 | * aware it is there. This could be useful when the user first opens your
32 | * app, etc. The animation will only happen if the Refresh View (ListView,
33 | * ScrollView, etc) is in a state where a Pull-to-Refresh could occur by a
34 | * user's touch gesture (i.e. scrolled to the top/bottom).
35 | *
36 | * @return true - if the Demo has been started, false if not.
37 | */
38 | public boolean demo();
39 |
40 | /**
41 | * Get the mode that this view is currently in. This is only really useful
42 | * when using Mode.BOTH.
43 | *
44 | * @return Mode that the view is currently in
45 | */
46 | public Mode getCurrentMode();
47 |
48 | /**
49 | * Returns whether the Touch Events are filtered or not. If true is
50 | * returned, then the View will only use touch events where the difference
51 | * in the Y-axis is greater than the difference in the X-axis. This means
52 | * that the View will not interfere when it is used in a horizontal
53 | * scrolling View (such as a ViewPager).
54 | *
55 | * @return boolean - true if the View is filtering Touch Events
56 | */
57 | public boolean getFilterTouchEvents();
58 |
59 | /**
60 | * Returns a proxy object which allows you to call methods on all of the
61 | * LoadingLayouts (the Views which show when Pulling/Refreshing).
62 | *
63 | * You should not keep the result of this method any longer than you need
64 | * it.
65 | *
66 | * @return Object which will proxy any calls you make on it, to all of the
67 | * LoadingLayouts.
68 | */
69 | public ILoadingLayout getLoadingLayoutProxy();
70 |
71 | /**
72 | * Returns a proxy object which allows you to call methods on the
73 | * LoadingLayouts (the Views which show when Pulling/Refreshing). The actual
74 | * LoadingLayout(s) which will be affected, are chosen by the parameters you
75 | * give.
76 | *
77 | * You should not keep the result of this method any longer than you need
78 | * it.
79 | *
80 | * @param includeStart
81 | * - Whether to include the Start/Header Views
82 | * @param includeEnd
83 | * - Whether to include the End/Footer Views
84 | * @return Object which will proxy any calls you make on it, to the
85 | * LoadingLayouts included.
86 | */
87 | public ILoadingLayout getLoadingLayoutProxy(boolean includeStart,
88 | boolean includeEnd);
89 |
90 | /**
91 | * Get the mode that this view has been set to. If this returns
92 | * Mode.BOTH, you can use getCurrentMode() to
93 | * check which mode the view is currently in
94 | *
95 | * @return Mode that the view has been set to
96 | */
97 | public Mode getMode();
98 |
99 | /**
100 | * Get the Wrapped Refreshable View. Anything returned here has already been
101 | * added to the content view.
102 | *
103 | * @return The View which is currently wrapped
104 | */
105 | public T getRefreshableView();
106 |
107 | /**
108 | * Get whether the 'Refreshing' View should be automatically shown when
109 | * refreshing. Returns true by default.
110 | *
111 | * @return - true if the Refreshing View will be show
112 | */
113 | public boolean getShowViewWhileRefreshing();
114 |
115 | /**
116 | * @return - The state that the View is currently in.
117 | */
118 | public State getState();
119 |
120 | /**
121 | * Whether Pull-to-Refresh is enabled
122 | *
123 | * @return enabled
124 | */
125 | public boolean isPullToRefreshEnabled();
126 |
127 | /**
128 | * Gets whether Overscroll support is enabled. This is different to
129 | * Android's standard Overscroll support (the edge-glow) which is available
130 | * from GINGERBREAD onwards
131 | *
132 | * @return true - if both PullToRefresh-OverScroll and Android's inbuilt
133 | * OverScroll are enabled
134 | */
135 | public boolean isPullToRefreshOverScrollEnabled();
136 |
137 | /**
138 | * Returns whether the Widget is currently in the Refreshing mState
139 | *
140 | * @return true if the Widget is currently refreshing
141 | */
142 | public boolean isRefreshing();
143 |
144 | /**
145 | * Returns whether the widget has enabled scrolling on the Refreshable View
146 | * while refreshing.
147 | *
148 | * @return true if the widget has enabled scrolling while refreshing
149 | */
150 | public boolean isScrollingWhileRefreshingEnabled();
151 |
152 | /**
153 | * Mark the current Refresh as complete. Will Reset the UI and hide the
154 | * Refreshing View
155 | */
156 | public void onRefreshComplete();
157 |
158 | /**
159 | * Set the Touch Events to be filtered or not. If set to true, then the View
160 | * will only use touch events where the difference in the Y-axis is greater
161 | * than the difference in the X-axis. This means that the View will not
162 | * interfere when it is used in a horizontal scrolling View (such as a
163 | * ViewPager), but will restrict which types of finger scrolls will trigger
164 | * the View.
165 | *
166 | * @param filterEvents
167 | * - true if you want to filter Touch Events. Default is true.
168 | */
169 | public void setFilterTouchEvents(boolean filterEvents);
170 |
171 | /**
172 | * Set the mode of Pull-to-Refresh that this view will use.
173 | *
174 | * @param mode
175 | * - Mode to set the View to
176 | */
177 | public void setMode(Mode mode);
178 |
179 | /**
180 | * Set OnPullEventListener for the Widget
181 | *
182 | * @param listener
183 | * - Listener to be used when the Widget has a pull event to
184 | * propogate.
185 | */
186 | public void setOnPullEventListener(OnPullEventListener listener);
187 |
188 | /**
189 | * Set OnRefreshListener for the Widget
190 | *
191 | * @param listener
192 | * - Listener to be used when the Widget is set to Refresh
193 | */
194 | public void setOnRefreshListener(OnRefreshListener listener);
195 |
196 | /**
197 | * Set OnRefreshListener for the Widget
198 | *
199 | * @param listener
200 | * - Listener to be used when the Widget is set to Refresh
201 | */
202 | public void setOnRefreshListener(OnRefreshListener2 listener);
203 |
204 | /**
205 | * Sets whether Overscroll support is enabled. This is different to
206 | * Android's standard Overscroll support (the edge-glow). This setting only
207 | * takes effect when running on device with Android v2.3 or greater.
208 | *
209 | * @param enabled
210 | * - true if you want Overscroll enabled
211 | */
212 | public void setPullToRefreshOverScrollEnabled(boolean enabled);
213 |
214 | /**
215 | * Sets the Widget to be in the refresh state. The UI will be updated to
216 | * show the 'Refreshing' view, and be scrolled to show such.
217 | */
218 | public void setRefreshing();
219 |
220 | /**
221 | * Sets the Widget to be in the refresh state. The UI will be updated to
222 | * show the 'Refreshing' view.
223 | *
224 | * @param doScroll
225 | * - true if you want to force a scroll to the Refreshing view.
226 | */
227 | public void setRefreshing(boolean doScroll);
228 |
229 | /**
230 | * Sets the Animation Interpolator that is used for animated scrolling.
231 | * Defaults to a DecelerateInterpolator
232 | *
233 | * @param interpolator
234 | * - Interpolator to use
235 | */
236 | public void setScrollAnimationInterpolator(Interpolator interpolator);
237 |
238 | /**
239 | * By default the Widget disables scrolling on the Refreshable View while
240 | * refreshing. This method can change this behaviour.
241 | *
242 | * @param scrollingWhileRefreshingEnabled
243 | * - true if you want to enable scrolling while refreshing
244 | */
245 | public void setScrollingWhileRefreshingEnabled(
246 | boolean scrollingWhileRefreshingEnabled);
247 |
248 | /**
249 | * A mutator to enable/disable whether the 'Refreshing' View should be
250 | * automatically shown when refreshing.
251 | *
252 | * @param showView
253 | */
254 | public void setShowViewWhileRefreshing(boolean showView);
255 |
256 | }
257 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/pulltorefresh/OverscrollHelper.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.pulltorefresh;
17 |
18 | import android.annotation.TargetApi;
19 | import android.util.Log;
20 | import android.view.View;
21 |
22 | import com.wuba.bangbang.uicomponents.pulltorefresh.PullToRefreshBase.Mode;
23 | import com.wuba.bangbang.uicomponents.pulltorefresh.PullToRefreshBase.State;
24 |
25 | @TargetApi(9)
26 | public final class OverscrollHelper {
27 |
28 | static final String LOG_TAG = "OverscrollHelper";
29 | static final float DEFAULT_OVERSCROLL_SCALE = 1f;
30 |
31 | /**
32 | * Helper method for Overscrolling that encapsulates all of the necessary
33 | * function.
34 | *
35 | * This should only be used on AdapterView's such as ListView as it just
36 | * calls through to overScrollBy() with the scrollRange = 0. AdapterView's
37 | * do not have a scroll range (i.e. getScrollY() doesn't work).
38 | *
39 | * @param view
40 | * - PullToRefreshView that is calling this.
41 | * @param deltaX
42 | * - Change in X in pixels, passed through from from overScrollBy
43 | * call
44 | * @param scrollX
45 | * - Current X scroll value in pixels before applying deltaY,
46 | * passed through from from overScrollBy call
47 | * @param deltaY
48 | * - Change in Y in pixels, passed through from from overScrollBy
49 | * call
50 | * @param scrollY
51 | * - Current Y scroll value in pixels before applying deltaY,
52 | * passed through from from overScrollBy call
53 | * @param isTouchEvent
54 | * - true if this scroll operation is the result of a touch
55 | * event, passed through from from overScrollBy call
56 | */
57 | public static void overScrollBy(final PullToRefreshBase> view,
58 | final int deltaX, final int scrollX, final int deltaY,
59 | final int scrollY, final boolean isTouchEvent) {
60 | overScrollBy(view, deltaX, scrollX, deltaY, scrollY, 0, isTouchEvent);
61 | }
62 |
63 | /**
64 | * Helper method for Overscrolling that encapsulates all of the necessary
65 | * function. This version of the call is used for Views that need to specify
66 | * a Scroll Range but scroll back to it's edge correctly.
67 | *
68 | * @param view
69 | * - PullToRefreshView that is calling this.
70 | * @param deltaX
71 | * - Change in X in pixels, passed through from from overScrollBy
72 | * call
73 | * @param scrollX
74 | * - Current X scroll value in pixels before applying deltaY,
75 | * passed through from from overScrollBy call
76 | * @param deltaY
77 | * - Change in Y in pixels, passed through from from overScrollBy
78 | * call
79 | * @param scrollY
80 | * - Current Y scroll value in pixels before applying deltaY,
81 | * passed through from from overScrollBy call
82 | * @param scrollRange
83 | * - Scroll Range of the View, specifically needed for ScrollView
84 | * @param isTouchEvent
85 | * - true if this scroll operation is the result of a touch
86 | * event, passed through from from overScrollBy call
87 | */
88 | public static void overScrollBy(final PullToRefreshBase> view,
89 | final int deltaX, final int scrollX, final int deltaY,
90 | final int scrollY, final int scrollRange, final boolean isTouchEvent) {
91 | overScrollBy(view, deltaX, scrollX, deltaY, scrollY, scrollRange, 0,
92 | DEFAULT_OVERSCROLL_SCALE, isTouchEvent);
93 | }
94 |
95 | /**
96 | * Helper method for Overscrolling that encapsulates all of the necessary
97 | * function. This is the advanced version of the call.
98 | *
99 | * @param view
100 | * - PullToRefreshView that is calling this.
101 | * @param deltaX
102 | * - Change in X in pixels, passed through from from overScrollBy
103 | * call
104 | * @param scrollX
105 | * - Current X scroll value in pixels before applying deltaY,
106 | * passed through from from overScrollBy call
107 | * @param deltaY
108 | * - Change in Y in pixels, passed through from from overScrollBy
109 | * call
110 | * @param scrollY
111 | * - Current Y scroll value in pixels before applying deltaY,
112 | * passed through from from overScrollBy call
113 | * @param scrollRange
114 | * - Scroll Range of the View, specifically needed for ScrollView
115 | * @param fuzzyThreshold
116 | * - Threshold for which the values how fuzzy we should treat the
117 | * other values. Needed for WebView as it doesn't always scroll
118 | * back to it's edge. 0 = no fuzziness.
119 | * @param scaleFactor
120 | * - Scale Factor for overscroll amount
121 | * @param isTouchEvent
122 | * - true if this scroll operation is the result of a touch
123 | * event, passed through from from overScrollBy call
124 | */
125 | public static void overScrollBy(final PullToRefreshBase> view,
126 | final int deltaX, final int scrollX, final int deltaY,
127 | final int scrollY, final int scrollRange, final int fuzzyThreshold,
128 | final float scaleFactor, final boolean isTouchEvent) {
129 |
130 | final int deltaValue, currentScrollValue, scrollValue;
131 | switch (view.getPullToRefreshScrollDirection()) {
132 | case HORIZONTAL:
133 | deltaValue = deltaX;
134 | scrollValue = scrollX;
135 | currentScrollValue = view.getScrollX();
136 | break;
137 | case VERTICAL:
138 | default:
139 | deltaValue = deltaY;
140 | scrollValue = scrollY;
141 | currentScrollValue = view.getScrollY();
142 | break;
143 | }
144 |
145 | // Check that OverScroll is enabled and that we're not currently
146 | // refreshing.
147 | if (view.isPullToRefreshOverScrollEnabled() && !view.isRefreshing()) {
148 | final Mode mode = view.getMode();
149 |
150 | // Check that Pull-to-Refresh is enabled, and the event isn't from
151 | // touch
152 | if (mode.permitsPullToRefresh() && !isTouchEvent && deltaValue != 0) {
153 | final int newScrollValue = (deltaValue + scrollValue);
154 |
155 | if (PullToRefreshBase.DEBUG) {
156 | Log.d(LOG_TAG, "OverScroll. DeltaX: " + deltaX
157 | + ", ScrollX: " + scrollX + ", DeltaY: " + deltaY
158 | + ", ScrollY: " + scrollY + ", NewY: "
159 | + newScrollValue + ", ScrollRange: " + scrollRange
160 | + ", CurrentScroll: " + currentScrollValue);
161 | }
162 |
163 | if (newScrollValue < (0 - fuzzyThreshold)) {
164 | // Check the mode supports the overscroll direction, and
165 | // then move scroll
166 | if (mode.showHeaderLoadingLayout()) {
167 | // If we're currently at zero, we're about to start
168 | // overscrolling, so change the state
169 | if (currentScrollValue == 0) {
170 | view.setState(State.OVERSCROLLING);
171 | }
172 |
173 | view.setHeaderScroll((int) (scaleFactor * (currentScrollValue + newScrollValue)));
174 | }
175 | } else if (newScrollValue > (scrollRange + fuzzyThreshold)) {
176 | // Check the mode supports the overscroll direction, and
177 | // then move scroll
178 | if (mode.showFooterLoadingLayout()) {
179 | // If we're currently at zero, we're about to start
180 | // overscrolling, so change the state
181 | if (currentScrollValue == 0) {
182 | view.setState(State.OVERSCROLLING);
183 | }
184 |
185 | view.setHeaderScroll((int) (scaleFactor * (currentScrollValue
186 | + newScrollValue - scrollRange)));
187 | }
188 | } else if (Math.abs(newScrollValue) <= fuzzyThreshold
189 | || Math.abs(newScrollValue - scrollRange) <= fuzzyThreshold) {
190 | // Means we've stopped overscrolling, so scroll back to 0
191 | view.setState(State.RESET);
192 | }
193 | } else if (isTouchEvent && State.OVERSCROLLING == view.getState()) {
194 | // This condition means that we were overscrolling from a fling,
195 | // but the user has touched the View and is now overscrolling
196 | // from touch instead. We need to just reset.
197 | view.setState(State.RESET);
198 | }
199 | }
200 | }
201 |
202 | static boolean isAndroidOverScrollEnabled(View view) {
203 | return view.getOverScrollMode() != View.OVER_SCROLL_NEVER;
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/photoview/IPhotoView.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.photoview;
17 |
18 | import android.graphics.Bitmap;
19 | import android.graphics.Matrix;
20 | import android.graphics.RectF;
21 | import android.view.GestureDetector;
22 | import android.view.View;
23 | import android.widget.ImageView;
24 |
25 | /**
26 | * 支持缩放的图片接口
27 | * @author 徐宁
28 | * @date: 2015-2-27 上午11:08:16
29 | */
30 | public interface IPhotoView {
31 |
32 | public static final float DEFAULT_MAX_SCALE = 3.0f;
33 | public static final float DEFAULT_MID_SCALE = 1.75f;
34 | public static final float DEFAULT_MIN_SCALE = 1.0f;
35 | public static final int DEFAULT_ZOOM_DURATION = 200;
36 |
37 | /**
38 | * Returns true if the PhotoView is set to allow zooming of Photos.
39 | *
40 | * @return true if the PhotoView allows zooming.
41 | */
42 | boolean canZoom();
43 |
44 | /**
45 | * Gets the Display Rectangle of the currently displayed Drawable. The Rectangle is relative to
46 | * this View and includes all scaling and translations.
47 | *
48 | * @return - RectF of Displayed Drawable
49 | */
50 | RectF getDisplayRect();
51 |
52 | /**
53 | * Sets the Display Matrix of the currently displayed Drawable. The Rectangle is considered
54 | * relative to this View and includes all scaling and translations.
55 | *
56 | * @param finalMatrix target matrix to set PhotoView to
57 | * @return - true if rectangle was applied successfully
58 | */
59 | boolean setDisplayMatrix(Matrix finalMatrix);
60 |
61 | /**
62 | * Gets the Display Matrix of the currently displayed Drawable. The Rectangle is considered
63 | * relative to this View and includes all scaling and translations.
64 | *
65 | * @return - true if rectangle was applied successfully
66 | */
67 | Matrix getDisplayMatrix();
68 |
69 | /**
70 | * Use {@link #getMinimumScale()} instead, this will be removed in future release
71 | *
72 | * @return The current minimum scale level. What this value represents depends on the current
73 | * {@link android.widget.ImageView.ScaleType}.
74 | */
75 | @Deprecated
76 | float getMinScale();
77 |
78 | /**
79 | * @return The current minimum scale level. What this value represents depends on the current
80 | * {@link android.widget.ImageView.ScaleType}.
81 | */
82 | float getMinimumScale();
83 |
84 | /**
85 | * Use {@link #getMediumScale()} instead, this will be removed in future release
86 | *
87 | * @return The current middle scale level. What this value represents depends on the current
88 | * {@link android.widget.ImageView.ScaleType}.
89 | */
90 | @Deprecated
91 | float getMidScale();
92 |
93 | /**
94 | * @return The current medium scale level. What this value represents depends on the current
95 | * {@link android.widget.ImageView.ScaleType}.
96 | */
97 | float getMediumScale();
98 |
99 | /**
100 | * Use {@link #getMaximumScale()} instead, this will be removed in future release
101 | *
102 | * @return The current maximum scale level. What this value represents depends on the current
103 | * {@link android.widget.ImageView.ScaleType}.
104 | */
105 | @Deprecated
106 | float getMaxScale();
107 |
108 | /**
109 | * @return The current maximum scale level. What this value represents depends on the current
110 | * {@link android.widget.ImageView.ScaleType}.
111 | */
112 | float getMaximumScale();
113 |
114 | /**
115 | * Returns the current scale value
116 | *
117 | * @return float - current scale value
118 | */
119 | float getScale();
120 |
121 | /**
122 | * Return the current scale type in use by the ImageView.
123 | *
124 | * @return current ImageView.ScaleType
125 | */
126 | ImageView.ScaleType getScaleType();
127 |
128 | /**
129 | * Whether to allow the ImageView's parent to intercept the touch event when the photo is scroll
130 | * to it's horizontal edge.
131 | *
132 | * @param allow whether to allow intercepting by parent element or not
133 | */
134 | void setAllowParentInterceptOnEdge(boolean allow);
135 |
136 | /**
137 | * Use {@link #setMinimumScale(float minimumScale)} instead, this will be removed in future
138 | * release
139 | *
140 | * Sets the minimum scale level. What this value represents depends on the current {@link
141 | * android.widget.ImageView.ScaleType}.
142 | *
143 | * @param minScale minimum allowed scale
144 | */
145 | @Deprecated
146 | void setMinScale(float minScale);
147 |
148 | /**
149 | * Sets the minimum scale level. What this value represents depends on the current {@link
150 | * android.widget.ImageView.ScaleType}.
151 | *
152 | * @param minimumScale minimum allowed scale
153 | */
154 | void setMinimumScale(float minimumScale);
155 |
156 | /**
157 | * Use {@link #setMediumScale(float mediumScale)} instead, this will be removed in future
158 | * release
159 | *
160 | * Sets the middle scale level. What this value represents depends on the current {@link
161 | * android.widget.ImageView.ScaleType}.
162 | *
163 | * @param midScale medium scale preset
164 | */
165 | @Deprecated
166 | void setMidScale(float midScale);
167 |
168 | /*
169 | * Sets the medium scale level. What this value represents depends on the current {@link android.widget.ImageView.ScaleType}.
170 | *
171 | * @param mediumScale medium scale preset
172 | */
173 | void setMediumScale(float mediumScale);
174 |
175 | /**
176 | * Use {@link #setMaximumScale(float maximumScale)} instead, this will be removed in future
177 | * release
178 | *
179 | * Sets the maximum scale level. What this value represents depends on the current {@link
180 | * android.widget.ImageView.ScaleType}.
181 | *
182 | * @param maxScale maximum allowed scale preset
183 | */
184 | @Deprecated
185 | void setMaxScale(float maxScale);
186 |
187 | /**
188 | * Sets the maximum scale level. What this value represents depends on the current {@link
189 | * android.widget.ImageView.ScaleType}.
190 | *
191 | * @param maximumScale maximum allowed scale preset
192 | */
193 | void setMaximumScale(float maximumScale);
194 |
195 | /**
196 | * Register a callback to be invoked when the Photo displayed by this view is long-pressed.
197 | *
198 | * @param listener - Listener to be registered.
199 | */
200 | void setOnLongClickListener(View.OnLongClickListener listener);
201 |
202 | /**
203 | * Register a callback to be invoked when the Matrix has changed for this View. An example would
204 | * be the user panning or scaling the Photo.
205 | *
206 | * @param listener - Listener to be registered.
207 | */
208 | void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener);
209 |
210 | /**
211 | * Register a callback to be invoked when the Photo displayed by this View is tapped with a
212 | * single tap.
213 | *
214 | * @param listener - Listener to be registered.
215 | */
216 | void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener);
217 |
218 | /**
219 | * Returns a listener to be invoked when the Photo displayed by this View is tapped with a
220 | * single tap.
221 | *
222 | * @return PhotoViewAttacher.OnPhotoTapListener currently set, may be null
223 | */
224 | PhotoViewAttacher.OnPhotoTapListener getOnPhotoTapListener();
225 |
226 | /**
227 | * Register a callback to be invoked when the View is tapped with a single tap.
228 | *
229 | * @param listener - Listener to be registered.
230 | */
231 | void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener);
232 |
233 | /**
234 | * Enables rotation via PhotoView internal functions.
235 | *
236 | * @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360
237 | */
238 | void setRotationTo(float rotationDegree);
239 |
240 | /**
241 | * Enables rotation via PhotoView internal functions.
242 | *
243 | * @param rotationDegree - Degree to rotate PhotoView by, should be in range 0 to 360
244 | */
245 | void setRotationBy(float rotationDegree);
246 |
247 | /**
248 | * Returns a callback listener to be invoked when the View is tapped with a single tap.
249 | *
250 | * @return PhotoViewAttacher.OnViewTapListener currently set, may be null
251 | */
252 | PhotoViewAttacher.OnViewTapListener getOnViewTapListener();
253 |
254 | /**
255 | * Changes the current scale to the specified value.
256 | *
257 | * @param scale - Value to scale to
258 | */
259 | void setScale(float scale);
260 |
261 | /**
262 | * Changes the current scale to the specified value.
263 | *
264 | * @param scale - Value to scale to
265 | * @param animate - Whether to animate the scale
266 | */
267 | void setScale(float scale, boolean animate);
268 |
269 | /**
270 | * Changes the current scale to the specified value, around the given focal point.
271 | *
272 | * @param scale - Value to scale to
273 | * @param focalX - X Focus Point
274 | * @param focalY - Y Focus Point
275 | * @param animate - Whether to animate the scale
276 | */
277 | void setScale(float scale, float focalX, float focalY, boolean animate);
278 |
279 | /**
280 | * Controls how the image should be resized or moved to match the size of the ImageView. Any
281 | * scaling or panning will happen within the confines of this {@link
282 | * android.widget.ImageView.ScaleType}.
283 | *
284 | * @param scaleType - The desired scaling mode.
285 | */
286 | void setScaleType(ImageView.ScaleType scaleType);
287 |
288 | /**
289 | * Allows you to enable/disable the zoom functionality on the ImageView. When disable the
290 | * ImageView reverts to using the FIT_CENTER matrix.
291 | *
292 | * @param zoomable - Whether the zoom functionality is enabled.
293 | */
294 | void setZoomable(boolean zoomable);
295 |
296 | /**
297 | * Enables rotation via PhotoView internal functions. Name is chosen so it won't collide with
298 | * View.setRotation(float) in API since 11
299 | *
300 | * @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360
301 | * @deprecated use {@link #setRotationTo(float)}
302 | */
303 | void setPhotoViewRotation(float rotationDegree);
304 |
305 | /**
306 | * Extracts currently visible area to Bitmap object, if there is no image loaded yet or the
307 | * ImageView is already destroyed, returns {@code null}
308 | *
309 | * @return currently visible area as bitmap or null
310 | */
311 | Bitmap getVisibleRectangleBitmap();
312 |
313 | /**
314 | * Allows to change zoom transition speed, default value is 200 (PhotoViewAttacher.DEFAULT_ZOOM_DURATION).
315 | * Will default to 200 if provided negative value
316 | *
317 | * @param milliseconds duration of zoom interpolation
318 | */
319 | void setZoomTransitionDuration(int milliseconds);
320 |
321 | /**
322 | * Will return instance of IPhotoView (eg. PhotoViewAttacher), can be used to provide better
323 | * integration
324 | *
325 | * @return IPhotoView implementation instance if available, null if not
326 | */
327 | IPhotoView getIPhotoViewImplementation();
328 |
329 | /**
330 | * Sets custom double tap listener, to intercept default given functions. To reset behavior to
331 | * default, you can just pass in "null" or public field of PhotoViewAttacher.defaultOnDoubleTapListener
332 | *
333 | * @param newOnDoubleTapListener custom OnDoubleTapListener to be set on ImageView
334 | */
335 | public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener);
336 | }
337 |
--------------------------------------------------------------------------------
/src/com/wuba/bangbang/uicomponents/pulltorefresh/internal/LoadingLayout.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
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 com.wuba.bangbang.uicomponents.pulltorefresh.internal;
17 |
18 | import android.annotation.SuppressLint;
19 | import android.content.Context;
20 | import android.content.res.ColorStateList;
21 | import android.content.res.TypedArray;
22 | import android.graphics.Typeface;
23 | import android.graphics.drawable.AnimationDrawable;
24 | import android.graphics.drawable.Drawable;
25 | import android.util.TypedValue;
26 | import android.view.Gravity;
27 | import android.view.LayoutInflater;
28 | import android.view.View;
29 | import android.view.ViewGroup;
30 | import android.view.animation.Interpolator;
31 | import android.view.animation.LinearInterpolator;
32 | import android.widget.FrameLayout;
33 | import android.widget.ImageView;
34 | import android.widget.LinearLayout;
35 | import android.widget.ProgressBar;
36 | import android.widget.RelativeLayout;
37 | import android.widget.TextView;
38 |
39 | import com.example.android_select_picture_module.R;
40 | import com.wuba.bangbang.uicomponents.pulltorefresh.ILoadingLayout;
41 | import com.wuba.bangbang.uicomponents.pulltorefresh.PullToRefreshBase.Mode;
42 |
43 | @SuppressLint("ViewConstructor")
44 | public abstract class LoadingLayout extends FrameLayout implements
45 | ILoadingLayout {
46 |
47 | static final String LOG_TAG = "PullToRefresh-LoadingLayout";
48 |
49 | static final Interpolator ANIMATION_INTERPOLATOR = new LinearInterpolator();
50 |
51 | protected RelativeLayout mInnerLayout;
52 |
53 | protected final ImageView mHeaderImage;
54 |
55 | private boolean mUseIntrinsicAnimation;
56 |
57 | protected final TextView mHeaderText;
58 |
59 | protected final Mode mMode;
60 | /**上拉加载更多*/
61 | private CharSequence mPullLabel;
62 | /**正在刷新*/
63 | private CharSequence mRefreshingLabel;
64 | /**松开即可加载*/
65 | private CharSequence mReleaseLabel;
66 | /**刷新结束时显示的文字提示,如“加载成功”*/
67 | protected CharSequence mFinishLabel;
68 | /**头部显示的ProgressBar*/
69 | protected ProgressBar mProgressBar;
70 | protected LinearLayout mHeader;
71 |
72 |
73 | public LoadingLayout(Context context, final Mode mode, TypedArray attrs) {
74 | super(context);
75 | mMode = mode;
76 |
77 | LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header_vertical, this);
78 | mInnerLayout = (RelativeLayout) findViewById(R.id.fl_inner);
79 | mHeaderText = (TextView) mInnerLayout.findViewById(R.id.pull_to_refresh_text);
80 | mHeaderImage = (ImageView) mInnerLayout.findViewById(R.id.pull_to_refresh_image);
81 | mProgressBar = (ProgressBar)findViewById(R.id.progressbar);
82 | mHeader = (LinearLayout)findViewById(R.id.header);
83 | readLabel();
84 |
85 | if (attrs.hasValue(R.styleable.pull_to_refresh_ptr_header_background)) {
86 | Drawable background = attrs.getDrawable(R.styleable.pull_to_refresh_ptr_header_background);
87 | if (null != background) {
88 | ViewCompat.setBackground(this, background);
89 | }
90 | }
91 |
92 | if (attrs.hasValue(R.styleable.pull_to_refresh_ptr_header_text_appearance)) {
93 | TypedValue styleID = new TypedValue();
94 | attrs.getValue(R.styleable.pull_to_refresh_ptr_header_text_appearance, styleID);
95 | setTextAppearance(styleID.data);
96 | }
97 | if (attrs.hasValue(R.styleable.pull_to_refresh_ptr_sub_header_text_appearance)) {
98 | TypedValue styleID = new TypedValue();
99 | attrs.getValue(
100 | R.styleable.pull_to_refresh_ptr_sub_header_text_appearance,
101 | styleID);
102 | }
103 |
104 | // Text Color attrs need to be set after TextAppearance attrs
105 | if (attrs.hasValue(R.styleable.pull_to_refresh_ptr_header_text_color)) {
106 | ColorStateList colors = attrs
107 | .getColorStateList(R.styleable.pull_to_refresh_ptr_header_text_color);
108 | if (null != colors) {
109 | setTextColor(colors);
110 | }
111 | }
112 |
113 | // Try and get defined drawable from Attrs
114 | Drawable imageDrawable = null;
115 | if (attrs.hasValue(R.styleable.pull_to_refresh_ptr_drawable)) {
116 | imageDrawable = attrs
117 | .getDrawable(R.styleable.pull_to_refresh_ptr_drawable);
118 | }
119 |
120 | // Check Specific Drawable from Attrs, these overrite the generic
121 | // drawable attr above
122 | switch (mode) {
123 | case PULL_FROM_START:
124 | default:
125 | if (attrs.hasValue(R.styleable.pull_to_refresh_ptr_drawable_start)) {
126 | imageDrawable = attrs
127 | .getDrawable(R.styleable.pull_to_refresh_ptr_drawable_start);
128 | } else if (attrs
129 | .hasValue(R.styleable.pull_to_refresh_ptr_drawable_top)) {
130 | Utils.warnDeprecation("ptrDrawableTop", "ptrDrawableStart");
131 | imageDrawable = attrs
132 | .getDrawable(R.styleable.pull_to_refresh_ptr_drawable_top);
133 | }
134 | break;
135 |
136 | case PULL_FROM_END:
137 | if (attrs.hasValue(R.styleable.pull_to_refresh_ptr_drawable_end)) {
138 | imageDrawable = attrs
139 | .getDrawable(R.styleable.pull_to_refresh_ptr_drawable_end);
140 | } else if (attrs
141 | .hasValue(R.styleable.pull_to_refresh_ptr_drawable_bottom)) {
142 | Utils.warnDeprecation("ptrDrawableBottom", "ptrDrawableEnd");
143 | imageDrawable = attrs
144 | .getDrawable(R.styleable.pull_to_refresh_ptr_drawable_bottom);
145 | }
146 | break;
147 | }
148 |
149 | // If we don't have a user defined drawable, load the default
150 | if (null == imageDrawable) {
151 | imageDrawable = context.getResources().getDrawable(
152 | getDefaultDrawableResId());
153 | }
154 |
155 | // Set Drawable, and save width/height
156 | setLoadingDrawable(imageDrawable);
157 |
158 | reset();
159 | }
160 |
161 | /**
162 | * 获取Lable
163 | */
164 | private void readLabel() {
165 | if (mInnerLayout == null || mMode == null) {
166 | return;
167 | }
168 |
169 | Context context = getContext();
170 | FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mInnerLayout.getLayoutParams();
171 | mFinishLabel = context.getString(R.string.pull_up_refresh_complete_label);
172 | switch (mMode) {
173 | case PULL_FROM_END:
174 | lp.gravity = Gravity.TOP;
175 |
176 | // Load in labels
177 | mPullLabel = context
178 | .getString(R.string.pull_to_refresh_from_bottom_pull_label);
179 | mRefreshingLabel = context
180 | .getString(R.string.pull_to_refresh_from_bottom_refreshing_label);
181 | mReleaseLabel = context
182 | .getString(R.string.pull_to_refresh_from_bottom_release_label);
183 | break;
184 |
185 | case PULL_FROM_START:
186 | default:
187 | lp.gravity = Gravity.BOTTOM;
188 |
189 | // Load in labels
190 | mPullLabel = context.getString(R.string.pull_to_refresh_pull_label);
191 | mRefreshingLabel = context
192 | .getString(R.string.pull_to_refresh_refreshing_label);
193 | mReleaseLabel = context
194 | .getString(R.string.pull_to_refresh_release_label);
195 | break;
196 | }
197 | }
198 |
199 | public final void setHeight(int height) {
200 | ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) getLayoutParams();
201 | lp.height = height;
202 | requestLayout();
203 | }
204 |
205 | public final void setWidth(int width) {
206 | ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) getLayoutParams();
207 | lp.width = width;
208 | requestLayout();
209 | }
210 |
211 | public final int getContentSize() {
212 | return mInnerLayout.getHeight();
213 | }
214 |
215 | public final void hideAllViews() {
216 | if (View.VISIBLE == mHeaderText.getVisibility()) {
217 | mHeaderText.setVisibility(View.INVISIBLE);
218 | }
219 | if (View.VISIBLE == mHeaderImage.getVisibility()) {
220 | mHeaderImage.setVisibility(View.INVISIBLE);
221 | }
222 | }
223 |
224 | public final void onPull(float scaleOfLayout) {
225 | if (!mUseIntrinsicAnimation) {
226 | onPullImpl(scaleOfLayout);
227 | }
228 | }
229 |
230 | public final void pullToRefresh() {
231 | //显示提示文字,隐藏progressbar
232 | if(mHeader.getVisibility() != View.VISIBLE){
233 |
234 | mHeader.setVisibility(View.VISIBLE);
235 | }
236 | if(mProgressBar.getVisibility() == View.VISIBLE){
237 |
238 | mProgressBar.setVisibility(View.GONE);
239 | }
240 | if (null != mHeaderText) {
241 | mHeaderText.setText(mPullLabel);
242 | }
243 |
244 | // Now call the callback
245 | pullToRefreshImpl();
246 | }
247 |
248 | public final void refreshing() {
249 |
250 | //隐藏提示文字
251 | if(mHeader.getVisibility() == View.VISIBLE){
252 |
253 | mHeader.setVisibility(View.GONE);
254 | }
255 | if (null != mHeaderText) {
256 | mHeaderText.setText(mRefreshingLabel);
257 | }
258 |
259 | if (mUseIntrinsicAnimation) {
260 | ((AnimationDrawable) mHeaderImage.getDrawable()).start();
261 | } else {
262 | // Now call the callback
263 | refreshingImpl();
264 | }
265 | }
266 |
267 | public final void releaseToRefresh() {
268 | if (null != mHeaderText) {
269 | mHeaderText.setText(mReleaseLabel);
270 | }
271 |
272 | // Now call the callback
273 | releaseToRefreshImpl();
274 | }
275 |
276 | public final void reset() {
277 | if (null != mHeaderText) {
278 | mHeaderText.setText(mPullLabel);
279 | }
280 | mHeaderImage.setVisibility(View.VISIBLE);
281 |
282 | if (mUseIntrinsicAnimation) {
283 | ((AnimationDrawable) mHeaderImage.getDrawable()).stop();
284 | } else {
285 | // Now call the callback
286 | resetImpl();
287 | }
288 | }
289 |
290 | public final void setLoadingDrawable(Drawable imageDrawable) {
291 | // Set Drawable
292 | mHeaderImage.setImageDrawable(imageDrawable);
293 | mUseIntrinsicAnimation = (imageDrawable instanceof AnimationDrawable);
294 |
295 | // Now call the callback
296 | onLoadingDrawableSet(imageDrawable);
297 | }
298 |
299 | public void setPullLabel(CharSequence pullLabel) {
300 | mPullLabel = pullLabel;
301 | }
302 |
303 | public void setRefreshingLabel(CharSequence refreshingLabel) {
304 | mRefreshingLabel = refreshingLabel;
305 | // 更新视图显示
306 | // 下面这段逻辑会影响组件显示结果,如果下拉刷新的需求改变可以关注一下这部分逻辑还需不需要
307 | if (null != mHeaderText) {
308 | mHeaderText.setText(mRefreshingLabel);
309 | }
310 | readLabel();
311 | }
312 |
313 | public void setReleaseLabel(CharSequence releaseLabel) {
314 | mReleaseLabel = releaseLabel;
315 | }
316 |
317 | @Override
318 | public void setTextTypeface(Typeface tf) {
319 | mHeaderText.setTypeface(tf);
320 | }
321 |
322 | public final void showInvisibleViews() {
323 | if (View.INVISIBLE == mHeaderText.getVisibility()) {
324 | mHeaderText.setVisibility(View.VISIBLE);
325 | }
326 | if (View.INVISIBLE == mHeaderImage.getVisibility()) {
327 | mHeaderImage.setVisibility(View.VISIBLE);
328 | }
329 | }
330 |
331 | /**
332 | * Callbacks for derivative Layouts
333 | */
334 |
335 | protected abstract int getDefaultDrawableResId();
336 |
337 | protected abstract void onLoadingDrawableSet(Drawable imageDrawable);
338 | /**下拉回调接口*/
339 | protected abstract void onPullImpl(float scaleOfLayout);
340 |
341 | protected abstract void pullToRefreshImpl();
342 |
343 | protected abstract void refreshingImpl();
344 |
345 | protected abstract void releaseToRefreshImpl();
346 |
347 | protected abstract void resetImpl();
348 |
349 | private void setTextAppearance(int value) {
350 | if (null != mHeaderText) {
351 | mHeaderText.setTextAppearance(getContext(), value);
352 | }
353 | }
354 |
355 | private void setTextColor(ColorStateList color) {
356 | if (null != mHeaderText) {
357 | mHeaderText.setTextColor(color);
358 | }
359 | }
360 |
361 | public CharSequence getmFinishLabel() {
362 | return mFinishLabel;
363 | }
364 | }
--------------------------------------------------------------------------------