The file containing the source code shown below is located in the corresponding directory in <sdk>/samples/android-<version>/...
/* * Copyright (C) 2007 The Android开源工程 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.home; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.LayoutInflater; import android.widget.TextView; import java.util.List; /** * The ApplicationsStackLayout is a specialized layout used for the purpose of the home screen * only. This layout stacks various icons in three distinct areas: the recents, the favorites * (or faves) and the button. * * This layout supports two different orientations: vertical and horizontal. When horizontal, * the areas are laid out this way: * * [RECENTS][FAVES][BUTTON] * * When vertical, the layout is the following: * * [RECENTS] * [FAVES] * [BUTTON] * * The layout operates from the "bottom up" (or from right to left.) This means that the button * area will first be laid out, then the faves area, then the recents. When there are too many * favorites, the recents area is not displayed. * * The following attributes can be set in XML: * * orientation: horizontal or vertical * marginLeft: the left margin of each element in the stack * marginTop: the top margin of each element in the stack * marginRight: the right margin of each element in the stack * marginBottom: the bottom margin of each element in the stack */ public class ApplicationsStackLayout extends ViewGroup implements View.OnClickListener { public static final int HORIZONTAL = 0; public static final int VERTICAL = 1; private View mButton; private LayoutInflater mInflater; private int mFavoritesEnd; private int mFavoritesStart; private List<ApplicationInfo> mFavorites; private List<ApplicationInfo> mRecents; private int mOrientation = VERTICAL; private int mMarginLeft; private int mMarginTop; private int mMarginRight; private int mMarginBottom; private Rect mDrawRect = new Rect(); private Drawable mBackground; private int mIconSize; public ApplicationsStackLayout(Context context) { super(context); initLayout(); } public ApplicationsStackLayout(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ApplicationsStackLayout); mOrientation = a.getInt(R.styleable.ApplicationsStackLayout_stackOrientation, VERTICAL); mMarginLeft = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginLeft, 0); mMarginTop = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginTop, 0); mMarginRight = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginRight, 0); mMarginBottom = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginBottom, 0); a.recycle(); mIconSize = 42; //(int) getResources().getDimension(android.R.dimen.app_icon_size); initLayout(); } private void initLayout() { mInflater = LayoutInflater.from(getContext()); mButton = mInflater.inflate(R.layout.all_applications_button, this, false); addView(mButton); mBackground = getBackground(); setBackgroundDrawable(null); setWillNotDraw(false); } /** * Return the current orientation, either VERTICAL (default) or HORIZONTAL. * * @return the stack orientation */ public int getOrientation() { return mOrientation; } @Override protected void onDraw(Canvas canvas) { final Drawable background = mBackground; final int right = getWidth(); final int bottom = getHeight(); // Draw behind recents if (mOrientation == VERTICAL) { mDrawRect.set(0, 0, right, mFavoritesStart); } else { mDrawRect.set(0, 0, mFavoritesStart, bottom); } background.setBounds(mDrawRect); background.draw(canvas); // Draw behind favorites if (mFavoritesStart > -1) { if (mOrientation == VERTICAL) { mDrawRect.set(0, mFavoritesStart, right, mFavoritesEnd); } else { mDrawRect.set(mFavoritesStart, 0, mFavoritesEnd, bottom); } background.setBounds(mDrawRect); background.draw(canvas); } super.onDraw(canvas); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); final int widthMode = MeasureSpec.getMode(widthMeasureSpec); final int widthSize = MeasureSpec.getSize(widthMeasureSpec); final int heightMode = MeasureSpec.getMode(heightMeasureSpec); final int heightSize = MeasureSpec.getSize(heightMeasureSpec); if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) { throw new IllegalStateException("ApplicationsStackLayout can only be used with " + "measure spec mode=EXACTLY"); } setMeasuredDimension(widthSize, heightSize); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { removeAllApplications(); LayoutParams layoutParams = mButton.getLayoutParams(); final int widthSpec = MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.EXACTLY); final int heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY); mButton.measure(widthSpec, heightSpec); if (mOrientation == VERTICAL) { layoutVertical(); } else { layoutHorizontal(); } } private void layoutVertical() { int childLeft = 0; int childTop = getHeight(); int childWidth = mButton.getMeasuredWidth(); int childHeight = mButton.getMeasuredHeight(); childTop -= childHeight + mMarginBottom; mButton.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); childTop -= mMarginTop; mFavoritesEnd = childTop - mMarginBottom; int oldChildTop = childTop; childTop = stackApplications(mFavorites, childLeft, childTop); if (childTop != oldChildTop) { mFavoritesStart = childTop + mMarginTop; } else { mFavoritesStart = -1; } stackApplications(mRecents, childLeft, childTop); } private void layoutHorizontal() { int childLeft = getWidth(); int childTop = 0; int childWidth = mButton.getMeasuredWidth(); int childHeight = mButton.getMeasuredHeight(); childLeft -= childWidth; mButton.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); childLeft -= mMarginLeft; mFavoritesEnd = childLeft - mMarginRight; int oldChildLeft = childLeft; childLeft = stackApplications(mFavorites, childLeft, childTop); if (childLeft != oldChildLeft) { mFavoritesStart = childLeft + mMarginLeft; } else { mFavoritesStart = -1; } stackApplications(mRecents, childLeft, childTop); } private int stackApplications(List<ApplicationInfo> applications, int childLeft, int childTop) { LayoutParams layoutParams; int widthSpec; int heightSpec; int childWidth; int childHeight; final boolean isVertical = mOrientation == VERTICAL; final int count = applications.size(); for (int i = count - 1; i >= 0; i--) { final ApplicationInfo info = applications.get(i); final View view = createApplicationIcon(mInflater, this, info); layoutParams = view.getLayoutParams(); widthSpec = MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.EXACTLY); heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY); view.measure(widthSpec, heightSpec); childWidth = view.getMeasuredWidth(); childHeight = view.getMeasuredHeight(); if (isVertical) { childTop -= childHeight + mMarginBottom; if (childTop < 0) { childTop += childHeight + mMarginBottom; break; } } else { childLeft -= childWidth + mMarginRight; if (childLeft < 0) { childLeft += childWidth + mMarginRight; break; } } addViewInLayout(view, -1, layoutParams); view.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); if (isVertical) { childTop -= mMarginTop; } else { childLeft -= mMarginLeft; } } return isVertical ? childTop : childLeft; } private void removeAllApplications() { final int count = getChildCount(); for (int i = count - 1; i >= 0; i--) { final View view = getChildAt(i); if (view != mButton) { removeViewAt(i); } } } private View createApplicationIcon(LayoutInflater inflater, ViewGroup group, ApplicationInfo info) { TextView textView = (TextView) inflater.inflate(R.layout.favorite, group, false); info.icon.setBounds(0, 0, mIconSize, mIconSize); textView.setCompoundDrawables(null, info.icon, null, null); textView.setText(info.title); textView.setTag(info.intent); textView.setOnClickListener(this); return textView; } /** * Sets the list of favorites. * * @param applications the applications to put in the favorites area */ public void setFavorites(List<ApplicationInfo> applications) { mFavorites = applications; requestLayout(); } /** * Sets the list of recents. * * @param applications the applications to put in the recents area */ public void setRecents(List<ApplicationInfo> applications) { mRecents = applications; requestLayout(); } public void onClick(View v) { getContext().startActivity((Intent) v.getTag()); } }