├── LICENSE
├── README.md
├── controllers
└── widget.js
├── docs
└── screenshot1.png
├── styles
└── widget.tss
├── views
└── widget.xml
└── widget.json
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Apra Informatica
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ti.ImageViewer
2 | Image viewer widget for Appcelerator Titanium
3 |
4 | With this image viewer it's possible to show a single - zoomable, scrollable and pinchable - local image on iOS and Android (on iOS also remote images).
5 |
6 | It uses module org.iotashan.TiTouchImageView (on Android), and installation of this module is necessary if you mean to use the widget on Android.
7 |
8 | 
9 |
10 | ## Installation
11 |
12 | Add in your *config.json*, under `dependencies`:
13 |
14 | ```
15 | "dependencies": {
16 | "it.apra.tiimageviewer": "*"
17 | }
18 | ```
19 |
20 | ## Usage
21 | ```javascript
22 | widget = Alloy.createWidget('it.apra.tiimageviewer', {
23 | 'image' : filepath,
24 | 'title' : filename,
25 | 'subtitle' : des
26 | });
27 | ```
28 |
29 | ## Usage with Alloy
30 | ```xml
31 |
32 | ```
33 |
34 | **Args**
35 | * **image**: image filepath
36 | * **title**: optional image title (showed in lower panel)
37 | * **subtitle**: optional image subtitle (showed in lower panel)
38 | * **lowerInfoHidden**: if true hides lower info panel
39 | * **lowerGradientHidden**: if true hides lower info panel gradient
40 | * **backgroundColor**: backgroundColor (default is 'black')
41 |
42 | **Functions**
43 | * **removeEventListeners**: removes all listeners on controls
44 | * **reloadImage**: reloads the image
45 | * **showLowerInfo**: showes lower info
46 | * **hideLowerInfo**: hides lower info
47 |
48 | ##Notes
49 | * Could be useful a compatibility on Android without the native module too (using a webview?)
50 | * The pinch-to-zoom and scroll on iOS are based on the widget https://github.com/CaffeinaLab/Ti.TiltImageView.
51 |
--------------------------------------------------------------------------------
/controllers/widget.js:
--------------------------------------------------------------------------------
1 | var args = arguments[0] || {};
2 | $.image = args.image;
3 | var title = args.title || "",
4 | subtitle = args.subtitle || "",
5 | lowerInfoHidden = args.lowerInfoHidden || args.lowerInfoHided || false,
6 | lowerGradientHidden = args.lowerGradientHidden || args.lowerGradientHided || false,
7 | backgroundColor = args.backgroundColor || 'black';
8 |
9 | var lastValidOrientation, imageView, imageLoad, orientationChange, removeEventListeners, showLowerInfo;
10 |
11 | lastValidOrientation = null;
12 |
13 | showLowerInfo = function(){
14 | if (!lowerInfoHidden){
15 | $.title.visible = true;
16 | $.description.visible = true;
17 | }
18 | };
19 | hideLowerInfo = function(){
20 | $.title.visible = false;
21 | $.description.visible = false;
22 | };
23 |
24 | if (OS_IOS) {
25 | (function(){
26 | var getMaxOffset, IMGS, OUTS, SS, LAYOUT, MINZOOMSCALE;
27 |
28 | imageView = Ti.UI.createImageView({
29 | 'image' : $.image,
30 | 'height': Ti.UI.SIZE,
31 | 'width': Ti.UI.SIZE,
32 | 'touchEnabled': false
33 | });
34 | $.imageViewContainer.add(imageView);
35 |
36 | getMaxOffset = function() {
37 | return (IMGS.width*$.imageViewContainer.zoomScale)-OUTS.width;
38 | };
39 |
40 | imageLoad = function(){
41 | Ti.API.debug('Loading imagetView ' + title);
42 |
43 | var size, rect, OR, IR, zoomScaleToFit;
44 |
45 | if (imageView.image != $.image) {
46 | imageView.image = $.image;
47 | }
48 | size = imageView.size;
49 | rect = $.index.size;
50 | IMGS = { width: size.width, height: size.height };
51 | OUTS = { width: rect.width, height: rect.height };
52 | OR = OUTS.width/OUTS.height;
53 | IR = IMGS.width/IMGS.height;
54 |
55 | // Recalculate if the min-height is not sufficient
56 | if (IMGS.heightOR) {
67 | LAYOUT = 'H';
68 | if (OUTS.height > 0 && IMGS.height > 0){
69 | MINZOOMSCALE = OUTS.height/IMGS.height;
70 | }
71 | SS = OUTS.width-40;
72 | $.scrollBar.applyProperties({
73 | bottom: 90, left: 20, right: 20, top: null,
74 | height: 1, width: Ti.UI.FILL
75 | });
76 | $.scrollBarInset.width = 60;
77 | } else {
78 | LAYOUT = 'V';
79 | if (OUTS.width > 0 && IMGS.width > 0){
80 | MINZOOMSCALE = OUTS.width/IMGS.width;
81 | }
82 | SS = OUTS.height-20;
83 | $.scrollBar.applyProperties({
84 | right: 20, left: null, top: 10, bottom: 10,
85 | height: Ti.UI.FILL, width: 1
86 | });
87 | $.scrollBarInset.height = 60;
88 | }
89 |
90 | // scalesToFit
91 | if (IMGS.width > OUTS.width || IMGS.height > OUTS.height) {
92 | zoomScaleToFit = Math.min(OUTS.height / IMGS.height, OUTS.width / IMGS.width);
93 | if (zoomScaleToFit > 0 && zoomScaleToFit < 1){
94 | MINZOOMSCALE = zoomScaleToFit;
95 | }
96 | }
97 | MINZOOMSCALE *= 0.95;
98 |
99 | $.imageViewContainer.minZoomScale = MINZOOMSCALE;
100 | $.imageViewContainer.zoomScale = MINZOOMSCALE;
101 | $.imageViewContainer.maxZoomScale = 5;
102 | };
103 |
104 | $.imageViewContainer.addEventListener('scroll', function(){
105 | if (LAYOUT==='H') {
106 | $.scrollBarInset.animate({
107 | left: (SS-60)*($.imageViewContainer.contentOffset.x/getMaxOffset())
108 | });
109 | } else {
110 | $.scrollBarInset.animate({
111 | top: (SS-60)*($.imageViewContainer.contentOffset.y/getMaxOffset())
112 | });
113 | }
114 | });
115 |
116 | imageView.addEventListener('load', imageLoad);
117 | $.index.addEventListener('singletap', function(e) {
118 | imageLoad();
119 | });
120 | }());
121 | } else if (OS_ANDROID){
122 | (function(){
123 | imageView = require('org.iotashan.TiTouchImageView').createView({
124 | 'image' : $.image,
125 | 'width': Ti.UI.FILL,
126 | 'height' : Ti.UI.FILL
127 | });
128 | $.imageViewContainer.add(imageView);
129 |
130 | imageLoad = function(){
131 | Ti.API.debug('Loading imagetView ' + title);
132 |
133 | if (imageView.image != $.image) {
134 | imageView.image = $.image;
135 | }
136 |
137 | imageView.resetZoom();
138 | };
139 | }());
140 | }
141 |
142 | (function(){
143 | var lastValidOrientation;
144 |
145 | orientationChange = function(e){
146 | if (e){
147 | Ti.API.debug('Orientation: ' + e.orientation);
148 | switch(e.orientation){
149 | case Ti.UI.PORTRAIT:
150 | case Ti.UI.UPSIDE_PORTRAIT:
151 | case Ti.UI.LANDSCAPE_LEFT:
152 | case Ti.UI.LANDSCAPE_RIGHT:
153 | if (e.orientation === lastValidOrientation){
154 | return;
155 | }
156 | lastValidOrientation = e.orientation;
157 | break;
158 | default:
159 | return;
160 | }
161 | }
162 |
163 | imageLoad();
164 | };
165 | Ti.Gesture.addEventListener('orientationchange', orientationChange);
166 | }());
167 |
168 | removeEventListeners = function(){
169 | Ti.API.debug('tiImageViewer: removingEventListeners ' + title);
170 |
171 | if (orientationChange) { Ti.Gesture.removeEventListener('orientationchange', orientationChange); }
172 | if (imageView && imageLoad) { imageView.removeEventListener('load', imageLoad); }
173 | };
174 |
175 |
176 | $.title.text = title;
177 | $.description.text = subtitle;
178 | $.index.backgroundColor = backgroundColor;
179 |
180 | if (lowerInfoHidden){
181 | hideLowerInfo();
182 | } else {
183 | showLowerInfo();
184 | }
185 |
186 | $.gradientImage.visible = !lowerGradientHidden;
187 |
188 | exports.reloadImage = imageLoad;
189 | exports.removeEventListeners = removeEventListeners;
190 | exports.showLowerInfo = showLowerInfo;
191 | exports.hideLowerInfo = hideLowerInfo;
192 |
--------------------------------------------------------------------------------
/docs/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apra-informatica/Ti.ImageViewer/7efcc9eb845d73187f7157af64901c4bebcc30da/docs/screenshot1.png
--------------------------------------------------------------------------------
/styles/widget.tss:
--------------------------------------------------------------------------------
1 | "#index":{
2 | width: Ti.UI.FILL,
3 | height: Ti.UI.FILL
4 | },
5 | "#imageViewContainer":{
6 | width: Ti.UI.FILL,
7 | height: Ti.UI.FILL
8 | },
9 | "#imageViewContainer[platform=ios]":{
10 | disableBounce: true
11 | },
12 | "#title":{
13 | touchEnabled: false,
14 | bottom: 40,
15 | left: 20,
16 | right: 20,
17 | height: 34,
18 | color: '#fff',
19 | shadow: {
20 | shadowColor: '#000',
21 | shadowOffset: { x: 0, y: 1 },
22 | shadowRadius: 4
23 | },
24 | font: {
25 | fontWeight: 'bold',
26 | fontSize: 24,
27 | }
28 | },
29 | "#description":{
30 | touchEnabled: false,
31 | bottom: 20,
32 | left: 20,
33 | right: 20,
34 | height: 18,
35 | color: '#fff',
36 | shadow: {
37 | shadowColor: '#000',
38 | shadowOffset: { x: 0, y: 1 },
39 | shadowRadius: 2
40 | },
41 | font: {
42 | fontSize: 14,
43 | }
44 | },
45 | "#scrollBar":{
46 | touchEnabled: false,
47 | bottom: 90,
48 | height: 1,
49 | left: 20,
50 | right: 20,
51 | backgroundColor: '#4fff'
52 | },
53 | "#scrollBarInset":{
54 | touchEnabled: false,
55 | width: 60,
56 | left: 0,
57 | top: 0,
58 | backgroundColor: '#fff'
59 | },
60 | "#gradientImage":{
61 | touchEnabled: false,
62 | bottom: 0,
63 | height: 260,
64 | backgroundGradient: {
65 | type: 'linear',
66 | startPoint: { x: 0, y: 0 },
67 | endPoint: { x: 0, y: '100%' },
68 | colors: [ { color: '#0000', offset: 0.0}, { color: '#000', offset: 1 } ],
69 | }
70 | }
--------------------------------------------------------------------------------
/views/widget.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/widget.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "it.apra.tiimageviewer",
3 | "name": "Ti.ImageViewer",
4 | "description" : "Image viewer widget for Appcelerator Titanium",
5 | "author": "Mauro Piccotti",
6 | "version": "1.0.1",
7 | "copyright":"Copyright (c) 2015",
8 | "min-alloy-version": "1.0",
9 | "min-titanium-version":"4.0",
10 | "tags":"fullscreen,image,view,viewer",
11 | "platforms":"android,ios"
12 | }
--------------------------------------------------------------------------------