├── README.md └── Library └── java └── com └── tzanou └── PercentVisibleLayout └── PercentVisibleLayout.java /README.md: -------------------------------------------------------------------------------- 1 | # PercentVisibleLayout 2 | 3 | PercentVisibleLayout is a layout (extends RelativeLayout) with a custom listener which gives the visibility percentage of the layout every time it is changed.Pixel visibility listener is also available. 4 | 5 | ### Currently supporting 6 | - Use **ONLY** inside Listviews,RecyclerViews,ScrollViews,Viewpager etc. 7 | - Percentage Listener with visible height/width percentage and flags for which part is missing 8 | - Pixels Listener with visible height/width pixels and flags for which part is missing 9 | 10 | 11 | 12 | 13 | ### Demo 14 | 15 | [![](https://pinalbookclub.files.wordpress.com/2013/12/google-play-icon-small.png?w=593)](https://play.google.com/store/apps/details?id=demo.percentvisiblelayout.tzanou.gr.percentvisiblelayoutdemo) 16 | 17 | 18 | ![alt text](http://i268.photobucket.com/albums/jj26/tzanou/simple_zpskny3oz8q.gif ) ![alt text](http://i268.photobucket.com/albums/jj26/tzanou/complex_zpsdvhsxfkn.gif ) ![alt text](http://i268.photobucket.com/albums/jj26/tzanou/horizontal_zpsen0debme.gif ) 19 | 20 | ### Usage 21 | 22 | 23 | 24 | #### In your xml file 25 | 26 | ```xml 27 | 32 | 33 | 38 | 39 | 40 | ``` 41 | #### In your activity 42 | 43 | ```java 44 | 45 | mCustomLayout=(PercentVisibleLayout) findViewById(R.id.custom_layout); 46 | 47 | mCustomLayout.setOnVisibilityPercentChangedListener(new PercentVisibleLayout.OnVisibilityPercentChanged() { 48 | @Override 49 | public void onVisibilityChange(int fromHeight, int fromWidth, int percentageHeight, int percentageWidth) { 50 | holder.mText.setText( percentageHeight+"%" ); 51 | } 52 | }); 53 | ``` 54 | 55 | ## More examples and methods on [Wiki Page](https://github.com/tzanou/VisibilityPercentageLayout/wiki) 56 | 57 | ##Download 58 | 59 | ``` 60 | dependencies { 61 | compile 'com.tzanou:PercentVisibleLayout:1.1.2@aar' 62 | } 63 | ``` 64 | 65 | or Downwnload [PercentVisibleLayout.java](https://github.com/tzanou/PercentVisibleLayout/blob/master/Library/java/com/tzanou/PercentVisibleLayout/PercentVisibleLayout.java) 66 | 67 | 68 | ##Licensing 69 | 70 | Copyright 2015 George Tzanoudakis 71 | 72 | Licensed under the Apache License, Version 2.0 (the "License"); 73 | you may not use this file except in compliance with the License. 74 | You may obtain a copy of the License at 75 | 76 | http://www.apache.org/licenses/LICENSE-2.0 77 | 78 | Unless required by applicable law or agreed to in writing, software 79 | distributed under the License is distributed on an "AS IS" BASIS, 80 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 81 | See the License for the specific language governing permissions and 82 | limitations under the License. 83 | -------------------------------------------------------------------------------- /Library/java/com/tzanou/PercentVisibleLayout/PercentVisibleLayout.java: -------------------------------------------------------------------------------- 1 | package com.tzanou.PercentVisibleLayout; 2 | 3 | import android.content.Context; 4 | import android.graphics.Rect; 5 | import android.util.AttributeSet; 6 | import android.util.Log; 7 | import android.view.ViewTreeObserver; 8 | import android.widget.RelativeLayout; 9 | 10 | /** 11 | * Created by tzanou on 8/28/15. 12 | */ 13 | public class PercentVisibleLayout extends RelativeLayout { 14 | 15 | 16 | private OnVisibilityPercentChanged mPercentageListener; 17 | private OnVisibilityPixelChanged mPixelVisibilityListener; 18 | private String id = ""; 19 | private Context mContext; 20 | private int lastPixelWidth, lastPixelHeight, lastPercentageWidht, lastPercentageHeight; 21 | private int minHorizontalPercentage = 0; 22 | private int maxHorizontalPercentage = 101; 23 | private int minVerticalPercentage = 0; 24 | private int maxVerticalPercentage = 101; 25 | private boolean duplicateEnabled = false; 26 | public static final int TOP = 1; 27 | public static final int BOTTOM = 3; 28 | public static final int RIGHT = 2; 29 | public static final int LEFT = 4; 30 | public static final int LEFT_AND_RIGHT = 5; 31 | public static final int TOP_AND_BOTTOM = 6; 32 | public static final int NOWHERE = 7; 33 | 34 | 35 | public PercentVisibleLayout(Context context, AttributeSet attrs) { 36 | super(context, attrs); 37 | this.mContext = context; 38 | this.mPercentageListener = null; 39 | 40 | 41 | this.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() { 42 | @Override 43 | public void onScrollChanged() { 44 | calculateVisibility(); 45 | 46 | 47 | } 48 | }); 49 | 50 | } 51 | 52 | 53 | public PercentVisibleLayout(Context context, AttributeSet attrs, int defStyleAttr, String id) { 54 | super(context, attrs, defStyleAttr); 55 | 56 | } 57 | 58 | public PercentVisibleLayout(Context context, AttributeSet attrs, String id) { 59 | super(context, attrs); 60 | 61 | } 62 | 63 | public PercentVisibleLayout(Context context) { 64 | super(context); 65 | 66 | } 67 | 68 | 69 | 70 | @Override 71 | public void setRotation(float rotation) { 72 | // super.setRotation(rotation); 73 | } 74 | 75 | private void calculateVisibility() { 76 | 77 | 78 | Rect rectf = new Rect(); 79 | this.getLocalVisibleRect(rectf); 80 | 81 | 82 | 83 | int fromWhereHeigth; 84 | int fromWhereWidht; 85 | int top = rectf.top; 86 | int bottom = rectf.bottom; 87 | int right = rectf.right; 88 | int left = rectf.left; 89 | int width = this.getWidth(); 90 | int height = this.getHeight(); 91 | int heightPercentage; 92 | int heightPixels; 93 | int widthPercentage; 94 | int widthPixels; 95 | 96 | 97 | if (top != 0 && bottom != height) { 98 | fromWhereHeigth = TOP_AND_BOTTOM; 99 | 100 | } else if (top != 0) { 101 | fromWhereHeigth = TOP; 102 | } else if (bottom != height) { 103 | fromWhereHeigth = BOTTOM; 104 | 105 | } else { 106 | fromWhereHeigth = NOWHERE; 107 | } 108 | 109 | 110 | if (left != 0 && right != width) { 111 | fromWhereWidht = LEFT_AND_RIGHT; 112 | 113 | } else if (left != 0) { 114 | fromWhereWidht = LEFT; 115 | } else if (right != width) { 116 | fromWhereWidht = RIGHT; 117 | 118 | } else { 119 | fromWhereWidht = NOWHERE; 120 | } 121 | 122 | 123 | heightPixels = height + top - bottom; 124 | widthPixels = width + left - right; 125 | 126 | heightPercentage = (int) (100 - ((double) (heightPixels) / height) * 100); 127 | widthPercentage = (int) (100 - ((double) (widthPixels) / width) * 100); 128 | 129 | if (top > height || bottom > height) { 130 | heightPercentage = 0; 131 | heightPixels = 0; 132 | } 133 | 134 | if (right > width || left > width) { 135 | widthPercentage = 0; 136 | widthPixels = 0; 137 | } 138 | 139 | 140 | if (mPercentageListener != null && isBetweenHorizontalPercentageLimits(widthPercentage) && isBetweenVerticalPercentageLimits(heightPercentage)) { 141 | 142 | if (duplicateEnabled || (!duplicateEnabled && (lastPercentageHeight != heightPercentage || lastPercentageWidht!=widthPercentage))){ 143 | lastPercentageHeight=heightPercentage; 144 | lastPercentageWidht=widthPercentage; 145 | mPercentageListener.onVisibilityChange(fromWhereHeigth, fromWhereWidht, heightPercentage, widthPercentage); 146 | 147 | } 148 | 149 | 150 | 151 | } 152 | 153 | 154 | 155 | if (mPixelVisibilityListener != null) { 156 | mPixelVisibilityListener.onVisibilityChange(fromWhereHeigth, fromWhereWidht, heightPixels, widthPixels); 157 | } 158 | 159 | 160 | 161 | 162 | 163 | 164 | } 165 | 166 | 167 | public void setMinHortizontalPercentage(int perc){ 168 | if(perc>=0 && perc <=100){ 169 | this.minHorizontalPercentage=perc; 170 | }else{ 171 | Log.d("tzanouError","Sorry not a percentage"); 172 | } 173 | 174 | } 175 | 176 | 177 | public void setMaxHorizontalPercentage(int perc){ 178 | if(perc>=0 && perc <=100){ 179 | this.maxHorizontalPercentage=perc; 180 | }else{ 181 | Log.d("tzanouError","Sorry not a percentage"); 182 | } 183 | 184 | } 185 | 186 | public void setMinVerticalPercentage(int perc){ 187 | if(perc>=0 && perc <=100){ 188 | this.minVerticalPercentage=perc; 189 | }else{ 190 | Log.d("tzanouError","Sorry not a percentage"); 191 | } 192 | 193 | } 194 | 195 | 196 | public void setMaxVerticalPercentage(int perc){ 197 | if(perc>=0 && perc <=100){ 198 | this.maxVerticalPercentage=perc; 199 | }else{ 200 | Log.d("tzanouError","Sorry not a percentage"); 201 | } 202 | 203 | } 204 | 205 | 206 | public void resetPercentageLimits(){ 207 | this.minHorizontalPercentage = 0; 208 | this.maxHorizontalPercentage = 101; 209 | this.minVerticalPercentage = 0; 210 | this.maxVerticalPercentage = 101; 211 | 212 | } 213 | 214 | public void allowDuplicates(boolean bool){ 215 | this.duplicateEnabled=bool; 216 | 217 | } 218 | 219 | 220 | private boolean isBetweenHorizontalPercentageLimits(int a){ 221 | if(a<=maxHorizontalPercentage && a>=minHorizontalPercentage){ 222 | return true; 223 | }else{ 224 | return false; 225 | } 226 | } 227 | 228 | 229 | private boolean isBetweenVerticalPercentageLimits(int a){ 230 | if(a<=maxVerticalPercentage && a>=minVerticalPercentage){ 231 | return true; 232 | }else{ 233 | return false; 234 | } 235 | } 236 | 237 | 238 | 239 | 240 | public interface OnVisibilityPercentChanged { 241 | void onVisibilityChange(int verticalClip,int horizontalClip,int percentageHeight,int percentageWidth); 242 | } 243 | 244 | public void setOnVisibilityPercentChangedListener(OnVisibilityPercentChanged eventListener) { 245 | mPercentageListener = eventListener; 246 | } 247 | 248 | public void removeVisibilityPercentageListener() { 249 | mPercentageListener = null; 250 | } 251 | 252 | 253 | 254 | 255 | 256 | public interface OnVisibilityPixelChanged { 257 | void onVisibilityChange(int verticalClip,int horizontalClip,int pixelHeight,int pixelWidth); 258 | } 259 | 260 | public void setOnVisibilityPixelChangedListener(OnVisibilityPixelChanged eventListener) { 261 | mPixelVisibilityListener = eventListener; 262 | } 263 | 264 | public void removePixelPercentageListener() { 265 | mPixelVisibilityListener = null; 266 | } 267 | 268 | 269 | 270 | } 271 | --------------------------------------------------------------------------------