├── samples
├── res
│ ├── drawable
│ │ ├── image1.jpg
│ │ ├── image2.jpg
│ │ ├── image3.jpg
│ │ ├── image4.jpg
│ │ ├── image5.jpg
│ │ └── image6.jpg
│ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ ├── drawable-ldpi
│ │ └── ic_launcher.png
│ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ ├── values
│ │ ├── styles.xml
│ │ ├── dimens.xml
│ │ └── strings.xml
│ ├── values-v11
│ │ └── styles.xml
│ └── layout
│ │ ├── main.xml
│ │ └── layout_inflate_example.xml
├── proguard-project.txt
├── project.properties
├── ant.properties
├── src
│ └── at
│ │ └── technikum
│ │ └── mti
│ │ └── fancycoverflow
│ │ └── samples
│ │ ├── example
│ │ ├── XmlInflateExample.java
│ │ ├── SimpleExample.java
│ │ ├── ViewGroupReflectionExample.java
│ │ └── ViewGroupExample.java
│ │ ├── shared
│ │ └── FancyCoverFlowSampleAdapter.java
│ │ └── MainActivity.java
├── AndroidManifest.xml
└── build.xml
├── .gitignore
├── LICENSE
├── library
├── proguard-project.txt
├── res
│ └── values
│ │ ├── strings.xml
│ │ └── attr.xml
├── AndroidManifest.xml
├── project.properties
├── ant.properties
├── src
│ └── at
│ │ └── technikum
│ │ └── mti
│ │ └── fancycoverflow
│ │ ├── FancyCoverFlowAdapter.java
│ │ ├── FancyCoverFlowItemWrapper.java
│ │ └── FancyCoverFlow.java
└── build.xml
└── README.md
/samples/res/drawable/image1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidschreiber/FancyCoverFlow/HEAD/samples/res/drawable/image1.jpg
--------------------------------------------------------------------------------
/samples/res/drawable/image2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidschreiber/FancyCoverFlow/HEAD/samples/res/drawable/image2.jpg
--------------------------------------------------------------------------------
/samples/res/drawable/image3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidschreiber/FancyCoverFlow/HEAD/samples/res/drawable/image3.jpg
--------------------------------------------------------------------------------
/samples/res/drawable/image4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidschreiber/FancyCoverFlow/HEAD/samples/res/drawable/image4.jpg
--------------------------------------------------------------------------------
/samples/res/drawable/image5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidschreiber/FancyCoverFlow/HEAD/samples/res/drawable/image5.jpg
--------------------------------------------------------------------------------
/samples/res/drawable/image6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidschreiber/FancyCoverFlow/HEAD/samples/res/drawable/image6.jpg
--------------------------------------------------------------------------------
/samples/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidschreiber/FancyCoverFlow/HEAD/samples/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidschreiber/FancyCoverFlow/HEAD/samples/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidschreiber/FancyCoverFlow/HEAD/samples/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidschreiber/FancyCoverFlow/HEAD/samples/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/samples/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/samples/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 48dp
4 | 16dp
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Eclipse project files
19 | .classpath
20 | .project
21 |
22 | # Proguard folder generated by Eclipse
23 | proguard/
24 |
25 | # Intellij project files
26 | *.iml
27 | *.ipr
28 | *.iws
29 | .idea/
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2013 David Schreiber
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
--------------------------------------------------------------------------------
/library/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/samples/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/library/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 | FancyCoverFlow
21 |
22 |
--------------------------------------------------------------------------------
/library/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/samples/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 | FancyCoverFlow
21 | XML Inflate Example
22 | Simple Example
23 | ViewGroup Example
24 | ViewGroup with Reflection
25 |
26 |
--------------------------------------------------------------------------------
/samples/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
24 |
25 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/library/res/values/attr.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/library/project.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2013 David Schreiber
3 | # 2013 John Paul Nalog
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 |
18 | # This file is automatically generated by Android Tools.
19 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
20 | #
21 | # This file must be checked in Version Control Systems.
22 | #
23 | # To customize properties used by the Ant build system edit
24 | # "ant.properties", and override values to adapt the script to your
25 | # project structure.
26 | #
27 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
28 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
29 |
30 | android.library=true
31 | # Project target.
32 | target=android-17
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | FancyCoverFlow
2 | ==============
3 |
4 | THIS PROJECT IS NO LONGER MAINTAINED!
5 | =====================================
6 |
7 | ## What is FancyCoverFlow?
8 | FancyCoverFlow is a flexible Android widget providing out of the box view transformations to give your app a unique look and feel. Curious about what FancyCoverFlow can do for you? Check out the FancyCoverFlow examples on Google Play.
9 |
10 | [](https://play.google.com/store/apps/details?id=at.technikum.mti.fancycoverflow.samples)
11 | 
12 |
13 | ## How to use?
14 | Using FancyCoverFlow in your Android app is as simple as
15 |
16 | fancyCoverFlow = new FancyCoverFlow(context);
17 | fancyCoverFlow.setMaxRotation(45);
18 | fancyCoverFlow.setUnselectedAlpha(0.3f);
19 | fancyCoverFlow.setUnselectedSaturation(0.0f);
20 | fancyCoverFlow.setUnselectedScale(0.4f);
21 |
22 | You can also inflate FancyCoverFlow from XML:
23 |
24 |
31 |
--------------------------------------------------------------------------------
/samples/project.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2013 David Schreiber
3 | # 2013 John Paul Nalog
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 |
18 | # This file is automatically generated by Android Tools.
19 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
20 | #
21 | # This file must be checked in Version Control Systems.
22 | #
23 | # To customize properties used by the Ant build system edit
24 | # "ant.properties", and override values to adapt the script to your
25 | # project structure.
26 | #
27 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
28 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
29 |
30 | # Project target.
31 | target=android-17
32 | android.library.reference.0=../library
33 |
--------------------------------------------------------------------------------
/library/ant.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2013 David Schreiber
3 | # 2013 John Paul Nalog
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 |
18 | # This file is used to override default values used by the Ant build system.
19 | #
20 | # This file must be checked into Version Control Systems, as it is
21 | # integral to the build system of your project.
22 |
23 | # This file is only used by the Ant script.
24 |
25 | # You can use this to override default values such as
26 | # 'source.dir' for the location of your java source folder and
27 | # 'out.dir' for the location of your output folder.
28 |
29 | # You can also use it define how the release builds are signed by declaring
30 | # the following properties:
31 | # 'key.store' for the location of your keystore and
32 | # 'key.alias' for the name of the key to use.
33 | # The password will be asked during the build when you use the 'release' target.
34 |
35 |
--------------------------------------------------------------------------------
/samples/ant.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2013 David Schreiber
3 | # 2013 John Paul Nalog
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 |
18 | # This file is used to override default values used by the Ant build system.
19 | #
20 | # This file must be checked into Version Control Systems, as it is
21 | # integral to the build system of your project.
22 |
23 | # This file is only used by the Ant script.
24 |
25 | # You can use this to override default values such as
26 | # 'source.dir' for the location of your java source folder and
27 | # 'out.dir' for the location of your output folder.
28 |
29 | # You can also use it define how the release builds are signed by declaring
30 | # the following properties:
31 | # 'key.store' for the location of your keystore and
32 | # 'key.alias' for the name of the key to use.
33 | # The password will be asked during the build when you use the 'release' target.
34 |
35 |
--------------------------------------------------------------------------------
/samples/res/layout/layout_inflate_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
20 |
25 |
26 |
36 |
37 |
--------------------------------------------------------------------------------
/samples/src/at/technikum/mti/fancycoverflow/samples/example/XmlInflateExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 David Schreiber
3 | * 2013 John Paul Nalog
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package at.technikum.mti.fancycoverflow.samples.example;
19 |
20 | import android.os.Bundle;
21 | import at.technikum.mti.fancycoverflow.FancyCoverFlow;
22 | import at.technikum.mti.fancycoverflow.samples.R;
23 | import at.technikum.mti.fancycoverflow.samples.shared.FancyCoverFlowSampleAdapter;
24 |
25 | public class XmlInflateExample extends SimpleExample {
26 |
27 | // =============================================================================
28 | // Supertype overrides
29 | // =============================================================================
30 |
31 | @Override
32 | public void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | this.setContentView(R.layout.layout_inflate_example);
35 |
36 | FancyCoverFlow fancyCoverFlow = (FancyCoverFlow) findViewById(R.id.fancyCoverFlow);
37 | fancyCoverFlow.setAdapter(new FancyCoverFlowSampleAdapter());
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/samples/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
23 |
24 |
27 |
28 |
32 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
44 |
45 |
48 |
49 |
52 |
53 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/samples/src/at/technikum/mti/fancycoverflow/samples/shared/FancyCoverFlowSampleAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 David Schreiber
3 | * 2013 John Paul Nalog
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package at.technikum.mti.fancycoverflow.samples.shared;
19 |
20 | import android.view.View;
21 | import android.view.ViewGroup;
22 | import android.widget.ImageView;
23 | import at.technikum.mti.fancycoverflow.FancyCoverFlow;
24 | import at.technikum.mti.fancycoverflow.FancyCoverFlowAdapter;
25 | import at.technikum.mti.fancycoverflow.samples.R;
26 |
27 | public class FancyCoverFlowSampleAdapter extends FancyCoverFlowAdapter {
28 |
29 | // =============================================================================
30 | // Private members
31 | // =============================================================================
32 |
33 | private int[] images = {R.drawable.image1, R.drawable.image2, R.drawable.image3, R.drawable.image4, R.drawable.image5, R.drawable.image6,};
34 |
35 | // =============================================================================
36 | // Supertype overrides
37 | // =============================================================================
38 |
39 | @Override
40 | public int getCount() {
41 | return images.length;
42 | }
43 |
44 | @Override
45 | public Integer getItem(int i) {
46 | return images[i];
47 | }
48 |
49 | @Override
50 | public long getItemId(int i) {
51 | return i;
52 | }
53 |
54 | @Override
55 | public View getCoverFlowItem(int i, View reuseableView, ViewGroup viewGroup) {
56 | ImageView imageView = null;
57 |
58 | if (reuseableView != null) {
59 | imageView = (ImageView) reuseableView;
60 | } else {
61 | imageView = new ImageView(viewGroup.getContext());
62 | imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
63 | imageView.setLayoutParams(new FancyCoverFlow.LayoutParams(300, 400));
64 |
65 | }
66 |
67 | imageView.setImageResource(this.getItem(i));
68 | return imageView;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/samples/src/at/technikum/mti/fancycoverflow/samples/example/SimpleExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 David Schreiber
3 | * 2013 John Paul Nalog
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package at.technikum.mti.fancycoverflow.samples.example;
19 |
20 | import android.app.Activity;
21 | import android.os.Bundle;
22 | import at.technikum.mti.fancycoverflow.FancyCoverFlow;
23 | import at.technikum.mti.fancycoverflow.samples.R;
24 | import at.technikum.mti.fancycoverflow.samples.shared.FancyCoverFlowSampleAdapter;
25 |
26 | public class SimpleExample extends Activity {
27 |
28 | // =============================================================================
29 | // Child views
30 | // =============================================================================
31 |
32 | private FancyCoverFlow fancyCoverFlow;
33 |
34 | // =============================================================================
35 | // Supertype overrides
36 | // =============================================================================
37 |
38 | /**
39 | * Called when the activity is first created.
40 | */
41 | @Override
42 | public void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.main);
45 |
46 | this.fancyCoverFlow = (FancyCoverFlow) this.findViewById(R.id.fancyCoverFlow);
47 |
48 | this.fancyCoverFlow.setAdapter(new FancyCoverFlowSampleAdapter());
49 | this.fancyCoverFlow.setUnselectedAlpha(1.0f);
50 | this.fancyCoverFlow.setUnselectedSaturation(0.0f);
51 | this.fancyCoverFlow.setUnselectedScale(0.5f);
52 | this.fancyCoverFlow.setSpacing(50);
53 | this.fancyCoverFlow.setMaxRotation(0);
54 | this.fancyCoverFlow.setScaleDownGravity(0.2f);
55 | this.fancyCoverFlow.setActionDistance(FancyCoverFlow.ACTION_DISTANCE_AUTO);
56 | }
57 |
58 | // =============================================================================
59 | // Private classes
60 | // =============================================================================
61 |
62 |
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/library/src/at/technikum/mti/fancycoverflow/FancyCoverFlowAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 David Schreiber
3 | * 2013 John Paul Nalog
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package at.technikum.mti.fancycoverflow;
19 |
20 | import android.view.View;
21 | import android.view.ViewGroup;
22 | import android.widget.BaseAdapter;
23 |
24 |
25 | public abstract class FancyCoverFlowAdapter extends BaseAdapter {
26 |
27 | // =============================================================================
28 | // Supertype overrides
29 | // =============================================================================
30 |
31 | @Override
32 | public final View getView(int i, View reusableView, ViewGroup viewGroup) {
33 | FancyCoverFlow coverFlow = (FancyCoverFlow) viewGroup;
34 |
35 | View wrappedView = null;
36 | FancyCoverFlowItemWrapper coverFlowItem;
37 |
38 | if (reusableView != null) {
39 | coverFlowItem = (FancyCoverFlowItemWrapper) reusableView;
40 | wrappedView = coverFlowItem.getChildAt(0);
41 | coverFlowItem.removeAllViews();
42 | } else {
43 | coverFlowItem = new FancyCoverFlowItemWrapper(viewGroup.getContext());
44 | }
45 |
46 | wrappedView = this.getCoverFlowItem(i, wrappedView, viewGroup);
47 |
48 | if (wrappedView == null) {
49 | throw new NullPointerException("getCoverFlowItem() was expected to return a view, but null was returned.");
50 | }
51 |
52 | final boolean isReflectionEnabled = coverFlow.isReflectionEnabled();
53 | coverFlowItem.setReflectionEnabled(isReflectionEnabled);
54 |
55 | if(isReflectionEnabled) {
56 | coverFlowItem.setReflectionGap(coverFlow.getReflectionGap());
57 | coverFlowItem.setReflectionRatio(coverFlow.getReflectionRatio());
58 | }
59 |
60 |
61 | coverFlowItem.addView(wrappedView);
62 | coverFlowItem.setLayoutParams(wrappedView.getLayoutParams());
63 |
64 | return coverFlowItem;
65 | }
66 |
67 | // =============================================================================
68 | // Abstract methods
69 | // =============================================================================
70 |
71 | public abstract View getCoverFlowItem(int position, View reusableView, ViewGroup parent);
72 | }
73 |
--------------------------------------------------------------------------------
/samples/src/at/technikum/mti/fancycoverflow/samples/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 David Schreiber
3 | * 2013 John Paul Nalog
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package at.technikum.mti.fancycoverflow.samples;
19 |
20 | import android.app.ListActivity;
21 | import android.content.Context;
22 | import android.content.Intent;
23 | import android.os.Bundle;
24 | import android.view.Gravity;
25 | import android.view.View;
26 | import android.view.ViewGroup;
27 | import android.widget.AbsListView;
28 | import android.widget.BaseAdapter;
29 | import android.widget.TextView;
30 | import at.technikum.mti.fancycoverflow.samples.example.SimpleExample;
31 | import at.technikum.mti.fancycoverflow.samples.example.ViewGroupExample;
32 | import at.technikum.mti.fancycoverflow.samples.example.ViewGroupReflectionExample;
33 | import at.technikum.mti.fancycoverflow.samples.example.XmlInflateExample;
34 |
35 | public class MainActivity extends ListActivity {
36 |
37 | @Override
38 | protected void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 |
41 | this.setListAdapter(new ExampleAdapter());
42 | }
43 |
44 | // =============================================================================
45 | // Private classes
46 | // =============================================================================
47 |
48 | /**
49 | * TODO: Scan the example package for activities and show them automatically.
50 | */
51 | private static class ExampleAdapter extends BaseAdapter {
52 |
53 | // =============================================================================
54 | // Private members
55 | // =============================================================================
56 |
57 | private final Class[] exampleActivities = new Class[]{SimpleExample.class, ViewGroupExample.class, ViewGroupReflectionExample.class, XmlInflateExample.class};
58 |
59 | // =============================================================================
60 | // Supertype overrides
61 | // =============================================================================
62 |
63 | @Override
64 | public int getCount() {
65 | return this.exampleActivities.length;
66 | }
67 |
68 | @Override
69 | public Class getItem(int i) {
70 | return this.exampleActivities[i];
71 | }
72 |
73 | @Override
74 | public long getItemId(int i) {
75 | return i;
76 | }
77 |
78 | @Override
79 | public View getView(int i, View reusableView, ViewGroup viewGroup) {
80 | TextView view;
81 |
82 | if (reusableView != null) {
83 | view = (TextView) reusableView;
84 | } else {
85 | final Context context = viewGroup.getContext();
86 | final int listItemPadding = context.getResources().getDimensionPixelSize(R.dimen.mainActivityListItemPadding);
87 | view = new TextView(context);
88 | view.setGravity(Gravity.CENTER_VERTICAL);
89 | view.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, context.getResources().getDimensionPixelSize(R.dimen.mainActivityListItemHeight)));
90 | view.setPadding(listItemPadding, 0, listItemPadding, 0);
91 | }
92 |
93 | final Class activity = this.getItem(i);
94 |
95 | view.setText(activity.getSimpleName());
96 | view.setOnClickListener(new View.OnClickListener() {
97 | @Override
98 | public void onClick(View view) {
99 | Intent i = new Intent(view.getContext(), activity);
100 | view.getContext().startActivity(i);
101 | }
102 | });
103 |
104 | return view;
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/samples/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
46 |
47 |
48 |
52 |
53 |
54 |
55 |
56 |
57 |
66 |
67 |
68 |
69 |
73 |
74 |
86 |
87 |
88 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/library/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
46 |
47 |
48 |
52 |
53 |
54 |
55 |
56 |
57 |
66 |
67 |
68 |
69 |
73 |
74 |
86 |
87 |
88 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/samples/src/at/technikum/mti/fancycoverflow/samples/example/ViewGroupReflectionExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 David Schreiber
3 | * 2013 John Paul Nalog
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package at.technikum.mti.fancycoverflow.samples.example;
19 |
20 | import android.app.Activity;
21 | import android.content.Context;
22 | import android.content.Intent;
23 | import android.net.Uri;
24 | import android.os.Bundle;
25 | import android.view.Gravity;
26 | import android.view.View;
27 | import android.view.ViewGroup;
28 | import android.widget.Button;
29 | import android.widget.ImageView;
30 | import android.widget.LinearLayout;
31 | import android.widget.TextView;
32 | import at.technikum.mti.fancycoverflow.FancyCoverFlow;
33 | import at.technikum.mti.fancycoverflow.FancyCoverFlowAdapter;
34 | import at.technikum.mti.fancycoverflow.samples.R;
35 |
36 | public class ViewGroupReflectionExample extends Activity {
37 |
38 | // =============================================================================
39 | // Supertype overrides
40 | // =============================================================================
41 |
42 | @Override
43 | protected void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | this.setContentView(R.layout.layout_inflate_example);
46 |
47 | FancyCoverFlow fancyCoverFlow = (FancyCoverFlow) findViewById(R.id.fancyCoverFlow);
48 | fancyCoverFlow.setReflectionEnabled(true);
49 | fancyCoverFlow.setReflectionRatio(0.3f);
50 | fancyCoverFlow.setReflectionGap(0);
51 |
52 | fancyCoverFlow.setAdapter(new ViewGroupExampleAdapter());
53 | }
54 |
55 | // =============================================================================
56 | // Private classes
57 | // =============================================================================
58 |
59 | private static class ViewGroupExampleAdapter extends FancyCoverFlowAdapter {
60 |
61 | // =============================================================================
62 | // Private members
63 | // =============================================================================
64 |
65 | private int[] images = {R.drawable.image1, R.drawable.image2, R.drawable.image3, R.drawable.image4, R.drawable.image5, R.drawable.image6,};
66 |
67 | // =============================================================================
68 | // Supertype overrides
69 | // =============================================================================
70 |
71 | @Override
72 | public int getCount() {
73 | return images.length;
74 | }
75 |
76 | @Override
77 | public Integer getItem(int i) {
78 | return images[i];
79 | }
80 |
81 | @Override
82 | public long getItemId(int i) {
83 | return i;
84 | }
85 |
86 | @Override
87 | public View getCoverFlowItem(int i, View reuseableView, ViewGroup viewGroup) {
88 | CustomViewGroup customViewGroup = null;
89 |
90 | if (reuseableView != null) {
91 | customViewGroup = (CustomViewGroup) reuseableView;
92 | } else {
93 | customViewGroup = new CustomViewGroup(viewGroup.getContext());
94 | customViewGroup.setLayoutParams(new FancyCoverFlow.LayoutParams(300, 600));
95 | }
96 |
97 | customViewGroup.getImageView().setImageResource(this.getItem(i));
98 |
99 | return customViewGroup;
100 | }
101 | }
102 |
103 | private static class CustomViewGroup extends LinearLayout {
104 |
105 | // =============================================================================
106 | // Child views
107 | // =============================================================================
108 |
109 | private ImageView imageView;
110 |
111 | private Button button;
112 |
113 | // =============================================================================
114 | // Constructor
115 | // =============================================================================
116 |
117 | private CustomViewGroup(Context context) {
118 | super(context);
119 |
120 | this.setOrientation(VERTICAL);
121 | this.setWeightSum(5);
122 |
123 | this.imageView = new ImageView(context);
124 | this.button = new Button(context);
125 |
126 | LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
127 |
128 | this.imageView.setLayoutParams(layoutParams);
129 | this.button.setLayoutParams(layoutParams);
130 |
131 | this.imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
132 | this.imageView.setAdjustViewBounds(true);
133 |
134 | this.button.setText("Goto GitHub");
135 | this.button.setOnClickListener(new OnClickListener() {
136 | @Override
137 | public void onClick(View view) {
138 | Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("https://davidschreiber.github.com/FancyCoverFlow"));
139 | view.getContext().startActivity(i);
140 | }
141 | });
142 |
143 | this.addView(this.imageView);
144 | this.addView(this.button);
145 | }
146 |
147 | // =============================================================================
148 | // Getters
149 | // =============================================================================
150 |
151 | private ImageView getImageView() {
152 | return imageView;
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/samples/src/at/technikum/mti/fancycoverflow/samples/example/ViewGroupExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 David Schreiber
3 | * 2013 John Paul Nalog
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package at.technikum.mti.fancycoverflow.samples.example;
19 |
20 | import android.app.Activity;
21 | import android.content.Context;
22 | import android.content.Intent;
23 | import android.net.Uri;
24 | import android.os.Bundle;
25 | import android.view.Gravity;
26 | import android.view.View;
27 | import android.view.ViewGroup;
28 | import android.widget.Button;
29 | import android.widget.ImageView;
30 | import android.widget.LinearLayout;
31 | import android.widget.TextView;
32 | import at.technikum.mti.fancycoverflow.FancyCoverFlow;
33 | import at.technikum.mti.fancycoverflow.FancyCoverFlowAdapter;
34 | import at.technikum.mti.fancycoverflow.samples.R;
35 |
36 | public class ViewGroupExample extends Activity {
37 |
38 | // =============================================================================
39 | // Supertype overrides
40 | // =============================================================================
41 |
42 | @Override
43 | protected void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | this.setContentView(R.layout.layout_inflate_example);
46 |
47 | FancyCoverFlow fancyCoverFlow = (FancyCoverFlow) findViewById(R.id.fancyCoverFlow);
48 | fancyCoverFlow.setAdapter(new ViewGroupExampleAdapter());
49 | }
50 |
51 | // =============================================================================
52 | // Private classes
53 | // =============================================================================
54 |
55 | private static class ViewGroupExampleAdapter extends FancyCoverFlowAdapter {
56 |
57 | // =============================================================================
58 | // Private members
59 | // =============================================================================
60 |
61 | private int[] images = {R.drawable.image1, R.drawable.image2, R.drawable.image3, R.drawable.image4, R.drawable.image5, R.drawable.image6,};
62 |
63 | // =============================================================================
64 | // Supertype overrides
65 | // =============================================================================
66 |
67 | @Override
68 | public int getCount() {
69 | return images.length;
70 | }
71 |
72 | @Override
73 | public Integer getItem(int i) {
74 | return images[i];
75 | }
76 |
77 | @Override
78 | public long getItemId(int i) {
79 | return i;
80 | }
81 |
82 | @Override
83 | public View getCoverFlowItem(int i, View reuseableView, ViewGroup viewGroup) {
84 | CustomViewGroup customViewGroup = null;
85 |
86 | if (reuseableView != null) {
87 | customViewGroup = (CustomViewGroup) reuseableView;
88 | } else {
89 | customViewGroup = new CustomViewGroup(viewGroup.getContext());
90 | customViewGroup.setLayoutParams(new FancyCoverFlow.LayoutParams(300, 600));
91 | }
92 |
93 | customViewGroup.getImageView().setImageResource(this.getItem(i));
94 | customViewGroup.getTextView().setText(String.format("Item %d", i));
95 |
96 | return customViewGroup;
97 | }
98 | }
99 |
100 | private static class CustomViewGroup extends LinearLayout {
101 |
102 | // =============================================================================
103 | // Child views
104 | // =============================================================================
105 |
106 | private TextView textView;
107 |
108 | private ImageView imageView;
109 |
110 | private Button button;
111 |
112 | // =============================================================================
113 | // Constructor
114 | // =============================================================================
115 |
116 | private CustomViewGroup(Context context) {
117 | super(context);
118 |
119 | this.setOrientation(VERTICAL);
120 |
121 | this.textView = new TextView(context);
122 | this.imageView = new ImageView(context);
123 | this.button = new Button(context);
124 |
125 | LinearLayout.LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
126 | this.textView.setLayoutParams(layoutParams);
127 | this.imageView.setLayoutParams(layoutParams);
128 | this.button.setLayoutParams(layoutParams);
129 |
130 | this.textView.setGravity(Gravity.CENTER);
131 |
132 | this.imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
133 | this.imageView.setAdjustViewBounds(true);
134 |
135 | this.button.setText("Goto GitHub");
136 | this.button.setOnClickListener(new OnClickListener() {
137 | @Override
138 | public void onClick(View view) {
139 | Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("https://davidschreiber.github.com/FancyCoverFlow"));
140 | view.getContext().startActivity(i);
141 | }
142 | });
143 |
144 | this.addView(this.textView);
145 | this.addView(this.imageView);
146 | this.addView(this.button);
147 | }
148 |
149 | // =============================================================================
150 | // Getters
151 | // =============================================================================
152 |
153 | private TextView getTextView() {
154 | return textView;
155 | }
156 |
157 | private ImageView getImageView() {
158 | return imageView;
159 | }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/library/src/at/technikum/mti/fancycoverflow/FancyCoverFlowItemWrapper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 David Schreiber
3 | * 2013 John Paul Nalog
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package at.technikum.mti.fancycoverflow;
19 |
20 | import android.*;
21 | import android.R;
22 | import android.annotation.SuppressLint;
23 | import android.annotation.TargetApi;
24 | import android.content.Context;
25 | import android.graphics.*;
26 | import android.os.Build;
27 | import android.util.AttributeSet;
28 | import android.view.View;
29 | import android.view.ViewGroup;
30 |
31 | /**
32 | * This class has only internal use (package scope).
33 | *
34 | * It is responsible for applying additional effects to each coverflow item, that can only be applied at view level
35 | * (e.g. color saturation).
36 | *
37 | * This is a ViewGroup by intention to enable child views in layouts to stay interactive (like buttons) though
38 | * transformed.
39 | *
40 | * Since this class is only used within the FancyCoverFlowAdapter it doesn't need to check if there are multiple
41 | * children or not (there can only be one at all times).
42 | */
43 | @SuppressWarnings("ConstantConditions")
44 | class FancyCoverFlowItemWrapper extends ViewGroup {
45 |
46 | // =============================================================================
47 | // Private members
48 | // =============================================================================
49 |
50 | private float saturation;
51 |
52 | private boolean isReflectionEnabled = false;
53 |
54 | private float imageReflectionRatio;
55 |
56 | private int reflectionGap;
57 |
58 | private float originalScaledownFactor;
59 |
60 | /**
61 | * This is a matrix to apply color filters (like saturation) to the wrapped view.
62 | */
63 | private ColorMatrix colorMatrix;
64 |
65 | /**
66 | * This paint is used to draw the wrapped view including any filters.
67 | */
68 | private Paint paint;
69 |
70 | /**
71 | * This is a cache holding the wrapped view's visual representation.
72 | */
73 | private Bitmap wrappedViewBitmap;
74 |
75 | /**
76 | * This canvas is used to let the wrapped view draw it's content.
77 | */
78 | private Canvas wrappedViewDrawingCanvas;
79 |
80 |
81 | // =============================================================================
82 | // Constructor
83 | // =============================================================================
84 |
85 | public FancyCoverFlowItemWrapper(Context context) {
86 | super(context);
87 | this.init();
88 | }
89 |
90 | public FancyCoverFlowItemWrapper(Context context, AttributeSet attrs) {
91 | super(context, attrs);
92 | this.init();
93 | }
94 |
95 | public FancyCoverFlowItemWrapper(Context context, AttributeSet attrs, int defStyle) {
96 | super(context, attrs, defStyle);
97 | this.init();
98 | }
99 |
100 | private void init() {
101 | this.paint = new Paint();
102 | this.colorMatrix = new ColorMatrix();
103 | // TODO: Define a default value for saturation inside an XML.
104 | this.setSaturation(1);
105 | }
106 |
107 | // =============================================================================
108 | // Getters / Setters
109 | // =============================================================================
110 |
111 | void setReflectionEnabled(boolean hasReflection) {
112 | if (hasReflection != this.isReflectionEnabled) {
113 | this.isReflectionEnabled = hasReflection;
114 |
115 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
116 | // Turn off hardware acceleration if necessary (reflections won't support it).
117 | this.setLayerType(hasReflection ? View.LAYER_TYPE_SOFTWARE : View.LAYER_TYPE_HARDWARE, null);
118 | }
119 |
120 | this.remeasureChildren();
121 | }
122 | }
123 |
124 | void setReflectionRatio(float imageReflectionRatio) {
125 | if (imageReflectionRatio != this.imageReflectionRatio) {
126 | this.imageReflectionRatio = imageReflectionRatio;
127 | this.remeasureChildren();
128 | }
129 | }
130 |
131 | void setReflectionGap(int reflectionGap) {
132 | if (reflectionGap != this.reflectionGap) {
133 | this.reflectionGap = reflectionGap;
134 | this.remeasureChildren();
135 | }
136 | }
137 |
138 | public void setSaturation(float saturation) {
139 | if (saturation != this.saturation) {
140 | this.saturation = saturation;
141 | this.colorMatrix.setSaturation(saturation);
142 | this.paint.setColorFilter(new ColorMatrixColorFilter(this.colorMatrix));
143 | }
144 | }
145 |
146 | // =============================================================================
147 | // Supertype overrides
148 | // =============================================================================
149 |
150 | @Override
151 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
152 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
153 | this.remeasureChildren();
154 |
155 | // If we have reflection enabled, the original image is scaled down and a reflection is added beneath. Thus,
156 | // while maintaining the same height the width decreases and we need to adjust measured width.
157 | // WARNING: This is a hack because we do not obey the EXACTLY MeasureSpec mode that we will get mostly.
158 | if (this.isReflectionEnabled) {
159 | this.setMeasuredDimension((int) (this.getMeasuredWidth() * this.originalScaledownFactor), this.getMeasuredHeight());
160 | }
161 | }
162 |
163 | @SuppressLint("DrawAllocation")
164 | @Override
165 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
166 | if (changed) {
167 | int measuredWidth = this.getMeasuredWidth();
168 | int measuredHeight = this.getMeasuredHeight();
169 |
170 | if (this.wrappedViewBitmap == null || this.wrappedViewBitmap.getWidth() != measuredWidth || this.wrappedViewBitmap.getHeight() != measuredHeight) {
171 | this.wrappedViewBitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);
172 | this.wrappedViewDrawingCanvas = new Canvas(this.wrappedViewBitmap);
173 | }
174 |
175 | View child = getChildAt(0);
176 | int childWidth = child.getMeasuredWidth();
177 | int childHeight = child.getMeasuredHeight();
178 | int childLeft = (measuredWidth - childWidth) / 2;
179 | int childRight = measuredWidth - childLeft;
180 | child.layout(childLeft, 0, childRight, childHeight);
181 | }
182 | }
183 |
184 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
185 | @Override
186 | protected void dispatchDraw(Canvas canvas) {
187 | View childView = getChildAt(0);
188 |
189 | if (childView != null) {
190 | // If on honeycomb or newer, cache the view.
191 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
192 | if (childView.isDirty()) {
193 | childView.draw(this.wrappedViewDrawingCanvas);
194 |
195 | if (this.isReflectionEnabled) {
196 | this.createReflectedImages();
197 | }
198 | }
199 | } else {
200 | childView.draw(this.wrappedViewDrawingCanvas);
201 | }
202 | }
203 |
204 | canvas.drawBitmap(this.wrappedViewBitmap, (this.getWidth() - childView.getWidth()) / 2, 0, paint);
205 | }
206 |
207 | // =============================================================================
208 | // Methods
209 | // =============================================================================
210 |
211 | private void remeasureChildren() {
212 | View child = this.getChildAt(0);
213 |
214 | if (child != null) {
215 | // When reflection is enabled calculate proportional scale down factor.
216 | final int originalChildHeight = this.getMeasuredHeight();
217 | this.originalScaledownFactor = this.isReflectionEnabled ? (originalChildHeight * (1 - this.imageReflectionRatio) - reflectionGap) / originalChildHeight : 1.0f;
218 | final int childHeight = (int) (this.originalScaledownFactor * originalChildHeight);
219 | final int childWidth = (int) (this.originalScaledownFactor * getMeasuredWidth());
220 |
221 | int heightSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST);
222 | int widthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.AT_MOST);
223 | this.getChildAt(0).measure(widthSpec, heightSpec);
224 | }
225 | }
226 |
227 | /**
228 | * Creates the reflected images.
229 | *
230 | * @return true, if successful
231 | */
232 | private void createReflectedImages() {
233 |
234 | final int width = this.wrappedViewBitmap.getWidth();
235 | final int height = this.wrappedViewBitmap.getHeight();
236 |
237 |
238 | final Matrix matrix = new Matrix();
239 | matrix.postScale(1, -1);
240 |
241 |
242 | final int scaledDownHeight = (int) (height * originalScaledownFactor);
243 | final int invertedHeight = height - scaledDownHeight - reflectionGap;
244 | final int invertedBitmapSourceTop = scaledDownHeight - invertedHeight;
245 | final Bitmap invertedBitmap = Bitmap.createBitmap(this.wrappedViewBitmap, 0, invertedBitmapSourceTop, width, invertedHeight, matrix, true);
246 |
247 | this.wrappedViewDrawingCanvas.drawBitmap(invertedBitmap, 0, scaledDownHeight + reflectionGap, null);
248 |
249 | final Paint paint = new Paint();
250 | final LinearGradient shader = new LinearGradient(0, height * imageReflectionRatio + reflectionGap, 0, height, 0x70ffffff, 0x00ffffff, Shader.TileMode.CLAMP);
251 | paint.setShader(shader);
252 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
253 | this.wrappedViewDrawingCanvas.drawRect(0, height * (1 - imageReflectionRatio), width, height, paint);
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/library/src/at/technikum/mti/fancycoverflow/FancyCoverFlow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 David Schreiber
3 | * 2013 John Paul Nalog
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package at.technikum.mti.fancycoverflow;
19 |
20 | import android.content.Context;
21 | import android.content.res.TypedArray;
22 | import android.graphics.*;
23 | import android.util.AttributeSet;
24 | import android.view.View;
25 | import android.view.ViewGroup;
26 | import android.view.animation.Transformation;
27 | import android.widget.Gallery;
28 | import android.widget.SpinnerAdapter;
29 |
30 | public class FancyCoverFlow extends Gallery {
31 |
32 | // =============================================================================
33 | // Constants
34 | // =============================================================================
35 |
36 | public static final int ACTION_DISTANCE_AUTO = Integer.MAX_VALUE;
37 |
38 | public static final float SCALEDOWN_GRAVITY_TOP = 0.0f;
39 |
40 | public static final float SCALEDOWN_GRAVITY_CENTER = 0.5f;
41 |
42 | public static final float SCALEDOWN_GRAVITY_BOTTOM = 1.0f;
43 |
44 | // =============================================================================
45 | // Private members
46 | // =============================================================================
47 |
48 | private float reflectionRatio = 0.4f;
49 |
50 | private int reflectionGap = 20;
51 |
52 | private boolean reflectionEnabled = false;
53 |
54 | /**
55 | * TODO: Doc
56 | */
57 | private float unselectedAlpha;
58 |
59 | /**
60 | * Camera used for view transformation.
61 | */
62 | private Camera transformationCamera;
63 |
64 | /**
65 | * TODO: Doc
66 | */
67 | private int maxRotation = 75;
68 |
69 | /**
70 | * Factor (0-1) that defines how much the unselected children should be scaled down. 1 means no scaledown.
71 | */
72 | private float unselectedScale;
73 |
74 | /**
75 | * TODO: Doc
76 | */
77 | private float scaleDownGravity = SCALEDOWN_GRAVITY_CENTER;
78 |
79 | /**
80 | * Distance in pixels between the transformation effects (alpha, rotation, zoom) are applied.
81 | */
82 | private int actionDistance;
83 |
84 | /**
85 | * Saturation factor (0-1) of items that reach the outer effects distance.
86 | */
87 | private float unselectedSaturation;
88 |
89 | // =============================================================================
90 | // Constructors
91 | // =============================================================================
92 |
93 | public FancyCoverFlow(Context context) {
94 | super(context);
95 | this.initialize();
96 | }
97 |
98 | public FancyCoverFlow(Context context, AttributeSet attrs) {
99 | super(context, attrs);
100 | this.initialize();
101 | this.applyXmlAttributes(attrs);
102 | }
103 |
104 | public FancyCoverFlow(Context context, AttributeSet attrs, int defStyle) {
105 | super(context, attrs, defStyle);
106 | this.initialize();
107 | this.applyXmlAttributes(attrs);
108 | }
109 |
110 | private void initialize() {
111 | this.transformationCamera = new Camera();
112 | this.setSpacing(0);
113 | }
114 |
115 | private void applyXmlAttributes(AttributeSet attrs) {
116 | TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.FancyCoverFlow);
117 |
118 | this.actionDistance = a.getInteger(R.styleable.FancyCoverFlow_actionDistance, ACTION_DISTANCE_AUTO);
119 | this.scaleDownGravity = a.getFloat(R.styleable.FancyCoverFlow_scaleDownGravity, 1.0f);
120 | this.maxRotation = a.getInteger(R.styleable.FancyCoverFlow_maxRotation, 45);
121 | this.unselectedAlpha = a.getFloat(R.styleable.FancyCoverFlow_unselectedAlpha, 0.3f);
122 | this.unselectedSaturation = a.getFloat(R.styleable.FancyCoverFlow_unselectedSaturation, 0.0f);
123 | this.unselectedScale = a.getFloat(R.styleable.FancyCoverFlow_unselectedScale, 0.75f);
124 | }
125 |
126 | // =============================================================================
127 | // Getter / Setter
128 | // =============================================================================
129 |
130 | public float getReflectionRatio() {
131 | return reflectionRatio;
132 | }
133 |
134 | public void setReflectionRatio(float reflectionRatio) {
135 | if (reflectionRatio <= 0 || reflectionRatio > 0.5f) {
136 | throw new IllegalArgumentException("reflectionRatio may only be in the interval (0, 0.5]");
137 | }
138 |
139 | this.reflectionRatio = reflectionRatio;
140 |
141 | if (this.getAdapter() != null) {
142 | ((FancyCoverFlowAdapter) this.getAdapter()).notifyDataSetChanged();
143 | }
144 | }
145 |
146 | public int getReflectionGap() {
147 | return reflectionGap;
148 | }
149 |
150 | public void setReflectionGap(int reflectionGap) {
151 | this.reflectionGap = reflectionGap;
152 |
153 | if (this.getAdapter() != null) {
154 | ((FancyCoverFlowAdapter) this.getAdapter()).notifyDataSetChanged();
155 | }
156 | }
157 |
158 | public boolean isReflectionEnabled() {
159 | return reflectionEnabled;
160 | }
161 |
162 | public void setReflectionEnabled(boolean reflectionEnabled) {
163 | this.reflectionEnabled = reflectionEnabled;
164 |
165 | if (this.getAdapter() != null) {
166 | ((FancyCoverFlowAdapter) this.getAdapter()).notifyDataSetChanged();
167 | }
168 | }
169 |
170 | /**
171 | * Use this to provide a {@link FancyCoverFlowAdapter} to the coverflow. This
172 | * method will throw an {@link ClassCastException} if the passed adapter does not
173 | * subclass {@link FancyCoverFlowAdapter}.
174 | *
175 | * @param adapter
176 | */
177 | @Override
178 | public void setAdapter(SpinnerAdapter adapter) {
179 | if (!(adapter instanceof FancyCoverFlowAdapter)) {
180 | throw new ClassCastException(FancyCoverFlow.class.getSimpleName() + " only works in conjunction with a " + FancyCoverFlowAdapter.class.getSimpleName());
181 | }
182 |
183 | super.setAdapter(adapter);
184 | }
185 |
186 | /**
187 | * Returns the maximum rotation that is applied to items left and right of the center of the coverflow.
188 | *
189 | * @return
190 | */
191 | public int getMaxRotation() {
192 | return maxRotation;
193 | }
194 |
195 | /**
196 | * Sets the maximum rotation that is applied to items left and right of the center of the coverflow.
197 | *
198 | * @param maxRotation
199 | */
200 | public void setMaxRotation(int maxRotation) {
201 | this.maxRotation = maxRotation;
202 | }
203 |
204 | /**
205 | * TODO: Write doc
206 | *
207 | * @return
208 | */
209 | public float getUnselectedAlpha() {
210 | return this.unselectedAlpha;
211 | }
212 |
213 | /**
214 | * TODO: Write doc
215 | *
216 | * @return
217 | */
218 | public float getUnselectedScale() {
219 | return unselectedScale;
220 | }
221 |
222 | /**
223 | * TODO: Write doc
224 | *
225 | * @param unselectedScale
226 | */
227 | public void setUnselectedScale(float unselectedScale) {
228 | this.unselectedScale = unselectedScale;
229 | }
230 |
231 | /**
232 | * TODO: Doc
233 | *
234 | * @return
235 | */
236 | public float getScaleDownGravity() {
237 | return scaleDownGravity;
238 | }
239 |
240 | /**
241 | * TODO: Doc
242 | *
243 | * @param scaleDownGravity
244 | */
245 | public void setScaleDownGravity(float scaleDownGravity) {
246 | this.scaleDownGravity = scaleDownGravity;
247 | }
248 |
249 | /**
250 | * TODO: Write doc
251 | *
252 | * @return
253 | */
254 | public int getActionDistance() {
255 | return actionDistance;
256 | }
257 |
258 | /**
259 | * TODO: Write doc
260 | *
261 | * @param actionDistance
262 | */
263 | public void setActionDistance(int actionDistance) {
264 | this.actionDistance = actionDistance;
265 | }
266 |
267 | /**
268 | * TODO: Write doc
269 | *
270 | * @param unselectedAlpha
271 | */
272 | @Override
273 | public void setUnselectedAlpha(float unselectedAlpha) {
274 | super.setUnselectedAlpha(unselectedAlpha);
275 | this.unselectedAlpha = unselectedAlpha;
276 | }
277 |
278 | /**
279 | * TODO: Write doc
280 | *
281 | * @return
282 | */
283 | public float getUnselectedSaturation() {
284 | return unselectedSaturation;
285 | }
286 |
287 | /**
288 | * TODO: Write doc
289 | *
290 | * @param unselectedSaturation
291 | */
292 | public void setUnselectedSaturation(float unselectedSaturation) {
293 | this.unselectedSaturation = unselectedSaturation;
294 | }
295 |
296 | // =============================================================================
297 | // Supertype overrides
298 | // =============================================================================
299 |
300 | @Override
301 | protected boolean getChildStaticTransformation(View child, Transformation t) {
302 | // We can cast here because FancyCoverFlowAdapter only creates wrappers.
303 | FancyCoverFlowItemWrapper item = (FancyCoverFlowItemWrapper) child;
304 |
305 | // Since Jelly Bean childs won't get invalidated automatically, needs to be added for the smooth coverflow animation
306 | if (android.os.Build.VERSION.SDK_INT >= 16) {
307 | item.invalidate();
308 | }
309 |
310 | final int coverFlowWidth = this.getWidth();
311 | final int coverFlowCenter = coverFlowWidth / 2;
312 | final int childWidth = item.getWidth();
313 | final int childHeight = item.getHeight();
314 | final int childCenter = item.getLeft() + childWidth / 2;
315 |
316 | // Use coverflow width when its defined as automatic.
317 | final int actionDistance = (this.actionDistance == ACTION_DISTANCE_AUTO) ? (int) ((coverFlowWidth + childWidth) / 2.0f) : this.actionDistance;
318 |
319 | // Calculate the abstract amount for all effects.
320 | final float effectsAmount = Math.min(1.0f, Math.max(-1.0f, (1.0f / actionDistance) * (childCenter - coverFlowCenter)));
321 |
322 | // Clear previous transformations and set transformation type (matrix + alpha).
323 | t.clear();
324 | t.setTransformationType(Transformation.TYPE_BOTH);
325 |
326 | // Alpha
327 | if (this.unselectedAlpha != 1) {
328 | final float alphaAmount = (this.unselectedAlpha - 1) * Math.abs(effectsAmount) + 1;
329 | t.setAlpha(alphaAmount);
330 | }
331 |
332 | // Saturation
333 | if (this.unselectedSaturation != 1) {
334 | // Pass over saturation to the wrapper.
335 | final float saturationAmount = (this.unselectedSaturation - 1) * Math.abs(effectsAmount) + 1;
336 | item.setSaturation(saturationAmount);
337 | }
338 |
339 | final Matrix imageMatrix = t.getMatrix();
340 |
341 | // Apply rotation.
342 | if (this.maxRotation != 0) {
343 | final int rotationAngle = (int) (-effectsAmount * this.maxRotation);
344 | this.transformationCamera.save();
345 | this.transformationCamera.rotateY(rotationAngle);
346 | this.transformationCamera.getMatrix(imageMatrix);
347 | this.transformationCamera.restore();
348 | }
349 |
350 | // Zoom.
351 | if (this.unselectedScale != 1) {
352 | final float zoomAmount = (this.unselectedScale - 1) * Math.abs(effectsAmount) + 1;
353 | // Calculate the scale anchor (y anchor can be altered)
354 | final float translateX = childWidth / 2.0f;
355 | final float translateY = childHeight * this.scaleDownGravity;
356 | imageMatrix.preTranslate(-translateX, -translateY);
357 | imageMatrix.postScale(zoomAmount, zoomAmount);
358 | imageMatrix.postTranslate(translateX, translateY);
359 | }
360 |
361 | return true;
362 | }
363 |
364 | // =============================================================================
365 | // Public classes
366 | // =============================================================================
367 |
368 | public static class LayoutParams extends Gallery.LayoutParams {
369 | public LayoutParams(Context c, AttributeSet attrs) {
370 | super(c, attrs);
371 | }
372 |
373 | public LayoutParams(int w, int h) {
374 | super(w, h);
375 | }
376 |
377 | public LayoutParams(ViewGroup.LayoutParams source) {
378 | super(source);
379 | }
380 | }
381 | }
382 |
--------------------------------------------------------------------------------