WindowAlignment.java revision 8b068ddbbf22a246eab49ec25a2f7c3abfbdca51
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. 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 distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15package android.support.v17.leanback.widget; 16 17import static android.support.v17.leanback.widget.BaseListView.WINDOW_ALIGN_LOW_EDGE; 18import static android.support.v17.leanback.widget.BaseListView.WINDOW_ALIGN_HIGH_EDGE; 19import static android.support.v17.leanback.widget.BaseListView.WINDOW_ALIGN_BOTH_EDGE; 20import static android.support.v17.leanback.widget.BaseListView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED; 21 22import static android.support.v7.widget.RecyclerView.HORIZONTAL; 23 24/** 25 * Maintains Window Alignment information of two axis. 26 */ 27class WindowAlignment { 28 29 /** 30 * Maintains alignment information in one direction. 31 */ 32 public static class Axis { 33 /** 34 * mScrollCenter is used to calculate dynamic transformation based on how far a view 35 * is from the mScrollCenter. For example, the views with center close to mScrollCenter 36 * will be scaled up. 37 */ 38 private float mScrollCenter; 39 /** 40 * Right or bottom edge of last child. 41 */ 42 private int mMaxEdge; 43 /** 44 * Left or top edge of first child, typically should be zero. 45 */ 46 private int mMinEdge; 47 48 private int mWindowAlignment = WINDOW_ALIGN_BOTH_EDGE; 49 50 private int mWindowAlignmentOffset = 0; 51 52 private float mWindowAlignmentOffsetPercent = 50f; 53 54 private int mSize; 55 56 private int mPaddingLow; 57 58 private int mPaddingHigh; 59 60 private String mName; // for debugging 61 62 public Axis(String name) { 63 reset(); 64 mName = name; 65 } 66 67 final public int getWindowAlignment() { 68 return mWindowAlignment; 69 } 70 71 final public void setWindowAlignment(int windowAlignment) { 72 mWindowAlignment = windowAlignment; 73 } 74 75 final public int getWindowAlignmentOffset() { 76 return mWindowAlignmentOffset; 77 } 78 79 final public void setWindowAlignmentOffset(int offset) { 80 mWindowAlignmentOffset = offset; 81 } 82 83 final public void setWindowAlignmentOffsetPercent(float percent) { 84 if ((percent < 0 || percent > 100) 85 && percent != WINDOW_ALIGN_OFFSET_PERCENT_DISABLED) { 86 throw new IllegalArgumentException(); 87 } 88 mWindowAlignmentOffsetPercent = percent; 89 } 90 91 final public float getWindowAlignmentOffsetPercent() { 92 return mWindowAlignmentOffsetPercent; 93 } 94 95 final public int getScrollCenter() { 96 return (int) mScrollCenter; 97 } 98 99 /** set minEdge, Integer.MIN_VALUE means unknown*/ 100 final public void setMinEdge(int minEdge) { 101 mMinEdge = minEdge; 102 } 103 104 public void invalidateScrollMin() { 105 mMinEdge = Integer.MIN_VALUE; 106 } 107 108 /** update max edge, Integer.MAX_VALUE means unknown*/ 109 final public void setMaxEdge(int maxEdge) { 110 mMaxEdge = maxEdge; 111 } 112 113 public void invalidateScrollMax() { 114 mMaxEdge = Integer.MAX_VALUE; 115 } 116 117 final public float updateScrollCenter(float scrollTarget) { 118 mScrollCenter = scrollTarget; 119 return scrollTarget; 120 } 121 122 private void reset() { 123 mScrollCenter = Integer.MIN_VALUE; 124 mMinEdge = Integer.MIN_VALUE; 125 mMaxEdge = Integer.MAX_VALUE; 126 } 127 128 final public boolean isMinUnknown() { 129 return mMinEdge == Integer.MIN_VALUE; 130 } 131 132 final public boolean isMaxUnknown() { 133 return mMaxEdge == Integer.MAX_VALUE; 134 } 135 136 final public void setSize(int size) { 137 mSize = size; 138 } 139 140 final public int getSize() { 141 return mSize; 142 } 143 144 final public void setPadding(int paddingLow, int paddingHigh) { 145 mPaddingLow = paddingLow; 146 mPaddingHigh = paddingHigh; 147 } 148 149 final public int getPaddingLow() { 150 return mPaddingLow; 151 } 152 153 final public int getPaddingHigh() { 154 return mPaddingHigh; 155 } 156 157 final public int getClientSize() { 158 return mSize - mPaddingLow - mPaddingHigh; 159 } 160 161 final public int getSystemScrollPos() { 162 return getSystemScrollPos((int) mScrollCenter); 163 } 164 165 final public int getSystemScrollPos(int scrollCenter) { 166 int middlePosition; 167 if (mWindowAlignmentOffset >= 0) { 168 middlePosition = mWindowAlignmentOffset - mPaddingLow; 169 } else { 170 middlePosition = mSize + mWindowAlignmentOffset - mPaddingLow; 171 } 172 if (mWindowAlignmentOffsetPercent != WINDOW_ALIGN_OFFSET_PERCENT_DISABLED) { 173 middlePosition += (int) (mSize * mWindowAlignmentOffsetPercent / 100); 174 } 175 int clientSize = getClientSize(); 176 int afterMiddlePosition = clientSize - middlePosition; 177 boolean isMinUnknown = isMinUnknown(); 178 boolean isMaxUnknown = isMaxUnknown(); 179 if (!isMinUnknown && !isMaxUnknown && 180 (mWindowAlignment & WINDOW_ALIGN_BOTH_EDGE) == WINDOW_ALIGN_BOTH_EDGE) { 181 if (mMaxEdge - mMinEdge <= clientSize) { 182 // total children size is less than view port and we want to align 183 // both edge: align first child to left edge of view port 184 return mMinEdge - mPaddingLow; 185 } 186 } 187 if (!isMinUnknown) { 188 if ((mWindowAlignment & WINDOW_ALIGN_LOW_EDGE) != 0 && 189 scrollCenter - mMinEdge <= middlePosition) { 190 // scroll center is within half of view port size: align the left edge 191 // of first child to the left edge of view port 192 return mMinEdge - mPaddingLow; 193 } 194 } 195 if (!isMaxUnknown) { 196 if ((mWindowAlignment & WINDOW_ALIGN_HIGH_EDGE) != 0 && 197 mMaxEdge - scrollCenter <= afterMiddlePosition) { 198 // scroll center is very close to the right edge of view port : align the 199 // right edge of last children (plus expanded size) to view port's right 200 return mMaxEdge -mPaddingLow - (clientSize); 201 } 202 } 203 // else put scroll center in middle of view port 204 return scrollCenter - middlePosition - mPaddingLow; 205 } 206 207 @Override 208 public String toString() { 209 return "center: " + mScrollCenter + " min:" + mMinEdge + 210 " max:" + mMaxEdge; 211 } 212 213 } 214 215 private int mOrientation = HORIZONTAL; 216 217 final public Axis vertical = new Axis("vertical"); 218 219 final public Axis horizontal = new Axis("horizontal"); 220 221 private Axis mMainAxis = horizontal; 222 223 private Axis mSecondAxis = vertical; 224 225 final public Axis mainAxis() { 226 return mMainAxis; 227 } 228 229 final public Axis secondAxis() { 230 return mSecondAxis; 231 } 232 233 final public void setOrientation(int orientation) { 234 mOrientation = orientation; 235 if (mOrientation == HORIZONTAL) { 236 mMainAxis = horizontal; 237 mSecondAxis = vertical; 238 } else { 239 mMainAxis = vertical; 240 mSecondAxis = horizontal; 241 } 242 } 243 244 final public int getOrientation() { 245 return mOrientation; 246 } 247 248 final public void reset() { 249 mainAxis().reset(); 250 } 251 252 @Override 253 public String toString() { 254 return new StringBuffer().append("horizontal=") 255 .append(horizontal.toString()) 256 .append("vertical=") 257 .append(vertical.toString()) 258 .toString(); 259 } 260 261} 262