74 | * The default implementation attempts to reset all view properties. This is useful when toggling transforms that do 75 | * not modify the same page properties. For instance changing from a transformation that applies rotation to a 76 | * transformation that fades can inadvertently leave a fragment stuck with a rotation or with some degree of applied 77 | * alpha. 78 | * 79 | * @param page 80 | * Apply the transformation to this page 81 | * @param position 82 | * Position of page relative to the current front-and-center position of the pager. 0 is front and 83 | * center. 1 is one full page position to the right, and -1 is one page position to the left. 84 | */ 85 | protected void onPreTransform(View page, float position) { 86 | final float width = page.getWidth(); 87 | 88 | page.setRotationX(0); 89 | page.setRotationY(0); 90 | page.setRotation(0); 91 | page.setScaleX(1); 92 | page.setScaleY(1); 93 | page.setPivotX(0); 94 | page.setPivotY(0); 95 | page.setTranslationY(0); 96 | page.setTranslationX(isPagingEnabled() ? 0f : -width * position); 97 | 98 | if (hideOffscreenPages()) { 99 | page.setAlpha(position <= -1f || position >= 1f ? 0f : 1f); 100 | page.setEnabled(false); 101 | } else { 102 | page.setEnabled(true); 103 | page.setAlpha(1f); 104 | } 105 | } 106 | 107 | /** 108 | * Called each {@link #transformPage(View, float)} after {@link #onTransform(View, float)}. 109 | * 110 | * @param page 111 | * Apply the transformation to this page 112 | * @param position 113 | * Position of page relative to the current front-and-center position of the pager. 0 is front and 114 | * center. 1 is one full page position to the right, and -1 is one page position to the left. 115 | */ 116 | protected void onPostTransform(View page, float position) { 117 | } 118 | 119 | /** 120 | * Same as {@link Math#min(double, double)} without double casting, zero closest to infinity handling, or NaN support. 121 | * 122 | * @param val 123 | * @param min 124 | * @return 125 | */ 126 | protected static final float min(float val, float min) { 127 | return val < min ? min : val; 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/AccordionTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class AccordionTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | view.setPivotX(position < 0 ? 0 : view.getWidth()); 26 | view.setScaleX(position < 0 ? 1f + position : 1f - position); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/BackgroundToForegroundTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class BackgroundToForegroundTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | final float height = view.getHeight(); 26 | final float width = view.getWidth(); 27 | final float scale = min(position < 0 ? 1f : Math.abs(1f - position), 0.5f); 28 | 29 | view.setScaleX(scale); 30 | view.setScaleY(scale); 31 | view.setPivotX(width * 0.5f); 32 | view.setPivotY(height * 0.5f); 33 | view.setTranslationX(position < 0 ? width * position : -width * position * 0.25f); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/CubeInTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class CubeInTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | // Rotate the fragment on the left or right edge 26 | view.setPivotX(position > 0 ? 0 : view.getWidth()); 27 | view.setPivotY(0); 28 | view.setRotationY(-90f * position); 29 | } 30 | 31 | @Override 32 | public boolean isPagingEnabled() { 33 | return true; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/CubeOutTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class CubeOutTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | view.setPivotX(position < 0f ? view.getWidth() : 0f); 26 | view.setPivotY(view.getHeight() * 0.5f); 27 | view.setRotationY(90f * position); 28 | } 29 | 30 | @Override 31 | public boolean isPagingEnabled() { 32 | return true; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/DefaultTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class DefaultTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | } 26 | 27 | @Override 28 | public boolean isPagingEnabled() { 29 | return true; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/DepthPageTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class DepthPageTransformer extends ABaseTransformer { 22 | 23 | private static final float MIN_SCALE = 0.75f; 24 | 25 | @Override 26 | protected void onTransform(View view, float position) { 27 | if (position <= 0f) { 28 | view.setTranslationX(0f); 29 | view.setScaleX(1f); 30 | view.setScaleY(1f); 31 | } else if (position <= 1f) { 32 | final float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); 33 | view.setAlpha(1 - position); 34 | view.setPivotY(0.5f * view.getHeight()); 35 | view.setTranslationX(view.getWidth() * -position); 36 | view.setScaleX(scaleFactor); 37 | view.setScaleY(scaleFactor); 38 | } 39 | } 40 | 41 | @Override 42 | protected boolean isPagingEnabled() { 43 | return true; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/FlipHorizontalTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class FlipHorizontalTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | final float rotation = 180f * position; 26 | 27 | view.setAlpha(rotation > 90f || rotation < -90f ? 0 : 1); 28 | view.setPivotX(view.getWidth() * 0.5f); 29 | view.setPivotY(view.getHeight() * 0.5f); 30 | view.setRotationY(rotation); 31 | } 32 | 33 | @Override 34 | protected void onPostTransform(View page, float position) { 35 | super.onPostTransform(page, position); 36 | 37 | //resolve problem: new page can't handle click event! 38 | if (position > -0.5f && position < 0.5f) { 39 | page.setVisibility(View.VISIBLE); 40 | } else { 41 | page.setVisibility(View.INVISIBLE); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/FlipVerticalTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class FlipVerticalTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | final float rotation = -180f * position; 26 | 27 | view.setAlpha(rotation > 90f || rotation < -90f ? 0f : 1f); 28 | view.setPivotX(view.getWidth() * 0.5f); 29 | view.setPivotY(view.getHeight() * 0.5f); 30 | view.setRotationX(rotation); 31 | } 32 | 33 | @Override 34 | protected void onPostTransform(View page, float position) { 35 | super.onPostTransform(page, position); 36 | 37 | if (position > -0.5f && position < 0.5f) { 38 | page.setVisibility(View.VISIBLE); 39 | } else { 40 | page.setVisibility(View.INVISIBLE); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/ForegroundToBackgroundTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class ForegroundToBackgroundTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | final float height = view.getHeight(); 26 | final float width = view.getWidth(); 27 | final float scale = min(position > 0 ? 1f : Math.abs(1f + position), 0.5f); 28 | 29 | view.setScaleX(scale); 30 | view.setScaleY(scale); 31 | view.setPivotX(width * 0.5f); 32 | view.setPivotY(height * 0.5f); 33 | view.setTranslationX(position > 0 ? width * position : -width * position * 0.25f); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/RotateDownTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class RotateDownTransformer extends ABaseTransformer { 22 | 23 | private static final float ROT_MOD = -15f; 24 | 25 | @Override 26 | protected void onTransform(View view, float position) { 27 | final float width = view.getWidth(); 28 | final float height = view.getHeight(); 29 | final float rotation = ROT_MOD * position * -1.25f; 30 | 31 | view.setPivotX(width * 0.5f); 32 | view.setPivotY(height); 33 | view.setRotation(rotation); 34 | } 35 | 36 | @Override 37 | protected boolean isPagingEnabled() { 38 | return true; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/RotateUpTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class RotateUpTransformer extends ABaseTransformer { 22 | 23 | private static final float ROT_MOD = -15f; 24 | 25 | @Override 26 | protected void onTransform(View view, float position) { 27 | final float width = view.getWidth(); 28 | final float rotation = ROT_MOD * position; 29 | 30 | view.setPivotX(width * 0.5f); 31 | view.setPivotY(0f); 32 | view.setTranslationX(0f); 33 | view.setRotation(rotation); 34 | } 35 | 36 | @Override 37 | protected boolean isPagingEnabled() { 38 | return true; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/ScaleInOutTransformer.java: -------------------------------------------------------------------------------- 1 | package com.soubw.jgallery.transformer; 2 | 3 | import android.view.View; 4 | 5 | public class ScaleInOutTransformer extends ABaseTransformer { 6 | 7 | @Override 8 | protected void onTransform(View view, float position) { 9 | view.setPivotX(position < 0 ? 0 : view.getWidth()); 10 | view.setPivotY(view.getHeight() / 2f); 11 | float scale = position < 0 ? 1f + position : 1f - position; 12 | view.setScaleX(scale); 13 | view.setScaleY(scale); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/StackTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class StackTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | view.setTranslationX(position < 0 ? 0f : -view.getWidth() * position); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/TabletTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.graphics.Camera; 20 | import android.graphics.Matrix; 21 | import android.view.View; 22 | 23 | public class TabletTransformer extends ABaseTransformer { 24 | 25 | private static final Matrix OFFSET_MATRIX = new Matrix(); 26 | private static final Camera OFFSET_CAMERA = new Camera(); 27 | private static final float[] OFFSET_TEMP_FLOAT = new float[2]; 28 | 29 | @Override 30 | protected void onTransform(View view, float position) { 31 | final float rotation = (position < 0 ? 30f : -30f) * Math.abs(position); 32 | 33 | view.setTranslationX(getOffsetXForRotation(rotation, view.getWidth(), view.getHeight())); 34 | view.setPivotX(view.getWidth() * 0.5f); 35 | view.setPivotY(0); 36 | view.setRotationY(rotation); 37 | } 38 | 39 | protected static final float getOffsetXForRotation(float degrees, int width, int height) { 40 | OFFSET_MATRIX.reset(); 41 | OFFSET_CAMERA.save(); 42 | OFFSET_CAMERA.rotateY(Math.abs(degrees)); 43 | OFFSET_CAMERA.getMatrix(OFFSET_MATRIX); 44 | OFFSET_CAMERA.restore(); 45 | 46 | OFFSET_MATRIX.preTranslate(-width * 0.5f, -height * 0.5f); 47 | OFFSET_MATRIX.postTranslate(width * 0.5f, height * 0.5f); 48 | OFFSET_TEMP_FLOAT[0] = width; 49 | OFFSET_TEMP_FLOAT[1] = height; 50 | OFFSET_MATRIX.mapPoints(OFFSET_TEMP_FLOAT); 51 | return (width - OFFSET_TEMP_FLOAT[0]) * (degrees > 0.0f ? 1.0f : -1.0f); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/ZoomInTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class ZoomInTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | final float scale = position < 0 ? position + 1f : Math.abs(1f - position); 26 | view.setScaleX(scale); 27 | view.setScaleY(scale); 28 | view.setPivotX(view.getWidth() * 0.5f); 29 | view.setPivotY(view.getHeight() * 0.5f); 30 | view.setAlpha(position < -1f || position > 1f ? 0f : 1f - (scale - 1f)); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/ZoomOutSlideTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class ZoomOutSlideTransformer extends ABaseTransformer { 22 | 23 | private static final float MIN_SCALE = 0.85f; 24 | private static final float MIN_ALPHA = 0.5f; 25 | 26 | @Override 27 | protected void onTransform(View view, float position) { 28 | if (position >= -1 || position <= 1) { 29 | // Modify the default slide transition to shrink the page as well 30 | final float height = view.getHeight(); 31 | final float width = view.getWidth(); 32 | final float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); 33 | final float vertMargin = height * (1 - scaleFactor) / 2; 34 | final float horzMargin = width * (1 - scaleFactor) / 2; 35 | 36 | // Center vertically 37 | view.setPivotY(0.5f * height); 38 | view.setPivotX(0.5f * width); 39 | 40 | if (position < 0) { 41 | view.setTranslationX(horzMargin - vertMargin / 2); 42 | } else { 43 | view.setTranslationX(-horzMargin + vertMargin / 2); 44 | } 45 | 46 | // Scale the page down (between MIN_SCALE and 1) 47 | view.setScaleX(scaleFactor); 48 | view.setScaleY(scaleFactor); 49 | 50 | // Fade the page relative to its size. 51 | view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA)); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jgallery/transformer/ZoomOutTranformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 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 | 17 | package com.soubw.jgallery.transformer; 18 | 19 | import android.view.View; 20 | 21 | public class ZoomOutTranformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | final float scale = 1f + Math.abs(position); 26 | view.setScaleX(scale); 27 | view.setScaleY(scale); 28 | view.setPivotX(view.getWidth() * 0.5f); 29 | view.setPivotY(view.getHeight() * 0.5f); 30 | view.setAlpha(position < -1f || position > 1f ? 0f : 1f - (scale - 1f)); 31 | if(position == -1){ 32 | view.setTranslationX(view.getWidth() * -1); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/jroundprogressbar/JRoundProgressBar.java: -------------------------------------------------------------------------------- 1 | package com.soubw.jroundprogressbar; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.res.TypedArray; 6 | import android.graphics.Canvas; 7 | import android.graphics.Color; 8 | import android.graphics.Paint; 9 | import android.graphics.RectF; 10 | import android.graphics.Typeface; 11 | import android.util.AttributeSet; 12 | import android.view.View; 13 | 14 | import com.soubw.jgallery.R; 15 | 16 | /** 17 | * author:WX_JIN 18 | * email:wangxiaojin@soubw.com 19 | * link: http://soubw.com 20 | */ 21 | public class JRoundProgressBar extends View { 22 | /** 23 | * 画笔对象的引用 24 | */ 25 | private Paint paint; 26 | 27 | /** 28 | * 圆环的颜色 29 | */ 30 | private int roundColor; 31 | 32 | /** 33 | * 圆环进度的颜色 34 | */ 35 | private int roundProgressColor; 36 | 37 | /** 38 | * 中间进度百分比的字符串的颜色 39 | */ 40 | private int textColor; 41 | 42 | /** 43 | * 中间进度百分比的字符串的字体 44 | */ 45 | private float textSize; 46 | 47 | /** 48 | * 圆环的宽度 49 | */ 50 | private float roundWidth; 51 | 52 | /** 53 | * 最大进度 54 | */ 55 | private int max; 56 | 57 | /** 58 | * 当前进度 59 | */ 60 | private int progress; 61 | /** 62 | * 是否显示中间的进度 63 | */ 64 | private boolean textIsDisplayable; 65 | 66 | /** 67 | * 进度的风格,实心或者空心 68 | */ 69 | private int style; 70 | 71 | public static final int STROKE = 0; 72 | public static final int FILL = 1; 73 | public static final int FILL_NO_STROKE = 2; 74 | 75 | public JRoundProgressBar(Context context) { 76 | this(context, null); 77 | } 78 | 79 | public JRoundProgressBar(Context context, AttributeSet attrs) { 80 | this(context, attrs, 0); 81 | } 82 | 83 | public JRoundProgressBar(Context context, AttributeSet attrs, int defStyle) { 84 | super(context, attrs, defStyle); 85 | 86 | paint = new Paint(); 87 | 88 | TypedArray mTypedArray = context.obtainStyledAttributes(attrs, 89 | R.styleable.JRoundProgressBar); 90 | 91 | // 获取自定义属性和默认值 92 | roundColor = mTypedArray.getColor( 93 | R.styleable.JRoundProgressBar_JGallery_JRoundColor, Color.RED); 94 | roundProgressColor = mTypedArray.getColor( 95 | R.styleable.JRoundProgressBar_JGallery_JRoundProgressColor, Color.GREEN); 96 | textColor = mTypedArray.getColor( 97 | R.styleable.JRoundProgressBar_JGallery_JRoundTextColor, Color.GREEN); 98 | textSize = mTypedArray.getDimension( 99 | R.styleable.JRoundProgressBar_JGallery_JRoundTextSize, 15); 100 | roundWidth = mTypedArray.getDimension( 101 | R.styleable.JRoundProgressBar_JGallery_JRoundWidth, 5); 102 | max = mTypedArray.getInteger(R.styleable.JRoundProgressBar_JGallery_JRoundMax, 100); 103 | textIsDisplayable = mTypedArray.getBoolean( 104 | R.styleable.JRoundProgressBar_JGallery_JRoundTextIsDisplayable, true); 105 | style = mTypedArray.getInt(R.styleable.JRoundProgressBar_JGallery_JRoundStyle, 0); 106 | 107 | mTypedArray.recycle(); 108 | } 109 | 110 | @SuppressLint("DrawAllocation") 111 | @Override 112 | protected void onDraw(Canvas canvas) { 113 | super.onDraw(canvas); 114 | 115 | /** 116 | * 画最外层的大圆环 117 | */ 118 | int centreX = getWidth() / 2; // 获取圆心的x坐标 119 | int centreY = getHeight() / 2; // 获取圆心的Y坐标 120 | int radius = (int) (centreX - roundWidth / 2); // 圆环的半径 121 | paint.setColor(roundColor); // 设置圆环的颜色 122 | paint.setStyle(Paint.Style.STROKE); // 设置空心 123 | paint.setStrokeWidth(roundWidth); // 设置圆环的宽度 124 | paint.setAntiAlias(true); // 消除锯齿 125 | canvas.drawCircle(centreX, centreY, radius, paint); // 画出圆环 126 | 127 | // Log.e("log", centre + ""); 128 | 129 | /** 130 | * 画进度百分比 131 | */ 132 | paint.setStrokeWidth(0); 133 | paint.setColor(textColor); 134 | paint.setTextSize(textSize); 135 | paint.setTypeface(Typeface.DEFAULT_BOLD); // 设置字体 136 | int percent = (int) (((float) progress / (float) max) * 100); // 中间的进度百分比,先转换成float在进行除法运算,不然都为0 137 | float textWidth = paint.measureText(percent + "%"); // 测量字体宽度,我们需要根据字体的宽度设置在圆环中间 138 | 139 | if (textIsDisplayable && percent != 0 && style == STROKE) { 140 | canvas.drawText(percent + "%", centreX - textWidth / 2, centreY 141 | + textSize / 2, paint); // 画出进度百分比 142 | } 143 | 144 | /** 145 | * 画圆弧 ,画圆环的进度 146 | */ 147 | 148 | // 设置进度是实心还是空心 149 | paint.setStrokeWidth(roundWidth); // 设置圆环的宽度 150 | paint.setColor(roundProgressColor); // 设置进度的颜色 151 | RectF oval = new RectF(centreX - radius, centreY - radius, centreX 152 | + radius, centreY + radius); // 用于定义的圆弧的形状和大小的界限 153 | 154 | switch (style) { 155 | case STROKE: { 156 | paint.setStyle(Paint.Style.STROKE); 157 | canvas.drawArc(oval, 0, 360 * progress / max, false, paint); // 根据进度画圆弧 158 | break; 159 | } 160 | case FILL: { 161 | paint.setStyle(Paint.Style.FILL_AND_STROKE); 162 | if (progress != 0) 163 | canvas.drawArc(oval, 0, 360 * progress / max, true, paint); // 根据进度画圆弧 164 | break; 165 | } 166 | case FILL_NO_STROKE: { 167 | paint.setStyle(Paint.Style.FILL); 168 | if (progress != 0) 169 | canvas.drawArc(oval, 0, 360 * progress / max, true, paint); // 根据进度画圆弧 170 | break; 171 | } 172 | } 173 | 174 | } 175 | 176 | public synchronized int getMax() { 177 | return max; 178 | } 179 | 180 | /** 181 | * 设置进度的最大值 182 | * 183 | * @param max 184 | */ 185 | public synchronized void setMax(int max) { 186 | if (max < 0) { 187 | throw new IllegalArgumentException("max not less than 0"); 188 | } 189 | this.max = max; 190 | } 191 | 192 | /** 193 | * 获取进度.需要同步 194 | * 195 | * @return 196 | */ 197 | public synchronized int getProgress() { 198 | return progress; 199 | } 200 | 201 | /** 202 | * 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步 刷新界面调用postInvalidate()能在非UI线程刷新 203 | * 204 | * @param progress 205 | */ 206 | public synchronized void setProgress(int progress) { 207 | if (progress < 0) { 208 | throw new IllegalArgumentException("progress not less than 0"); 209 | } 210 | if (progress > max) { 211 | progress = max; 212 | } 213 | if (progress <= max) { 214 | this.progress = progress; 215 | postInvalidate(); 216 | } 217 | 218 | } 219 | 220 | public int getCricleColor() { 221 | return roundColor; 222 | } 223 | 224 | public void setCricleColor(int cricleColor) { 225 | this.roundColor = cricleColor; 226 | } 227 | 228 | public int getCricleProgressColor() { 229 | return roundProgressColor; 230 | } 231 | 232 | public void setCricleProgressColor(int cricleProgressColor) { 233 | this.roundProgressColor = cricleProgressColor; 234 | } 235 | 236 | public int getTextColor() { 237 | return textColor; 238 | } 239 | 240 | public void setTextColor(int textColor) { 241 | this.textColor = textColor; 242 | } 243 | 244 | public float getTextSize() { 245 | return textSize; 246 | } 247 | 248 | public void setTextSize(float textSize) { 249 | this.textSize = textSize; 250 | } 251 | 252 | public float getRoundWidth() { 253 | return roundWidth; 254 | } 255 | 256 | public void setRoundWidth(float roundWidth) { 257 | this.roundWidth = roundWidth; 258 | } 259 | 260 | } 261 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/Compat.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.soubw.photoview; 17 | 18 | import android.annotation.TargetApi; 19 | import android.os.Build; 20 | import android.os.Build.VERSION; 21 | import android.os.Build.VERSION_CODES; 22 | import android.view.MotionEvent; 23 | import android.view.View; 24 | 25 | public class Compat { 26 | 27 | private static final int SIXTY_FPS_INTERVAL = 1000 / 60; 28 | 29 | public static void postOnAnimation(View view, Runnable runnable) { 30 | if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { 31 | postOnAnimationJellyBean(view, runnable); 32 | } else { 33 | view.postDelayed(runnable, SIXTY_FPS_INTERVAL); 34 | } 35 | } 36 | 37 | @TargetApi(16) 38 | private static void postOnAnimationJellyBean(View view, Runnable runnable) { 39 | view.postOnAnimation(runnable); 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 | @SuppressWarnings("deprecation") 50 | @TargetApi(Build.VERSION_CODES.ECLAIR) 51 | private static int getPointerIndexEclair(int action) { 52 | return (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT; 53 | } 54 | 55 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 56 | private static int getPointerIndexHoneyComb(int action) { 57 | return (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/DefaultOnDoubleTapListener.java: -------------------------------------------------------------------------------- 1 | package com.soubw.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 | /** 10 | * Provided default implementation of GestureDetector.OnDoubleTapListener, to be overridden with custom behavior, if needed 11 | *
12 | * To be used via {@link com.soubw.photoview.PhotoViewAttacher#setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener)} 13 | */ 14 | public class DefaultOnDoubleTapListener implements GestureDetector.OnDoubleTapListener { 15 | 16 | private PhotoViewAttacher photoViewAttacher; 17 | 18 | /** 19 | * Default constructor 20 | * 21 | * @param photoViewAttacher PhotoViewAttacher to bind to 22 | */ 23 | public DefaultOnDoubleTapListener(PhotoViewAttacher photoViewAttacher) { 24 | setPhotoViewAttacher(photoViewAttacher); 25 | } 26 | 27 | /** 28 | * Allows to change PhotoViewAttacher within range of single instance 29 | * 30 | * @param newPhotoViewAttacher PhotoViewAttacher to bind to 31 | */ 32 | public void setPhotoViewAttacher(PhotoViewAttacher newPhotoViewAttacher) { 33 | this.photoViewAttacher = newPhotoViewAttacher; 34 | } 35 | 36 | @Override 37 | public boolean onSingleTapConfirmed(MotionEvent e) { 38 | if (this.photoViewAttacher == null) 39 | return false; 40 | 41 | ImageView imageView = photoViewAttacher.getImageView(); 42 | 43 | if (null != photoViewAttacher.getOnPhotoTapListener()) { 44 | final RectF displayRect = photoViewAttacher.getDisplayRect(); 45 | 46 | if (null != displayRect) { 47 | final float x = e.getX(), y = e.getY(); 48 | 49 | // Check to see if the user tapped on the photo 50 | if (displayRect.contains(x, y)) { 51 | 52 | float xResult = (x - displayRect.left) 53 | / displayRect.width(); 54 | float yResult = (y - displayRect.top) 55 | / displayRect.height(); 56 | 57 | photoViewAttacher.getOnPhotoTapListener().onPhotoTap(imageView, xResult, yResult); 58 | return true; 59 | }else{ 60 | photoViewAttacher.getOnPhotoTapListener().onOutsidePhotoTap(); 61 | } 62 | } 63 | } 64 | if (null != photoViewAttacher.getOnViewTapListener()) { 65 | photoViewAttacher.getOnViewTapListener().onViewTap(imageView, e.getX(), e.getY()); 66 | } 67 | 68 | return false; 69 | } 70 | 71 | @Override 72 | public boolean onDoubleTap(MotionEvent ev) { 73 | if (photoViewAttacher == null) 74 | return false; 75 | 76 | try { 77 | float scale = photoViewAttacher.getScale(); 78 | float x = ev.getX(); 79 | float y = ev.getY(); 80 | 81 | if (scale < photoViewAttacher.getMediumScale()) { 82 | photoViewAttacher.setScale(photoViewAttacher.getMediumScale(), x, y, true); 83 | } else if (scale >= photoViewAttacher.getMediumScale() && scale < photoViewAttacher.getMaximumScale()) { 84 | photoViewAttacher.setScale(photoViewAttacher.getMaximumScale(), x, y, true); 85 | } else { 86 | photoViewAttacher.setScale(photoViewAttacher.getMinimumScale(), x, y, true); 87 | } 88 | } catch (ArrayIndexOutOfBoundsException e) { 89 | // Can sometimes happen when getX() and getY() is called 90 | } 91 | 92 | return true; 93 | } 94 | 95 | @Override 96 | public boolean onDoubleTapEvent(MotionEvent e) { 97 | // Wait for the confirmed onDoubleTap() instead 98 | return false; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/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.soubw.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 | public interface IPhotoView { 27 | 28 | float DEFAULT_MAX_SCALE = 3.0f; 29 | float DEFAULT_MID_SCALE = 1.75f; 30 | float DEFAULT_MIN_SCALE = 1.0f; 31 | int DEFAULT_ZOOM_DURATION = 200; 32 | 33 | /** 34 | * Returns true if the PhotoView is set to allow zooming of Photos. 35 | * 36 | * @return true if the PhotoView allows zooming. 37 | */ 38 | boolean canZoom(); 39 | 40 | /** 41 | * Gets the Display Rectangle of the currently displayed Drawable. The Rectangle is relative to 42 | * this View and includes all scaling and translations. 43 | * 44 | * @return - RectF of Displayed Drawable 45 | */ 46 | RectF getDisplayRect(); 47 | 48 | /** 49 | * Sets the Display Matrix of the currently displayed Drawable. The Rectangle is considered 50 | * relative to this View and includes all scaling and translations. 51 | * 52 | * @param finalMatrix target matrix to set PhotoView to 53 | * @return - true if rectangle was applied successfully 54 | */ 55 | boolean setDisplayMatrix(Matrix finalMatrix); 56 | 57 | /** 58 | * Copies the Display Matrix of the currently displayed Drawable. The Rectangle is considered 59 | * relative to this View and includes all scaling and translations. 60 | * 61 | * @param matrix target matrix to copy to 62 | */ 63 | void getDisplayMatrix(Matrix matrix); 64 | 65 | /** 66 | * @return The current minimum scale level. What this value represents depends on the current 67 | * {@link android.widget.ImageView.ScaleType}. 68 | */ 69 | float getMinimumScale(); 70 | 71 | /** 72 | * @return The current medium scale level. What this value represents depends on the current 73 | * {@link android.widget.ImageView.ScaleType}. 74 | */ 75 | float getMediumScale(); 76 | 77 | /** 78 | * @return The current maximum scale level. What this value represents depends on the current 79 | * {@link android.widget.ImageView.ScaleType}. 80 | */ 81 | float getMaximumScale(); 82 | 83 | /** 84 | * Returns the current scale value 85 | * 86 | * @return float - current scale value 87 | */ 88 | float getScale(); 89 | 90 | /** 91 | * Return the current scale type in use by the ImageView. 92 | * 93 | * @return current ImageView.ScaleType 94 | */ 95 | ImageView.ScaleType getScaleType(); 96 | 97 | /** 98 | * Whether to allow the ImageView's parent to intercept the touch event when the photo is scroll 99 | * to it's horizontal edge. 100 | * 101 | * @param allow whether to allow intercepting by parent element or not 102 | */ 103 | void setAllowParentInterceptOnEdge(boolean allow); 104 | 105 | /** 106 | * Sets the minimum scale level. What this value represents depends on the current {@link 107 | * android.widget.ImageView.ScaleType}. 108 | * 109 | * @param minimumScale minimum allowed scale 110 | */ 111 | void setMinimumScale(float minimumScale); 112 | 113 | /** 114 | * Sets the medium scale level. What this value represents depends on the current {@link android.widget.ImageView.ScaleType}. 115 | * 116 | * @param mediumScale medium scale preset 117 | */ 118 | void setMediumScale(float mediumScale); 119 | 120 | /** 121 | * Sets the maximum scale level. What this value represents depends on the current {@link 122 | * android.widget.ImageView.ScaleType}. 123 | * 124 | * @param maximumScale maximum allowed scale preset 125 | */ 126 | void setMaximumScale(float maximumScale); 127 | 128 | /** 129 | * Allows to set all three scale levels at once, so you don't run into problem with setting 130 | * medium/minimum scale before the maximum one 131 | * 132 | * @param minimumScale minimum allowed scale 133 | * @param mediumScale medium allowed scale 134 | * @param maximumScale maximum allowed scale preset 135 | */ 136 | void setScaleLevels(float minimumScale, float mediumScale, float maximumScale); 137 | 138 | /** 139 | * Register a callback to be invoked when the Photo displayed by this view is long-pressed. 140 | * 141 | * @param listener - Listener to be registered. 142 | */ 143 | void setOnLongClickListener(View.OnLongClickListener listener); 144 | 145 | /** 146 | * Register a callback to be invoked when the Matrix has changed for this View. An example would 147 | * be the user panning or scaling the Photo. 148 | * 149 | * @param listener - Listener to be registered. 150 | */ 151 | void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener); 152 | 153 | /** 154 | * Register a callback to be invoked when the Photo displayed by this View is tapped with a 155 | * single tap. 156 | * 157 | * @param listener - Listener to be registered. 158 | */ 159 | void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener); 160 | 161 | /** 162 | * Register a callback to be invoked when the View is tapped with a single tap. 163 | * 164 | * @param listener - Listener to be registered. 165 | */ 166 | void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener); 167 | 168 | /** 169 | * Enables rotation via PhotoView internal functions. 170 | * 171 | * @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360 172 | */ 173 | void setRotationTo(float rotationDegree); 174 | 175 | /** 176 | * Enables rotation via PhotoView internal functions. 177 | * 178 | * @param rotationDegree - Degree to rotate PhotoView by, should be in range 0 to 360 179 | */ 180 | void setRotationBy(float rotationDegree); 181 | 182 | /** 183 | * Changes the current scale to the specified value. 184 | * 185 | * @param scale - Value to scale to 186 | */ 187 | void setScale(float scale); 188 | 189 | /** 190 | * Changes the current scale to the specified value. 191 | * 192 | * @param scale - Value to scale to 193 | * @param animate - Whether to animate the scale 194 | */ 195 | void setScale(float scale, boolean animate); 196 | 197 | /** 198 | * Changes the current scale to the specified value, around the given focal point. 199 | * 200 | * @param scale - Value to scale to 201 | * @param focalX - X Focus Point 202 | * @param focalY - Y Focus Point 203 | * @param animate - Whether to animate the scale 204 | */ 205 | void setScale(float scale, float focalX, float focalY, boolean animate); 206 | 207 | /** 208 | * Controls how the image should be resized or moved to match the size of the ImageView. Any 209 | * scaling or panning will happen within the confines of this {@link 210 | * android.widget.ImageView.ScaleType}. 211 | * 212 | * @param scaleType - The desired scaling mode. 213 | */ 214 | void setScaleType(ImageView.ScaleType scaleType); 215 | 216 | /** 217 | * Allows you to enable/disable the zoom functionality on the ImageView. When disable the 218 | * ImageView reverts to using the FIT_CENTER matrix. 219 | * 220 | * @param zoomable - Whether the zoom functionality is enabled. 221 | */ 222 | void setZoomable(boolean zoomable); 223 | 224 | /** 225 | * Extracts currently visible area to Bitmap object, if there is no image loaded yet or the 226 | * ImageView is already destroyed, returns {@code null} 227 | * 228 | * @return currently visible area as bitmap or null 229 | */ 230 | Bitmap getVisibleRectangleBitmap(); 231 | 232 | /** 233 | * Allows to change zoom transition speed, default value is 200 (PhotoViewAttacher.DEFAULT_ZOOM_DURATION). 234 | * Will default to 200 if provided negative value 235 | * 236 | * @param milliseconds duration of zoom interpolation 237 | */ 238 | void setZoomTransitionDuration(int milliseconds); 239 | 240 | /** 241 | * Will return instance of IPhotoView (eg. PhotoViewAttacher), can be used to provide better 242 | * integration 243 | * 244 | * @return IPhotoView implementation instance if available, null if not 245 | */ 246 | IPhotoView getIPhotoViewImplementation(); 247 | 248 | /** 249 | * Sets custom double tap listener, to intercept default given functions. To reset behavior to 250 | * default, you can just pass in "null" or public field of PhotoViewAttacher.defaultOnDoubleTapListener 251 | * 252 | * @param newOnDoubleTapListener custom OnDoubleTapListener to be set on ImageView 253 | */ 254 | void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener); 255 | 256 | /** 257 | * Will report back about scale changes 258 | * 259 | * @param onScaleChangeListener OnScaleChangeListener instance 260 | */ 261 | void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener); 262 | 263 | /** 264 | * Will report back about fling(single touch) 265 | * 266 | * @param onSingleFlingListener OnSingleFlingListener instance 267 | */ 268 | void setOnSingleFlingListener(PhotoViewAttacher.OnSingleFlingListener onSingleFlingListener); 269 | } 270 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/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.soubw.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 | 29 | public class PhotoView extends ImageView implements IPhotoView { 30 | 31 | private PhotoViewAttacher mAttacher; 32 | 33 | private ScaleType mPendingScaleType; 34 | 35 | public PhotoView(Context context) { 36 | this(context, null); 37 | } 38 | 39 | public PhotoView(Context context, AttributeSet attr) { 40 | this(context, attr, 0); 41 | } 42 | 43 | public PhotoView(Context context, AttributeSet attr, int defStyle) { 44 | super(context, attr, defStyle); 45 | super.setScaleType(ScaleType.MATRIX); 46 | init(); 47 | } 48 | 49 | protected void init() { 50 | if (null == mAttacher || null == mAttacher.getImageView()) { 51 | mAttacher = new PhotoViewAttacher(this); 52 | } 53 | 54 | if (null != mPendingScaleType) { 55 | setScaleType(mPendingScaleType); 56 | mPendingScaleType = null; 57 | } 58 | } 59 | 60 | @Override 61 | public void setRotationTo(float rotationDegree) { 62 | mAttacher.setRotationTo(rotationDegree); 63 | } 64 | 65 | @Override 66 | public void setRotationBy(float rotationDegree) { 67 | mAttacher.setRotationBy(rotationDegree); 68 | } 69 | 70 | @Override 71 | public boolean canZoom() { 72 | return mAttacher.canZoom(); 73 | } 74 | 75 | @Override 76 | public RectF getDisplayRect() { 77 | return mAttacher.getDisplayRect(); 78 | } 79 | 80 | @Override 81 | public void getDisplayMatrix(Matrix matrix) { 82 | mAttacher.getDisplayMatrix(matrix); 83 | } 84 | 85 | @Override 86 | public boolean setDisplayMatrix(Matrix finalRectangle) { 87 | return mAttacher.setDisplayMatrix(finalRectangle); 88 | } 89 | 90 | @Override 91 | public float getMinimumScale() { 92 | return mAttacher.getMinimumScale(); 93 | } 94 | 95 | @Override 96 | public float getMediumScale() { 97 | return mAttacher.getMediumScale(); 98 | } 99 | 100 | @Override 101 | public float getMaximumScale() { 102 | return mAttacher.getMaximumScale(); 103 | } 104 | 105 | @Override 106 | public float getScale() { 107 | return mAttacher.getScale(); 108 | } 109 | 110 | @Override 111 | public ScaleType getScaleType() { 112 | return mAttacher.getScaleType(); 113 | } 114 | 115 | @Override 116 | public Matrix getImageMatrix() { 117 | return mAttacher.getImageMatrix(); 118 | } 119 | 120 | @Override 121 | public void setAllowParentInterceptOnEdge(boolean allow) { 122 | mAttacher.setAllowParentInterceptOnEdge(allow); 123 | } 124 | 125 | @Override 126 | public void setMinimumScale(float minimumScale) { 127 | mAttacher.setMinimumScale(minimumScale); 128 | } 129 | 130 | @Override 131 | public void setMediumScale(float mediumScale) { 132 | mAttacher.setMediumScale(mediumScale); 133 | } 134 | 135 | @Override 136 | public void setMaximumScale(float maximumScale) { 137 | mAttacher.setMaximumScale(maximumScale); 138 | } 139 | 140 | @Override 141 | public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) { 142 | mAttacher.setScaleLevels(minimumScale, mediumScale, maximumScale); 143 | } 144 | 145 | @Override 146 | // setImageBitmap calls through to this method 147 | public void setImageDrawable(Drawable drawable) { 148 | super.setImageDrawable(drawable); 149 | if (null != mAttacher) { 150 | mAttacher.update(); 151 | } 152 | } 153 | 154 | @Override 155 | public void setImageResource(int resId) { 156 | super.setImageResource(resId); 157 | if (null != mAttacher) { 158 | mAttacher.update(); 159 | } 160 | } 161 | 162 | @Override 163 | public void setImageURI(Uri uri) { 164 | super.setImageURI(uri); 165 | if (null != mAttacher) { 166 | mAttacher.update(); 167 | } 168 | } 169 | 170 | @Override 171 | protected boolean setFrame(int l, int t, int r, int b) { 172 | boolean changed = super.setFrame(l, t, r, b); 173 | if (null != mAttacher) { 174 | mAttacher.update(); 175 | } 176 | return changed; 177 | } 178 | 179 | @Override 180 | public void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener) { 181 | mAttacher.setOnMatrixChangeListener(listener); 182 | } 183 | 184 | @Override 185 | public void setOnLongClickListener(OnLongClickListener l) { 186 | mAttacher.setOnLongClickListener(l); 187 | } 188 | 189 | @Override 190 | public void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener) { 191 | mAttacher.setOnPhotoTapListener(listener); 192 | } 193 | 194 | @Override 195 | public void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener) { 196 | mAttacher.setOnViewTapListener(listener); 197 | } 198 | 199 | @Override 200 | public void setScale(float scale) { 201 | mAttacher.setScale(scale); 202 | } 203 | 204 | @Override 205 | public void setScale(float scale, boolean animate) { 206 | mAttacher.setScale(scale, animate); 207 | } 208 | 209 | @Override 210 | public void setScale(float scale, float focalX, float focalY, boolean animate) { 211 | mAttacher.setScale(scale, focalX, focalY, animate); 212 | } 213 | 214 | @Override 215 | public void setScaleType(ScaleType scaleType) { 216 | if (null != mAttacher) { 217 | mAttacher.setScaleType(scaleType); 218 | } else { 219 | mPendingScaleType = scaleType; 220 | } 221 | } 222 | 223 | @Override 224 | public void setZoomable(boolean zoomable) { 225 | mAttacher.setZoomable(zoomable); 226 | } 227 | 228 | @Override 229 | public Bitmap getVisibleRectangleBitmap() { 230 | return mAttacher.getVisibleRectangleBitmap(); 231 | } 232 | 233 | @Override 234 | public void setZoomTransitionDuration(int milliseconds) { 235 | mAttacher.setZoomTransitionDuration(milliseconds); 236 | } 237 | 238 | @Override 239 | public IPhotoView getIPhotoViewImplementation() { 240 | return mAttacher; 241 | } 242 | 243 | @Override 244 | public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) { 245 | mAttacher.setOnDoubleTapListener(newOnDoubleTapListener); 246 | } 247 | 248 | @Override 249 | public void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener) { 250 | mAttacher.setOnScaleChangeListener(onScaleChangeListener); 251 | } 252 | 253 | @Override 254 | public void setOnSingleFlingListener(PhotoViewAttacher.OnSingleFlingListener onSingleFlingListener) { 255 | mAttacher.setOnSingleFlingListener(onSingleFlingListener); 256 | } 257 | 258 | @Override 259 | protected void onDetachedFromWindow() { 260 | mAttacher.cleanup(); 261 | mAttacher = null; 262 | super.onDetachedFromWindow(); 263 | } 264 | 265 | @Override 266 | protected void onAttachedToWindow() { 267 | init(); 268 | super.onAttachedToWindow(); 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/gestures/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.soubw.photoview.gestures; 17 | 18 | import android.content.Context; 19 | import android.view.MotionEvent; 20 | import android.view.VelocityTracker; 21 | import android.view.ViewConfiguration; 22 | 23 | import com.soubw.photoview.log.LogManager; 24 | 25 | public class CupcakeGestureDetector implements GestureDetector { 26 | 27 | protected OnGestureListener mListener; 28 | private static final String LOG_TAG = "CupcakeGestureDetector"; 29 | float mLastTouchX; 30 | float mLastTouchY; 31 | final float mTouchSlop; 32 | final float mMinimumVelocity; 33 | 34 | @Override 35 | public void setOnGestureListener(OnGestureListener listener) { 36 | this.mListener = listener; 37 | } 38 | 39 | public CupcakeGestureDetector(Context context) { 40 | final ViewConfiguration configuration = ViewConfiguration 41 | .get(context); 42 | mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); 43 | mTouchSlop = configuration.getScaledTouchSlop(); 44 | } 45 | 46 | private VelocityTracker mVelocityTracker; 47 | private boolean mIsDragging; 48 | 49 | float getActiveX(MotionEvent ev) { 50 | return ev.getX(); 51 | } 52 | 53 | float getActiveY(MotionEvent ev) { 54 | return ev.getY(); 55 | } 56 | 57 | @Override 58 | public boolean isScaling() { 59 | return false; 60 | } 61 | 62 | @Override 63 | public boolean isDragging() { 64 | return mIsDragging; 65 | } 66 | 67 | @Override 68 | public boolean onTouchEvent(MotionEvent ev) { 69 | switch (ev.getAction()) { 70 | case MotionEvent.ACTION_DOWN: { 71 | mVelocityTracker = VelocityTracker.obtain(); 72 | if (null != mVelocityTracker) { 73 | mVelocityTracker.addMovement(ev); 74 | } else { 75 | LogManager.getLogger().i(LOG_TAG, "Velocity tracker is null"); 76 | } 77 | 78 | mLastTouchX = getActiveX(ev); 79 | mLastTouchY = getActiveY(ev); 80 | mIsDragging = false; 81 | break; 82 | } 83 | 84 | case MotionEvent.ACTION_MOVE: { 85 | final float x = getActiveX(ev); 86 | final float y = getActiveY(ev); 87 | final float dx = x - mLastTouchX, dy = y - mLastTouchY; 88 | 89 | if (!mIsDragging) { 90 | // Use Pythagoras to see if drag length is larger than 91 | // touch slop 92 | mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop; 93 | } 94 | 95 | if (mIsDragging) { 96 | mListener.onDrag(dx, dy); 97 | mLastTouchX = x; 98 | mLastTouchY = y; 99 | 100 | if (null != mVelocityTracker) { 101 | mVelocityTracker.addMovement(ev); 102 | } 103 | } 104 | break; 105 | } 106 | 107 | case MotionEvent.ACTION_CANCEL: { 108 | // Recycle Velocity Tracker 109 | if (null != mVelocityTracker) { 110 | mVelocityTracker.recycle(); 111 | mVelocityTracker = null; 112 | } 113 | break; 114 | } 115 | 116 | case MotionEvent.ACTION_UP: { 117 | if (mIsDragging) { 118 | if (null != mVelocityTracker) { 119 | mLastTouchX = getActiveX(ev); 120 | mLastTouchY = getActiveY(ev); 121 | 122 | // Compute velocity within the last 1000ms 123 | mVelocityTracker.addMovement(ev); 124 | mVelocityTracker.computeCurrentVelocity(1000); 125 | 126 | final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker 127 | .getYVelocity(); 128 | 129 | // If the velocity is greater than minVelocity, call 130 | // listener 131 | if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) { 132 | mListener.onFling(mLastTouchX, mLastTouchY, -vX, 133 | -vY); 134 | } 135 | } 136 | } 137 | 138 | // Recycle Velocity Tracker 139 | if (null != mVelocityTracker) { 140 | mVelocityTracker.recycle(); 141 | mVelocityTracker = null; 142 | } 143 | break; 144 | } 145 | } 146 | 147 | return true; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/gestures/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.soubw.photoview.gestures; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | import android.view.MotionEvent; 21 | 22 | import com.soubw.photoview.Compat; 23 | 24 | 25 | @TargetApi(5) 26 | public class EclairGestureDetector extends CupcakeGestureDetector { 27 | 28 | private static final int INVALID_POINTER_ID = -1; 29 | private int mActivePointerId = INVALID_POINTER_ID; 30 | private int mActivePointerIndex = 0; 31 | 32 | public EclairGestureDetector(Context context) { 33 | super(context); 34 | } 35 | 36 | @Override 37 | float getActiveX(MotionEvent ev) { 38 | try { 39 | return ev.getX(mActivePointerIndex); 40 | } catch (Exception e) { 41 | return ev.getX(); 42 | } 43 | } 44 | 45 | @Override 46 | float getActiveY(MotionEvent ev) { 47 | try { 48 | return ev.getY(mActivePointerIndex); 49 | } catch (Exception e) { 50 | return ev.getY(); 51 | } 52 | } 53 | 54 | @Override 55 | public boolean onTouchEvent(MotionEvent ev) { 56 | final int action = ev.getAction(); 57 | switch (action & MotionEvent.ACTION_MASK) { 58 | case MotionEvent.ACTION_DOWN: 59 | mActivePointerId = ev.getPointerId(0); 60 | break; 61 | case MotionEvent.ACTION_CANCEL: 62 | case MotionEvent.ACTION_UP: 63 | mActivePointerId = INVALID_POINTER_ID; 64 | break; 65 | case MotionEvent.ACTION_POINTER_UP: 66 | // Ignore deprecation, ACTION_POINTER_ID_MASK and 67 | // ACTION_POINTER_ID_SHIFT has same value and are deprecated 68 | // You can have either deprecation or lint target api warning 69 | final int pointerIndex = Compat.getPointerIndex(ev.getAction()); 70 | final int pointerId = ev.getPointerId(pointerIndex); 71 | if (pointerId == mActivePointerId) { 72 | // This was our active pointer going up. Choose a new 73 | // active pointer and adjust accordingly. 74 | final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 75 | mActivePointerId = ev.getPointerId(newPointerIndex); 76 | mLastTouchX = ev.getX(newPointerIndex); 77 | mLastTouchY = ev.getY(newPointerIndex); 78 | } 79 | break; 80 | } 81 | 82 | mActivePointerIndex = ev 83 | .findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId 84 | : 0); 85 | try { 86 | return super.onTouchEvent(ev); 87 | } catch (IllegalArgumentException e) { 88 | // Fix for support lib bug, happening when onDestroy is 89 | return true; 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/gestures/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.soubw.photoview.gestures; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | import android.view.MotionEvent; 21 | import android.view.ScaleGestureDetector; 22 | 23 | 24 | @TargetApi(8) 25 | public class FroyoGestureDetector extends EclairGestureDetector { 26 | 27 | protected final ScaleGestureDetector mDetector; 28 | 29 | public FroyoGestureDetector(Context context) { 30 | super(context); 31 | ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() { 32 | 33 | @Override 34 | public boolean onScale(ScaleGestureDetector detector) { 35 | float scaleFactor = detector.getScaleFactor(); 36 | 37 | if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor)) 38 | return false; 39 | 40 | mListener.onScale(scaleFactor, 41 | detector.getFocusX(), detector.getFocusY()); 42 | return true; 43 | } 44 | 45 | @Override 46 | public boolean onScaleBegin(ScaleGestureDetector detector) { 47 | return true; 48 | } 49 | 50 | @Override 51 | public void onScaleEnd(ScaleGestureDetector detector) { 52 | // NO-OP 53 | } 54 | }; 55 | mDetector = new ScaleGestureDetector(context, mScaleListener); 56 | } 57 | 58 | @Override 59 | public boolean isScaling() { 60 | return mDetector.isInProgress(); 61 | } 62 | 63 | @Override 64 | public boolean onTouchEvent(MotionEvent ev) { 65 | try { 66 | mDetector.onTouchEvent(ev); 67 | return super.onTouchEvent(ev); 68 | } catch (IllegalArgumentException e) { 69 | // Fix for support lib bug, happening when onDestroy is 70 | return true; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/gestures/GestureDetector.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.soubw.photoview.gestures; 17 | 18 | import android.view.MotionEvent; 19 | 20 | public interface GestureDetector { 21 | 22 | boolean onTouchEvent(MotionEvent ev); 23 | 24 | boolean isScaling(); 25 | 26 | boolean isDragging(); 27 | 28 | void setOnGestureListener(OnGestureListener listener); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/gestures/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.soubw.photoview.gestures; 17 | 18 | public interface OnGestureListener { 19 | 20 | void onDrag(float dx, float dy); 21 | 22 | void onFling(float startX, float startY, float velocityX, 23 | float velocityY); 24 | 25 | void onScale(float scaleFactor, float focusX, float focusY); 26 | 27 | } -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/gestures/VersionedGestureDetector.java: -------------------------------------------------------------------------------- 1 | package com.soubw.photoview.gestures; 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 | public final class VersionedGestureDetector { 23 | 24 | public static GestureDetector newInstance(Context context, 25 | OnGestureListener listener) { 26 | final int sdkVersion = Build.VERSION.SDK_INT; 27 | GestureDetector detector; 28 | 29 | if (sdkVersion < Build.VERSION_CODES.ECLAIR) { 30 | detector = new CupcakeGestureDetector(context); 31 | } else if (sdkVersion < Build.VERSION_CODES.FROYO) { 32 | detector = new EclairGestureDetector(context); 33 | } else { 34 | detector = new FroyoGestureDetector(context); 35 | } 36 | 37 | detector.setOnGestureListener(listener); 38 | 39 | return detector; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/log/LogManager.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.soubw.photoview.log; 17 | 18 | import android.util.Log; 19 | 20 | /** 21 | * class that holds the {@link Logger} for this library, defaults to {@link LoggerDefault} to send logs to android {@link Log} 22 | */ 23 | public final class LogManager { 24 | 25 | private static Logger logger = new LoggerDefault(); 26 | 27 | public static void setLogger(Logger newLogger) { 28 | logger = newLogger; 29 | } 30 | 31 | public static Logger getLogger() { 32 | return logger; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/log/Logger.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.soubw.photoview.log; 17 | 18 | /** 19 | * interface for a logger class to replace the static calls to {@link android.util.Log} 20 | */ 21 | public interface Logger { 22 | 23 | int v(String tag, String msg); 24 | 25 | int v(String tag, String msg, Throwable tr); 26 | 27 | int d(String tag, String msg); 28 | 29 | int d(String tag, String msg, Throwable tr); 30 | 31 | int i(String tag, String msg); 32 | 33 | int i(String tag, String msg, Throwable tr); 34 | 35 | int w(String tag, String msg); 36 | 37 | int w(String tag, String msg, Throwable tr); 38 | 39 | int e(String tag, String msg); 40 | 41 | int e(String tag, String msg, Throwable tr); 42 | } 43 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/log/LoggerDefault.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.soubw.photoview.log; 17 | 18 | import android.util.Log; 19 | 20 | /** 21 | * Helper class to redirect {@link LogManager#logger} to {@link Log} 22 | */ 23 | public class LoggerDefault implements Logger { 24 | 25 | @Override 26 | public int v(String tag, String msg) { 27 | return Log.v(tag, msg); 28 | } 29 | 30 | @Override 31 | public int v(String tag, String msg, Throwable tr) { 32 | return Log.v(tag, msg, tr); 33 | } 34 | 35 | @Override 36 | public int d(String tag, String msg) { 37 | return Log.d(tag, msg); 38 | } 39 | 40 | @Override 41 | public int d(String tag, String msg, Throwable tr) { 42 | return Log.d(tag, msg, tr); 43 | } 44 | 45 | @Override 46 | public int i(String tag, String msg) { 47 | return Log.i(tag, msg); 48 | } 49 | 50 | @Override 51 | public int i(String tag, String msg, Throwable tr) { 52 | return Log.i(tag, msg, tr); 53 | } 54 | 55 | @Override 56 | public int w(String tag, String msg) { 57 | return Log.w(tag, msg); 58 | } 59 | 60 | @Override 61 | public int w(String tag, String msg, Throwable tr) { 62 | return Log.w(tag, msg, tr); 63 | } 64 | 65 | @Override 66 | public int e(String tag, String msg) { 67 | return Log.e(tag, msg); 68 | } 69 | 70 | @Override 71 | public int e(String tag, String msg, Throwable tr) { 72 | return Log.e(tag, msg, tr); 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/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.soubw.photoview.scrollerproxy; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | import android.widget.OverScroller; 21 | 22 | @TargetApi(9) 23 | public class GingerScroller extends ScrollerProxy { 24 | 25 | protected final OverScroller mScroller; 26 | 27 | public GingerScroller(Context context) { 28 | mScroller = new OverScroller(context); 29 | } 30 | 31 | @Override 32 | public boolean computeScrollOffset() { 33 | return mScroller.computeScrollOffset(); 34 | } 35 | 36 | @Override 37 | public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, 38 | int overX, int overY) { 39 | mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, overX, overY); 40 | } 41 | 42 | @Override 43 | public void forceFinished(boolean finished) { 44 | mScroller.forceFinished(finished); 45 | } 46 | 47 | @Override 48 | public boolean isFinished() { 49 | return mScroller.isFinished(); 50 | } 51 | 52 | @Override 53 | public int getCurrX() { 54 | return mScroller.getCurrX(); 55 | } 56 | 57 | @Override 58 | public int getCurrY() { 59 | return mScroller.getCurrY(); 60 | } 61 | } -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/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.soubw.photoview.scrollerproxy; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | 21 | @TargetApi(14) 22 | public class IcsScroller extends GingerScroller { 23 | 24 | public IcsScroller(Context context) { 25 | super(context); 26 | } 27 | 28 | @Override 29 | public boolean computeScrollOffset() { 30 | return mScroller.computeScrollOffset(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/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.soubw.photoview.scrollerproxy; 17 | 18 | import android.content.Context; 19 | import android.widget.Scroller; 20 | 21 | public class PreGingerScroller extends ScrollerProxy { 22 | 23 | private final Scroller mScroller; 24 | 25 | public PreGingerScroller(Context context) { 26 | mScroller = new Scroller(context); 27 | } 28 | 29 | @Override 30 | public boolean computeScrollOffset() { 31 | return mScroller.computeScrollOffset(); 32 | } 33 | 34 | @Override 35 | public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, 36 | int overX, int overY) { 37 | mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY); 38 | } 39 | 40 | @Override 41 | public void forceFinished(boolean finished) { 42 | mScroller.forceFinished(finished); 43 | } 44 | 45 | public boolean isFinished() { 46 | return mScroller.isFinished(); 47 | } 48 | 49 | @Override 50 | public int getCurrX() { 51 | return mScroller.getCurrX(); 52 | } 53 | 54 | @Override 55 | public int getCurrY() { 56 | return mScroller.getCurrY(); 57 | } 58 | } -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/photoview/scrollerproxy/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.soubw.photoview.scrollerproxy; 17 | 18 | import android.content.Context; 19 | import android.os.Build.VERSION; 20 | import android.os.Build.VERSION_CODES; 21 | 22 | public abstract class ScrollerProxy { 23 | 24 | public static ScrollerProxy getScroller(Context context) { 25 | if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) { 26 | return new PreGingerScroller(context); 27 | } else if (VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) { 28 | return new GingerScroller(context); 29 | } else { 30 | return new IcsScroller(context); 31 | } 32 | } 33 | 34 | public abstract boolean computeScrollOffset(); 35 | 36 | public abstract void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, 37 | int maxY, int overX, int overY); 38 | 39 | public abstract void forceFinished(boolean finished); 40 | 41 | public abstract boolean isFinished(); 42 | 43 | public abstract int getCurrX(); 44 | 45 | public abstract int getCurrY(); 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/salvage/RecycleBin.java: -------------------------------------------------------------------------------- 1 | package com.soubw.salvage; 2 | 3 | import android.os.Build; 4 | import android.util.SparseArray; 5 | import android.view.View; 6 | 7 | /** 8 | * The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of 9 | * storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the 10 | * start of a layout. By construction, they are displaying current information. At the end of 11 | * layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that 12 | * could potentially be used by the adapter to avoid allocating views unnecessarily. 13 | * 14 | * This class was taken from Android's implementation of {@link android.widget.AbsListView} which 15 | * is copyrighted 2006 The Android Open Source Project. 16 | */ 17 | public class RecycleBin { 18 | /** 19 | * Views that were on screen at the start of layout. This array is populated at the start of 20 | * layout, and at the end of layout all view in activeViews are moved to scrapViews. 21 | * Views in activeViews represent a contiguous range of Views, with position of the first 22 | * view store in mFirstActivePosition. 23 | */ 24 | private View[] activeViews = new View[0]; 25 | private int[] activeViewTypes = new int[0]; 26 | 27 | /** 28 | * Unsorted views that can be used by the adapter as a convert view. 29 | */ 30 | private SparseArray
62 | * Returns the number of types of Views that will be created by 63 | * {@link #getView}. Each type represents a set of views that can be 64 | * converted in {@link #getView}. If the adapter always returns the same 65 | * type of View for all items, this method should return 1. 66 | *
67 | *68 | * This method will only be called when when the adapter is set on the 69 | * the {@link AdapterView}. 70 | *
71 | * 72 | * @return The number of types of Views that will be created by this adapter 73 | */ 74 | public int getViewTypeCount() { 75 | return 1; 76 | } 77 | 78 | /** 79 | * Get the type of View that will be created by {@link #getView} for the specified item. 80 | * 81 | * @param position The position of the item within the adapter's data set whose view type we 82 | * want. 83 | * @return An integer representing the type of View. Two views should share the same type if one 84 | * can be converted to the other in {@link #getView}. Note: Integers must be in the 85 | * range 0 to {@link #getViewTypeCount} - 1. {@link #IGNORE_ITEM_VIEW_TYPE} can 86 | * also be returned. 87 | * @see #IGNORE_ITEM_VIEW_TYPE 88 | */ 89 | @SuppressWarnings("UnusedParameters") // Argument potentially used by subclasses. 90 | public int getItemViewType(int position) { 91 | return AdapterView.ITEM_VIEW_TYPE_IGNORE; 92 | } 93 | 94 | /** 95 | * Get a View that displays the data at the specified position in the data set. You can either 96 | * create a View manually or inflate it from an XML layout file. When the View is inflated, the 97 | * parent View (GridView, ListView...) will apply default layout parameters unless you use 98 | * {@link android.view.LayoutInflater#inflate(int, ViewGroup, boolean)} 99 | * to specify a root view and to prevent attachment to the root. 100 | * 101 | * @param position The position of the item within the adapter's data set of the item whose view 102 | * we want. 103 | * @param convertView The old view to reuse, if possible. Note: You should check that this view 104 | * is non-null and of an appropriate type before using. If it is not possible to convert 105 | * this view to display the correct data, this method can create a new view. 106 | * Heterogeneous lists can specify their number of view types, so that this View is 107 | * always of the right type (see {@link #getViewTypeCount()} and 108 | * {@link #getItemViewType(int)}). 109 | * @param container The parent that this view will eventually be attached to 110 | * @return A View corresponding to the data at the specified position. 111 | */ 112 | public abstract View getView(int position, View convertView, ViewGroup container); 113 | 114 | public abstract void removeItemView(int position); 115 | } 116 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/utils/JFile.java: -------------------------------------------------------------------------------- 1 | package com.soubw.utils; 2 | 3 | import android.content.Context; 4 | import android.os.Environment; 5 | 6 | import com.soubw.config.JConfig; 7 | 8 | import java.io.File; 9 | 10 | /** 11 | * author: WX_JIN 12 | * email: wangxiaojin@soubw.com 13 | */ 14 | public class JFile { 15 | 16 | public static String initDirectory(Context context) { 17 | String baseDir; 18 | if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 19 | baseDir = Environment.getExternalStorageDirectory() + File.separator+ JConfig.baseName+ File.separator; 20 | }else { 21 | baseDir = context.getCacheDir().getAbsolutePath() + File.separator+ JConfig.baseName+ File.separator; 22 | } 23 | 24 | File basedir = new File(baseDir); 25 | if(!basedir.exists()) { 26 | basedir.mkdirs(); 27 | } 28 | JConfig.basePath = baseDir; 29 | return baseDir; 30 | } 31 | 32 | public static boolean fileIsExist(String url){ 33 | File dir = new File(url); 34 | if(dir.exists()) 35 | return true; 36 | return false; 37 | } 38 | 39 | public static File getCacheFile(){ 40 | File cachedir = new File(JConfig.basePath+ File.separator+ JConfig.cacheName+ File.separator); 41 | if(!cachedir.exists()) { 42 | cachedir.mkdirs(); 43 | } 44 | return cachedir; 45 | } 46 | 47 | public static String getDownPath(){ 48 | String path = JConfig.basePath+ File.separator+ JConfig.downPath+ File.separator; 49 | File file = new File(path); 50 | if(!file.exists()) { 51 | file.mkdirs(); 52 | } 53 | return path; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/utils/JMD5.java: -------------------------------------------------------------------------------- 1 | package com.soubw.utils; 2 | 3 | import java.security.MessageDigest; 4 | 5 | /** 6 | * author: WX_JIN 7 | * email: wangxiaojin@soubw.com 8 | */ 9 | public class JMD5 { 10 | 11 | public final static String MD5(String s) { 12 | char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 13 | try { 14 | byte[] btInput = s.getBytes(); 15 | MessageDigest mdInst = MessageDigest.getInstance("MD5"); 16 | mdInst.update(btInput); 17 | byte[] md = mdInst.digest(); 18 | int j = md.length; 19 | char str[] = new char[j * 2]; 20 | int k = 0; 21 | for (int i = 0; i < j; i++) { 22 | byte byte0 = md[i]; 23 | str[k++] = hexDigits[byte0 >>> 4 & 0xf]; 24 | str[k++] = hexDigits[byte0 & 0xf]; 25 | } 26 | return new String(str); 27 | } catch (Exception e) { 28 | e.printStackTrace(); 29 | return null; 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/utils/JViewShot.java: -------------------------------------------------------------------------------- 1 | package com.soubw.utils; 2 | 3 | import android.graphics.Bitmap; 4 | import android.view.View; 5 | 6 | import java.io.File; 7 | import java.io.FileNotFoundException; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | /** 11 | * author:WX_JIN 12 | * email:wangxiaojin@soubw.com 13 | * link: http://soubw.com 14 | */ 15 | public class JViewShot { 16 | 17 | /** 18 | * 截屏 19 | * @param v 需要截屏的View 20 | * @return 返回截屏的Bitmap 21 | */ 22 | public static Bitmap shotView(View v){ 23 | v.clearFocus(); 24 | v.setPressed(false); 25 | boolean willNotCache = v.willNotCacheDrawing(); 26 | v.setWillNotCacheDrawing(false); 27 | 28 | int color = v.getDrawingCacheBackgroundColor(); 29 | v.setDrawingCacheBackgroundColor(0); 30 | 31 | if (color != 0) { 32 | v.destroyDrawingCache(); 33 | } 34 | v.buildDrawingCache(); 35 | Bitmap cacheBitmap = v.getDrawingCache(); 36 | if (cacheBitmap == null) { 37 | return null; 38 | } 39 | Bitmap bitmap = Bitmap.createBitmap(cacheBitmap); 40 | 41 | v.destroyDrawingCache(); 42 | v.setWillNotCacheDrawing(willNotCache); 43 | v.setDrawingCacheBackgroundColor(color); 44 | return bitmap; 45 | /* //View是你需要截图的View 46 | v.setDrawingCacheEnabled(true); 47 | v.buildDrawingCache(); 48 | Bitmap b1 = v.getDrawingCache(); 49 | 50 | //去掉标题栏 51 | //Bitmap b = Bitmap.createBitmap(b1, 0, 25, 320, 455); 52 | Bitmap b = Bitmap.createBitmap(b1); 53 | v.destroyDrawingCache(); 54 | v.setDrawingCacheEnabled(false); 55 | return b; */ 56 | } 57 | 58 | 59 | //保存到sdcard 60 | public static void savePic(Bitmap b,String strFileName){ 61 | File f = new File("/sdcard/" + strFileName + ".png"); 62 | try { 63 | f.createNewFile(); 64 | } catch (IOException e) { 65 | } 66 | FileOutputStream fos = null; 67 | try { 68 | fos = new FileOutputStream(f); 69 | if (null != fos) 70 | { 71 | b.compress(Bitmap.CompressFormat.PNG, 100, fos); 72 | fos.flush(); 73 | fos.close(); 74 | } 75 | } catch (FileNotFoundException e) { 76 | e.printStackTrace(); 77 | } catch (IOException e) { 78 | e.printStackTrace(); 79 | } finally { 80 | if(b != null) { 81 | b.recycle(); 82 | } 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/utils/OkHttpProgress.java: -------------------------------------------------------------------------------- 1 | package com.soubw.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | 8 | import okhttp3.Call; 9 | import okhttp3.Callback; 10 | import okhttp3.Interceptor; 11 | import okhttp3.MediaType; 12 | import okhttp3.OkHttpClient; 13 | import okhttp3.Request; 14 | import okhttp3.Response; 15 | import okhttp3.ResponseBody; 16 | import okio.Buffer; 17 | import okio.BufferedSource; 18 | import okio.ForwardingSource; 19 | import okio.Okio; 20 | import okio.Source; 21 | 22 | /** 23 | * author:WX_JIN 24 | * email:wangxiaojin@soubw.com 25 | * link: http://soubw.com 26 | */ 27 | public class OkHttpProgress { 28 | 29 | public static void startUrl(String url, final String fileName, final ProgressListener progressListener) { 30 | 31 | Request request = new Request.Builder() 32 | .url(url) 33 | .build(); 34 | 35 | 36 | OkHttpClient client = new OkHttpClient.Builder() 37 | .addNetworkInterceptor(new Interceptor() { 38 | @Override 39 | public Response intercept(Chain chain) throws IOException { 40 | Response originalResponse = chain.proceed(chain.request()); 41 | return originalResponse.newBuilder() 42 | //.body(new ProgressResponseBody(originalResponse.body(), progressListener)) 43 | .build(); 44 | } 45 | }) 46 | .build(); 47 | 48 | try { 49 | client.newCall(request).enqueue(new Callback() { 50 | @Override 51 | public void onFailure(Call call, IOException e) { 52 | progressListener.onError(e.getMessage()); 53 | } 54 | 55 | @Override 56 | public void onResponse(Call call, Response response) throws IOException { 57 | InputStream is = null; 58 | byte[] buf = new byte[2048]; 59 | int len = 0; 60 | FileOutputStream fos = null; 61 | try { 62 | is = response.body().byteStream(); 63 | long total = response.body().contentLength(); 64 | File file = new File(JFile.getDownPath(), fileName); 65 | fos = new FileOutputStream(file); 66 | long sum = 0; 67 | while ((len = is.read(buf)) != -1) { 68 | fos.write(buf, 0, len); 69 | sum += len; 70 | progressListener.update(sum, total, false); 71 | } 72 | if (sum == total) { 73 | progressListener.update(sum, total, true); 74 | progressListener.onLoad(file.getPath(), fileName); 75 | } 76 | fos.flush(); 77 | } catch (Exception e) { 78 | progressListener.onError(e.getMessage()); 79 | } finally { 80 | try { 81 | if (is != null) 82 | is.close(); 83 | } catch (IOException e) { 84 | } 85 | try { 86 | if (fos != null) 87 | fos.close(); 88 | } catch (IOException e) { 89 | } 90 | } 91 | } 92 | }); 93 | 94 | /* Response response = client.newCall(request).execute(); 95 | if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); 96 | 97 | System.out.println(response.body().string());*/ 98 | } catch (Exception e) { 99 | System.out.print(e.getMessage()); 100 | } 101 | 102 | } 103 | 104 | 105 | private static class ProgressResponseBody extends ResponseBody { 106 | 107 | private final ResponseBody responseBody; 108 | private final ProgressListener progressListener; 109 | private BufferedSource bufferedSource; 110 | 111 | public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) { 112 | this.responseBody = responseBody; 113 | this.progressListener = progressListener; 114 | } 115 | 116 | @Override 117 | public MediaType contentType() { 118 | return responseBody.contentType(); 119 | } 120 | 121 | @Override 122 | public long contentLength() { 123 | return responseBody.contentLength(); 124 | } 125 | 126 | @Override 127 | public BufferedSource source() { 128 | if (bufferedSource == null) { 129 | bufferedSource = Okio.buffer(source(responseBody.source())); 130 | } 131 | return bufferedSource; 132 | } 133 | 134 | private Source source(Source source) { 135 | return new ForwardingSource(source) { 136 | long totalBytesRead = 0L; 137 | 138 | @Override 139 | public long read(Buffer sink, long byteCount) throws IOException { 140 | long bytesRead = super.read(sink, byteCount); 141 | // read() returns the number of bytes read, or -1 if this source is exhausted. 142 | totalBytesRead += bytesRead != -1 ? bytesRead : 0; 143 | progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1); 144 | return bytesRead; 145 | } 146 | }; 147 | } 148 | } 149 | 150 | public interface ProgressListener { 151 | void update(long bytesRead, long contentLength, boolean done); 152 | 153 | void onLoad(String path, String name); 154 | 155 | void onError(String errorMessage); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/view/BaseGestureDetector.java: -------------------------------------------------------------------------------- 1 | package com.soubw.view; 2 | 3 | import android.content.Context; 4 | import android.view.MotionEvent; 5 | 6 | /** 7 | * Created by zhy on 15/5/12. 8 | */ 9 | public abstract class BaseGestureDetector 10 | { 11 | 12 | protected boolean mGestureInProgress; 13 | 14 | protected MotionEvent mPreMotionEvent; 15 | protected MotionEvent mCurrentMotionEvent; 16 | 17 | protected Context mContext; 18 | 19 | public BaseGestureDetector(Context context) 20 | { 21 | mContext = context; 22 | } 23 | 24 | 25 | public boolean onToucEvent(MotionEvent event) 26 | { 27 | 28 | if (!mGestureInProgress) 29 | { 30 | handleStartProgressEvent(event); 31 | } else 32 | { 33 | handleInProgressEvent(event); 34 | } 35 | 36 | return true; 37 | 38 | } 39 | 40 | protected abstract void handleInProgressEvent(MotionEvent event); 41 | 42 | protected abstract void handleStartProgressEvent(MotionEvent event); 43 | 44 | protected abstract void updateStateByEvent(MotionEvent event); 45 | 46 | protected void resetState() 47 | { 48 | if (mPreMotionEvent != null) 49 | { 50 | mPreMotionEvent.recycle(); 51 | mPreMotionEvent = null; 52 | } 53 | if (mCurrentMotionEvent != null) 54 | { 55 | mCurrentMotionEvent.recycle(); 56 | mCurrentMotionEvent = null; 57 | } 58 | mGestureInProgress = false; 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/view/JImageView.java: -------------------------------------------------------------------------------- 1 | package com.soubw.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.View; 6 | 7 | import com.soubw.jgallery.R; 8 | import com.soubw.jgallery.config.DataType; 9 | 10 | /** 11 | * author:WX_JIN 12 | * email:wangxiaojin@soubw.com 13 | * link: http://soubw.com 14 | */ 15 | public class JImageView extends JView { 16 | 17 | public JImageView(Context context) { 18 | super(context); 19 | } 20 | 21 | public JImageView(Context context, AttributeSet attrs) { 22 | super(context, attrs); 23 | } 24 | 25 | public JImageView(Context context, AttributeSet attrs, int defStyleAttr) { 26 | super(context, attrs, defStyleAttr); 27 | } 28 | 29 | @Override 30 | protected void loadView(View view) { 31 | 32 | } 33 | 34 | @Override 35 | protected int layoutId() { 36 | return R.layout.jimageview; 37 | } 38 | 39 | @Override 40 | protected void onViewClick(View v) { 41 | 42 | } 43 | 44 | @Override 45 | protected void onViewLongClick(View v) { 46 | 47 | } 48 | 49 | @Override 50 | protected void loadFileSuccess(String path, String name) { 51 | 52 | } 53 | 54 | @Override 55 | protected void loadError(String error) { 56 | 57 | } 58 | 59 | 60 | @Override 61 | protected void preDownLoad() { 62 | 63 | } 64 | 65 | @Override 66 | protected void refreshStatus() { 67 | ivImage.setVisibility(View.INVISIBLE); 68 | jRoundProgressBar.setVisibility(View.INVISIBLE); 69 | layoutOver.setVisibility(View.INVISIBLE); 70 | if(dataType.equals(DataType.NORMAL_IMAGE) || dataType.equals(DataType.GIF_IMAGE)){ 71 | ivImage.setVisibility(View.VISIBLE); 72 | }else if(dataType.equals(DataType.OVER_IMAGE)){ 73 | layoutOver.setVisibility(View.VISIBLE); 74 | } 75 | 76 | } 77 | 78 | @Override 79 | protected void showImage(){ 80 | /* if (dataType.equals(DataType.NORMAL_IMAGE) ){ 81 | if (defaultImage == -1) 82 | Glide.with(context).load(listData.get(position)).centerCrop().crossFade().into(ivImage); 83 | else 84 | Glide.with(context).load(listData.get(position)).centerCrop().crossFade().placeholder(defaultImage).into(ivImage); 85 | }else if(dataType.equals(DataType.GIF_IMAGE)){ 86 | if (defaultImage == -1) 87 | Glide.with(context).load(listData.get(position)).asGif().diskCacheStrategy(DiskCacheStrategy.SOURCE).into(ivImage); 88 | else 89 | Glide.with(context).load(listData.get(position)).asGif().diskCacheStrategy(DiskCacheStrategy.SOURCE).placeholder(defaultImage).into(ivImage); 90 | }else if(dataType.equals(DataType.OVER_IMAGE)){ 91 | layoutOver.setVisibility(View.VISIBLE); 92 | } 93 | if (thumbnail != null && defaultImage != -1) 94 | Glide.with(context).load(thumbnail).centerCrop().crossFade().placeholder(defaultImage).into(ivImage); 95 | else if (thumbnail != null) 96 | Glide.with(context).load(thumbnail).centerCrop().crossFade().into(ivImage);*/ 97 | 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/view/JVideoView.java: -------------------------------------------------------------------------------- 1 | package com.soubw.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.PixelFormat; 6 | import android.media.MediaMetadataRetriever; 7 | import android.media.MediaPlayer; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | import android.widget.ImageView; 11 | import android.widget.ProgressBar; 12 | import android.widget.VideoView; 13 | 14 | import com.bumptech.glide.Glide; 15 | import com.soubw.jgallery.R; 16 | import com.soubw.jgallery.config.DataType; 17 | import com.soubw.utils.JFile; 18 | 19 | /** 20 | * author:WX_JIN 21 | * email:wangxiaojin@soubw.com 22 | * link: http://soubw.com 23 | */ 24 | public class JVideoView extends JView { 25 | 26 | private VideoView videoView; 27 | private ImageView ivPlayVideo; 28 | private ProgressBar progressBar; 29 | 30 | private int currentPosition = -1; 31 | private boolean isCurrentSelected = false; 32 | private MediaMetadataRetriever mediaMetadataRetriever; 33 | 34 | public JVideoView(Context context) { 35 | super(context); 36 | } 37 | 38 | public JVideoView(Context context, AttributeSet attrs) { 39 | super(context, attrs); 40 | } 41 | 42 | public JVideoView(Context context, AttributeSet attrs, int defStyleAttr) { 43 | super(context, attrs, defStyleAttr); 44 | } 45 | 46 | @Override 47 | protected void loadView(View view) { 48 | mediaMetadataRetriever = new MediaMetadataRetriever(); 49 | this.ivPlayVideo = (ImageView) view.findViewById(R.id.ivPlayVideo); 50 | this.ivPlayVideo.setOnClickListener(new OnClickListener() { 51 | @Override 52 | public void onClick(View v) { 53 | startVideo(); 54 | } 55 | }); 56 | this.videoView = (VideoView) view.findViewById(R.id.videoView); 57 | this.videoView.setZOrderOnTop(true); 58 | this.videoView.getHolder().setFormat(PixelFormat.TRANSPARENT); 59 | this.progressBar = (ProgressBar) view.findViewById(R.id.progressBar); 60 | this.videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 61 | @Override 62 | public void onPrepared(MediaPlayer mp) { 63 | progressBar.setVisibility(View.INVISIBLE); 64 | } 65 | }); 66 | this.videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 67 | @Override 68 | public void onCompletion(MediaPlayer mp) { 69 | ivPlayVideo.setVisibility(View.VISIBLE); 70 | } 71 | }); 72 | } 73 | 74 | @Override 75 | protected int layoutId() { 76 | return R.layout.jvideoview; 77 | } 78 | 79 | @Override 80 | protected void onViewClick(View v) { 81 | if(!pauseVideo()){ 82 | if (onJGalleryClickListener != null){ 83 | onJGalleryClickListener.OnClick(v,position); 84 | } 85 | } 86 | } 87 | 88 | @Override 89 | protected void onViewLongClick(View v) { 90 | if (onJGalleryLongClickListener != null){ 91 | onJGalleryLongClickListener.OnLongClick(v,position); 92 | } 93 | } 94 | 95 | @Override 96 | protected void loadFileSuccess(String path, String name) { 97 | dataType = DataType.LOCAL_VIDEO; 98 | url = path; 99 | refreshStatus(); 100 | if(onJGalleryLoadListener !=null){ 101 | onJGalleryLoadListener.onLoad(position,path, name); 102 | } 103 | if (isCurrentSelected){ 104 | startVideo(); 105 | } 106 | } 107 | 108 | @Override 109 | protected void loadError(String error) { 110 | dataType = DataType.OVER_VIDEO; 111 | refreshStatus(); 112 | } 113 | 114 | @Override 115 | protected void preDownLoad() { 116 | ivPlayVideo.setVisibility(View.INVISIBLE); 117 | } 118 | 119 | @Override 120 | protected void refreshStatus() { 121 | ivImage.setVisibility(View.INVISIBLE); 122 | jRoundProgressBar.setVisibility(View.INVISIBLE); 123 | progressBar.setVisibility(View.INVISIBLE); 124 | ivPlayVideo.setVisibility(View.INVISIBLE); 125 | layoutOver.setVisibility(View.INVISIBLE); 126 | if(dataType.equals(DataType.NET_VIDEO)){ 127 | ivPlayVideo.setVisibility(View.VISIBLE); 128 | showImage(); 129 | } else if(dataType.equals(DataType.LOCAL_VIDEO)){ 130 | if (!JFile.fileIsExist((String) url)){ 131 | dataType = DataType.OVER_VIDEO; 132 | refreshStatus(); 133 | return; 134 | } 135 | ivPlayVideo.setVisibility(View.VISIBLE); 136 | videoView.setVideoPath((String) url); 137 | mediaMetadataRetriever.setDataSource((String) url); 138 | showImage(); 139 | }else if(dataType.equals(DataType.OVER_VIDEO)){ 140 | layoutOver.setVisibility(View.VISIBLE); 141 | } 142 | } 143 | 144 | @Override 145 | protected void showImage(){ 146 | if (thumbnail != null && defaultImage != -1){ 147 | ivImage.setVisibility(View.VISIBLE); 148 | Glide.with(context).load(thumbnail).centerCrop().crossFade().placeholder(defaultImage).into(ivImage); 149 | } 150 | else if (thumbnail != null){ 151 | ivImage.setVisibility(View.VISIBLE); 152 | Glide.with(context).load(thumbnail).centerCrop().crossFade().into(ivImage); 153 | } 154 | } 155 | 156 | public void startVideo(){ 157 | isCurrentSelected = true; 158 | if (ivImage.getVisibility() == View.INVISIBLE){ 159 | return; 160 | } 161 | if (dataType.equals(DataType.LOCAL_VIDEO)){ 162 | ivImage.setVisibility(View.INVISIBLE); 163 | videoView.setVisibility(View.VISIBLE); 164 | if (currentPosition != -1){ 165 | videoView.seekTo(currentPosition); 166 | } 167 | videoView.start(); 168 | if (!videoView.isPlaying()){ 169 | progressBar.setVisibility(View.VISIBLE); 170 | } 171 | ivPlayVideo.setVisibility(View.INVISIBLE); 172 | } else if(dataType.equals(DataType.NET_VIDEO)){ 173 | downLoad(); 174 | } 175 | } 176 | 177 | public boolean pauseVideo(){ 178 | isCurrentSelected = false; 179 | if (videoView.isPlaying()){ 180 | currentPosition = videoView.getCurrentPosition(); 181 | videoView.pause(); 182 | // Bitmap bitmap = mediaMetadataRetriever.getFrameAtTime(currentPosition * 1000, 183 | // MediaMetadataRetriever.OPTION_NEXT_SYNC); 184 | Bitmap bitmap = null; 185 | if (bitmap != null) { 186 | ivImage.setVisibility(View.VISIBLE); 187 | ivImage.setImageBitmap(bitmap); 188 | }else{ 189 | showImage(); 190 | } 191 | videoView.setVisibility(View.INVISIBLE); 192 | ivPlayVideo.setVisibility(View.VISIBLE); 193 | return true; 194 | } 195 | return false; 196 | } 197 | 198 | } 199 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/view/JView.java: -------------------------------------------------------------------------------- 1 | package com.soubw.view; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.os.Message; 8 | import android.util.AttributeSet; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.widget.FrameLayout; 12 | import android.widget.ImageView; 13 | import android.widget.LinearLayout; 14 | 15 | import com.soubw.cache.ACache; 16 | import com.soubw.jgallery.R; 17 | import com.soubw.jgallery.config.DataType; 18 | import com.soubw.jgallery.listener.OnJGalleryClickListener; 19 | import com.soubw.jgallery.listener.OnJGalleryLoadListener; 20 | import com.soubw.jgallery.listener.OnJGalleryLongClickListener; 21 | import com.soubw.jroundprogressbar.JRoundProgressBar; 22 | import com.soubw.utils.JFile; 23 | import com.soubw.utils.JMD5; 24 | import com.soubw.utils.OkHttpProgress; 25 | 26 | import java.util.concurrent.ExecutorService; 27 | import java.util.concurrent.Executors; 28 | 29 | /** 30 | * author:WX_JIN 31 | * email:wangxiaojin@soubw.com 32 | * link: http://soubw.com 33 | */ 34 | public abstract class JView extends FrameLayout { 35 | 36 | private static final int MESSAGE_PROGRESS = 1; 37 | private static final int MESSAGE_FILE = 2; 38 | private static final int MESSAGE_ERROR = 3; 39 | 40 | protected OnJGalleryClickListener onJGalleryClickListener; 41 | protected OnJGalleryLongClickListener onJGalleryLongClickListener; 42 | protected OnJGalleryLoadListener onJGalleryLoadListener; 43 | protected JRoundProgressBar jRoundProgressBar; 44 | protected ImageView ivImage; 45 | protected LinearLayout layoutOver; 46 | 47 | protected Object url; 48 | protected Object dataType; 49 | protected Object thumbnail; 50 | protected int position; 51 | protected Context context; 52 | protected int defaultImage = -1; 53 | private ExecutorService executorService = Executors.newFixedThreadPool(5); 54 | protected ACache aCache; 55 | 56 | public JView(Context context) { 57 | this(context, null); 58 | } 59 | 60 | public JView(Context context, AttributeSet attrs) { 61 | this(context, attrs,0); 62 | } 63 | 64 | public JView(Context context, AttributeSet attrs, int defStyleAttr) { 65 | super(context, attrs, defStyleAttr); 66 | this.context = context; 67 | initView(); 68 | aCache = ACache.get(JFile.getCacheFile()); 69 | } 70 | 71 | private void initView() { 72 | View view = LayoutInflater.from(context).inflate(layoutId(), this, true); 73 | view.setOnClickListener(new OnClickListener() { 74 | @Override 75 | public void onClick(View v) { 76 | onViewClick(v); 77 | } 78 | }); 79 | view.setOnLongClickListener(new OnLongClickListener() { 80 | @Override 81 | public boolean onLongClick(View v) { 82 | onViewLongClick(v); 83 | return false; 84 | } 85 | }); 86 | this.layoutOver = (LinearLayout) view.findViewById(R.id.layoutOver); 87 | this.ivImage = (ImageView) view.findViewById(R.id.ivImage); 88 | this.jRoundProgressBar = (JRoundProgressBar) view.findViewById(R.id.jRoundProgressBar); 89 | loadView(view); 90 | } 91 | 92 | 93 | 94 | protected void downLoad(){ 95 | preDownLoad(); 96 | jRoundProgressBar.setVisibility(View.VISIBLE); 97 | final OkHttpProgress.ProgressListener progressListener = new OkHttpProgress.ProgressListener() { 98 | @Override 99 | public void update(long bytesRead,long contentLength, boolean done) { 100 | if (handler != null) { 101 | Message message = handler.obtainMessage(); 102 | message.what = MESSAGE_PROGRESS; 103 | message.arg1 = (int) bytesRead; 104 | message.arg2 = (int) contentLength; 105 | handler.sendMessage(message); 106 | } 107 | } 108 | 109 | @Override 110 | public void onLoad(String path, String name) { 111 | if (handler != null) { 112 | Message message = handler.obtainMessage(); 113 | message.what = MESSAGE_FILE; 114 | Bundle bundle = new Bundle(); 115 | bundle.putString("path",path); 116 | bundle.putString("name",name); 117 | message.setData(bundle); 118 | handler.sendMessage(message); 119 | } 120 | } 121 | 122 | @Override 123 | public void onError(String errorMessage) { 124 | if (handler != null) { 125 | Message message = handler.obtainMessage(); 126 | message.what = MESSAGE_ERROR; 127 | Bundle bundle = new Bundle(); 128 | bundle.putString("error",errorMessage); 129 | message.setData(bundle); 130 | handler.sendMessage(message); 131 | } 132 | } 133 | }; 134 | final String fileName = JMD5.MD5((String) url); 135 | if (aCache.getAsString(fileName)!= null ){ 136 | loadFileSuccess(aCache.getAsString(fileName), fileName); 137 | return; 138 | } 139 | executorService.execute(new Runnable() { 140 | @Override 141 | public void run() { 142 | OkHttpProgress.startUrl((String) url,fileName,progressListener); 143 | } 144 | }); 145 | 146 | } 147 | 148 | protected Handler handler = new Handler(Looper.getMainLooper()){ 149 | 150 | @Override 151 | public void handleMessage(Message msg) { 152 | super.handleMessage(msg); 153 | Bundle bundle; 154 | switch (msg.what) { 155 | case MESSAGE_PROGRESS: 156 | refreshProgress(msg.arg1*100/msg.arg2); 157 | break; 158 | case MESSAGE_FILE: 159 | bundle= msg.getData(); 160 | aCache.put(bundle.getString("name"),bundle.getString("path")); 161 | loadFileSuccess(bundle.getString("path"), bundle.getString("name")); 162 | break; 163 | case MESSAGE_ERROR: 164 | bundle= msg.getData(); 165 | loadError(bundle.getString("error")); 166 | break; 167 | default: 168 | break; 169 | } 170 | } 171 | }; 172 | protected abstract int layoutId(); 173 | protected abstract void loadView(View v); 174 | protected abstract void onViewClick(View v); 175 | protected abstract void onViewLongClick(View v); 176 | protected abstract void loadFileSuccess(String path, String name); 177 | protected abstract void loadError(String error); 178 | protected abstract void preDownLoad(); 179 | protected abstract void refreshStatus(); 180 | protected abstract void showImage(); 181 | 182 | private void refreshProgress(int progress) { 183 | if(this.jRoundProgressBar.getVisibility() != View.VISIBLE && dataType.equals(DataType.NET_VIDEO)) 184 | this.jRoundProgressBar.setVisibility(View.VISIBLE); 185 | this.jRoundProgressBar.setProgress(progress); 186 | } 187 | 188 | public void setData(Object o, Object dt,Object t,int di, int pos){ 189 | this.url = o; 190 | this.dataType = dt; 191 | this.thumbnail = t; 192 | this.position = pos; 193 | this.defaultImage = di; 194 | refreshStatus(); 195 | } 196 | 197 | public void setJGalleryClickListener(OnJGalleryClickListener listener) { 198 | this.onJGalleryClickListener = listener; 199 | } 200 | 201 | public void setJGalleryLongClickListener(OnJGalleryLongClickListener listener) { 202 | this.onJGalleryLongClickListener = listener; 203 | } 204 | 205 | public void setJGalleryLoadListener(OnJGalleryLoadListener listener) { 206 | this.onJGalleryLoadListener = listener; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/view/LargeImageView.java: -------------------------------------------------------------------------------- 1 | package com.soubw.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.BitmapRegionDecoder; 7 | import android.graphics.Canvas; 8 | import android.graphics.Rect; 9 | import android.util.AttributeSet; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | 16 | /** 17 | * Created by zhy on 15/5/16. 18 | */ 19 | public class LargeImageView extends View { 20 | private BitmapRegionDecoder mDecoder; 21 | /** 22 | * 图片的宽度和高度 23 | */ 24 | private int mImageWidth, mImageHeight; 25 | /** 26 | * 绘制的区域 27 | */ 28 | private volatile Rect mRect = new Rect(); 29 | 30 | private MoveGestureDetector mDetector; 31 | 32 | 33 | private static final BitmapFactory.Options options = new BitmapFactory.Options(); 34 | 35 | static { 36 | options.inPreferredConfig = Bitmap.Config.RGB_565; 37 | } 38 | 39 | public void setInputStream(InputStream is) { 40 | try { 41 | mDecoder = BitmapRegionDecoder.newInstance(is, false); 42 | BitmapFactory.Options tmpOptions = new BitmapFactory.Options(); 43 | // Grab the bounds for the scene dimensions 44 | tmpOptions.inJustDecodeBounds = true; 45 | BitmapFactory.decodeStream(is, null, tmpOptions); 46 | mImageWidth = tmpOptions.outWidth; 47 | mImageHeight = tmpOptions.outHeight; 48 | 49 | requestLayout(); 50 | invalidate(); 51 | } catch (IOException e) { 52 | e.printStackTrace(); 53 | } finally { 54 | 55 | try { 56 | if (is != null) is.close(); 57 | } catch (Exception e) { 58 | } 59 | } 60 | } 61 | 62 | 63 | public void init() { 64 | mDetector = new MoveGestureDetector(getContext(), new MoveGestureDetector.SimpleMoveGestureDetector() { 65 | @Override 66 | public boolean onMove(MoveGestureDetector detector) { 67 | int moveX = (int) detector.getMoveX(); 68 | int moveY = (int) detector.getMoveY(); 69 | 70 | if (mImageWidth > getWidth()) { 71 | mRect.offset(-moveX, 0); 72 | checkWidth(); 73 | invalidate(); 74 | } 75 | if (mImageHeight > getHeight()) { 76 | mRect.offset(0, -moveY); 77 | checkHeight(); 78 | invalidate(); 79 | } 80 | 81 | return true; 82 | } 83 | }); 84 | } 85 | 86 | 87 | private void checkWidth() { 88 | 89 | 90 | Rect rect = mRect; 91 | int imageWidth = mImageWidth; 92 | int imageHeight = mImageHeight; 93 | 94 | if (rect.right > imageWidth) { 95 | rect.right = imageWidth; 96 | rect.left = imageWidth - getWidth(); 97 | } 98 | 99 | if (rect.left < 0) { 100 | rect.left = 0; 101 | rect.right = getWidth(); 102 | } 103 | } 104 | 105 | 106 | private void checkHeight() { 107 | 108 | Rect rect = mRect; 109 | int imageWidth = mImageWidth; 110 | int imageHeight = mImageHeight; 111 | 112 | if (rect.bottom > imageHeight) { 113 | rect.bottom = imageHeight; 114 | rect.top = imageHeight - getHeight(); 115 | } 116 | 117 | if (rect.top < 0) { 118 | rect.top = 0; 119 | rect.bottom = getHeight(); 120 | } 121 | } 122 | 123 | 124 | public LargeImageView(Context context, AttributeSet attrs) { 125 | super(context, attrs); 126 | init(); 127 | } 128 | 129 | @Override 130 | public boolean onTouchEvent(MotionEvent event) { 131 | mDetector.onToucEvent(event); 132 | return true; 133 | } 134 | 135 | @Override 136 | protected void onDraw(Canvas canvas) { 137 | Bitmap bm = mDecoder.decodeRegion(mRect, options); 138 | canvas.drawBitmap(bm, 0, 0, null); 139 | } 140 | 141 | @Override 142 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 143 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 144 | 145 | int width = getMeasuredWidth(); 146 | int height = getMeasuredHeight(); 147 | 148 | int imageWidth = mImageWidth; 149 | int imageHeight = mImageHeight; 150 | 151 | mRect.left = imageWidth / 2 - width / 2; 152 | mRect.top = imageHeight / 2 - height / 2; 153 | mRect.right = mRect.left + width; 154 | mRect.bottom = mRect.top + height; 155 | 156 | } 157 | 158 | 159 | } 160 | -------------------------------------------------------------------------------- /jgallery/src/main/java/com/soubw/view/MoveGestureDetector.java: -------------------------------------------------------------------------------- 1 | package com.soubw.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.PointF; 5 | import android.view.MotionEvent; 6 | 7 | /** 8 | * Created by zhy on 15/5/12. 9 | */ 10 | public class MoveGestureDetector extends BaseGestureDetector 11 | { 12 | 13 | private PointF mCurrentPointer; 14 | private PointF mPrePointer; 15 | //仅仅为了减少创建内存 16 | private PointF mDeltaPointer = new PointF(); 17 | 18 | //用于记录最终结果,并返回 19 | private PointF mExtenalPointer = new PointF(); 20 | 21 | private OnMoveGestureListener mListenter; 22 | 23 | 24 | public MoveGestureDetector(Context context, OnMoveGestureListener listener) 25 | { 26 | super(context); 27 | mListenter = listener; 28 | } 29 | 30 | @Override 31 | protected void handleInProgressEvent(MotionEvent event) 32 | { 33 | int actionCode = event.getAction() & MotionEvent.ACTION_MASK; 34 | switch (actionCode) 35 | { 36 | case MotionEvent.ACTION_CANCEL: 37 | case MotionEvent.ACTION_UP: 38 | mListenter.onMoveEnd(this); 39 | resetState(); 40 | break; 41 | case MotionEvent.ACTION_MOVE: 42 | updateStateByEvent(event); 43 | boolean update = mListenter.onMove(this); 44 | if (update) 45 | { 46 | mPreMotionEvent.recycle(); 47 | mPreMotionEvent = MotionEvent.obtain(event); 48 | } 49 | break; 50 | 51 | } 52 | } 53 | 54 | @Override 55 | protected void handleStartProgressEvent(MotionEvent event) 56 | { 57 | int actionCode = event.getAction() & MotionEvent.ACTION_MASK; 58 | switch (actionCode) 59 | { 60 | case MotionEvent.ACTION_DOWN: 61 | resetState();//防止没有接收到CANCEL or UP ,保险起见 62 | mPreMotionEvent = MotionEvent.obtain(event); 63 | updateStateByEvent(event); 64 | break; 65 | case MotionEvent.ACTION_MOVE: 66 | mGestureInProgress = mListenter.onMoveBegin(this); 67 | break; 68 | } 69 | 70 | } 71 | 72 | protected void updateStateByEvent(MotionEvent event) 73 | { 74 | final MotionEvent prev = mPreMotionEvent; 75 | 76 | mPrePointer = caculateFocalPointer(prev); 77 | mCurrentPointer = caculateFocalPointer(event); 78 | 79 | //Log.e("TAG", mPrePointer.toString() + " , " + mCurrentPointer); 80 | 81 | boolean mSkipThisMoveEvent = prev.getPointerCount() != event.getPointerCount(); 82 | 83 | //Log.e("TAG", "mSkipThisMoveEvent = " + mSkipThisMoveEvent); 84 | mExtenalPointer.x = mSkipThisMoveEvent ? 0 : mCurrentPointer.x - mPrePointer.x; 85 | mExtenalPointer.y = mSkipThisMoveEvent ? 0 : mCurrentPointer.y - mPrePointer.y; 86 | 87 | } 88 | 89 | /** 90 | * 根据event计算多指中心点 91 | * 92 | * @param event 93 | * @return 94 | */ 95 | private PointF caculateFocalPointer(MotionEvent event) 96 | { 97 | final int count = event.getPointerCount(); 98 | float x = 0, y = 0; 99 | for (int i = 0; i < count; i++) 100 | { 101 | x += event.getX(i); 102 | y += event.getY(i); 103 | } 104 | 105 | x /= count; 106 | y /= count; 107 | 108 | return new PointF(x, y); 109 | } 110 | 111 | 112 | public float getMoveX() 113 | { 114 | return mExtenalPointer.x; 115 | 116 | } 117 | 118 | public float getMoveY() 119 | { 120 | return mExtenalPointer.y; 121 | } 122 | 123 | 124 | public interface OnMoveGestureListener 125 | { 126 | public boolean onMoveBegin(MoveGestureDetector detector); 127 | 128 | public boolean onMove(MoveGestureDetector detector); 129 | 130 | public void onMoveEnd(MoveGestureDetector detector); 131 | } 132 | 133 | public static class SimpleMoveGestureDetector implements OnMoveGestureListener 134 | { 135 | 136 | @Override 137 | public boolean onMoveBegin(MoveGestureDetector detector) 138 | { 139 | return true; 140 | } 141 | 142 | @Override 143 | public boolean onMove(MoveGestureDetector detector) 144 | { 145 | return false; 146 | } 147 | 148 | @Override 149 | public void onMoveEnd(MoveGestureDetector detector) 150 | { 151 | } 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /jgallery/src/main/res/drawable/jgallery_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WX-JIN/JGallery/7647aee23874070dd99f2fc19bdb9a79fa35c9d8/jgallery/src/main/res/drawable/jgallery_bg.jpg -------------------------------------------------------------------------------- /jgallery/src/main/res/drawable/jgallery_image_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WX-JIN/JGallery/7647aee23874070dd99f2fc19bdb9a79fa35c9d8/jgallery/src/main/res/drawable/jgallery_image_over.png -------------------------------------------------------------------------------- /jgallery/src/main/res/drawable/jgallery_num_indicator.xml: -------------------------------------------------------------------------------- 1 | 2 |