1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.widget; 18 19 import android.annotation.Nullable; 20 import android.content.Context; 21 import android.graphics.Rect; 22 import android.graphics.drawable.Drawable; 23 import android.util.AttributeSet; 24 import android.view.View; 25 import android.view.ViewGroup; 26 import android.view.ViewGroup.LayoutParams; 27 28 import com.android.internal.util.Predicate; 29 import com.android.internal.widget.PagerAdapter; 30 import com.android.internal.widget.ViewPager; 31 32 import java.util.ArrayList; 33 34 /** 35 * This displays a list of months in a calendar format with selectable days. 36 */ 37 class DayPickerViewPager extends ViewPager { 38 private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1); 39 DayPickerViewPager(Context context)40 public DayPickerViewPager(Context context) { 41 this(context, null); 42 } 43 DayPickerViewPager(Context context, AttributeSet attrs)44 public DayPickerViewPager(Context context, AttributeSet attrs) { 45 this(context, attrs, 0); 46 } 47 DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr)48 public DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr) { 49 this(context, attrs, defStyleAttr, 0); 50 } 51 DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)52 public DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr, 53 int defStyleRes) { 54 super(context, attrs, defStyleAttr, defStyleRes); 55 } 56 57 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)58 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 59 populate(); 60 61 // Everything below is mostly copied from FrameLayout. 62 int count = getChildCount(); 63 64 final boolean measureMatchParentChildren = 65 MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY || 66 MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY; 67 68 int maxHeight = 0; 69 int maxWidth = 0; 70 int childState = 0; 71 72 for (int i = 0; i < count; i++) { 73 final View child = getChildAt(i); 74 if (child.getVisibility() != GONE) { 75 measureChild(child, widthMeasureSpec, heightMeasureSpec); 76 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 77 maxWidth = Math.max(maxWidth, child.getMeasuredWidth()); 78 maxHeight = Math.max(maxHeight, child.getMeasuredHeight()); 79 childState = combineMeasuredStates(childState, child.getMeasuredState()); 80 if (measureMatchParentChildren) { 81 if (lp.width == LayoutParams.MATCH_PARENT || 82 lp.height == LayoutParams.MATCH_PARENT) { 83 mMatchParentChildren.add(child); 84 } 85 } 86 } 87 } 88 89 // Account for padding too 90 maxWidth += getPaddingLeft() + getPaddingRight(); 91 maxHeight += getPaddingTop() + getPaddingBottom(); 92 93 // Check against our minimum height and width 94 maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); 95 maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); 96 97 // Check against our foreground's minimum height and width 98 final Drawable drawable = getForeground(); 99 if (drawable != null) { 100 maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); 101 maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); 102 } 103 104 setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), 105 resolveSizeAndState(maxHeight, heightMeasureSpec, 106 childState << MEASURED_HEIGHT_STATE_SHIFT)); 107 108 count = mMatchParentChildren.size(); 109 if (count > 1) { 110 for (int i = 0; i < count; i++) { 111 final View child = mMatchParentChildren.get(i); 112 113 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 114 final int childWidthMeasureSpec; 115 final int childHeightMeasureSpec; 116 117 if (lp.width == LayoutParams.MATCH_PARENT) { 118 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( 119 getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), 120 MeasureSpec.EXACTLY); 121 } else { 122 childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 123 getPaddingLeft() + getPaddingRight(), 124 lp.width); 125 } 126 127 if (lp.height == LayoutParams.MATCH_PARENT) { 128 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( 129 getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), 130 MeasureSpec.EXACTLY); 131 } else { 132 childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 133 getPaddingTop() + getPaddingBottom(), 134 lp.height); 135 } 136 137 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 138 } 139 } 140 141 mMatchParentChildren.clear(); 142 } 143 144 @Override findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip)145 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { 146 if (predicate.apply(this)) { 147 return this; 148 } 149 150 // Always try the selected view first. 151 final DayPickerPagerAdapter adapter = (DayPickerPagerAdapter) getAdapter(); 152 final SimpleMonthView current = adapter.getView(getCurrent()); 153 if (current != childToSkip && current != null) { 154 final View v = current.findViewByPredicate(predicate); 155 if (v != null) { 156 return v; 157 } 158 } 159 160 final int len = getChildCount(); 161 for (int i = 0; i < len; i++) { 162 final View child = getChildAt(i); 163 164 if (child != childToSkip && child != current) { 165 final View v = child.findViewByPredicate(predicate); 166 167 if (v != null) { 168 return v; 169 } 170 } 171 } 172 173 return null; 174 } 175 176 } 177