Android 仪表板设计教程

红薯 发布于 2011/12/13 09:05
阅读 3K+
收藏 26

在手机 app 中,仪表板是一个非常重要的元素,为 app 的功能提供了直观的导航,在这个教程中我们将讲述如何创建 app 的仪表板界面。

我们将开发一个类似 facebook 的仪表板,如下图所示:

让我们从创建一个简单的项目开始。

1. 首先通过 File ⇒ New Android Project 创建一个新项目,填写项目的详情以及 Activity 名为 AndroidDashboardDesignActivity.
2. 在这个项目中,我将仪表板分成 Action Bar(Header), Dashboard 和 Footer 三部分,最后将它们合并在一起
3. 在 res/values 创建一个 styles.xml 文件,代码如下:

<resources>
    <style name="ActionBarCompat">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">50dp</item>
        <item name="android:orientation">horizontal</item>
        <item name="android:background">@drawable/actionbar_background</item>
;    </style>
 
    <style name="DashboardButton">
        <item name="android:layout_gravity">center_vertical</item>
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:gravity">center_horizontal</item>
        <item name="android:drawablePadding">2dp</item>
        <item name="android:textSize">16dp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textColor">#ff29549f</item>
        <item name="android:background">@null</item>
;    </style>   
 
   <style name="FooterBar">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">40dp</item>
        <item name="android:orientation">horizontal</item>
        <item name="android:background">#dedede</item>
    </style>
</resources>

接下来设计 Actionbar (Header)

首先设计两个图片:

1. 渐进的背景图
2. Logo

Android action bar and logo

4. 然后在 res/layout 目录下创建 actionbar_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/ActionBarCompat" ;>
 
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:clickable="false"
        android:paddingLeft="15dip"
        android:scaleType="center"
        android:src="@drawable/facebook_logo" ;/>
 
</LinearLayout>

设计仪表板

仪表板的设计需要设计一些图标,高度 90px

Android dashboard icons facebook

5. 创建一个 DashboardLayout.java

package com.androidhive.dashboard;
/*
 * Copyright 2011 Google Inc.
 *
 * 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.
 */
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
 
/**
 * Custom layout that arranges children in a grid-like manner, optimizing for even horizontal and
 * vertical whitespace.
 */
public class DashboardLayout extends ViewGroup {
 
    private static final int UNEVEN_GRID_PENALTY_MULTIPLIER = 10;
 
    private int mMaxChildWidth = 0;
    private int mMaxChildHeight = 0;
 
    public DashboardLayout(Context context) {
        super(context, null);
    }
 
    public DashboardLayout(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
    }
 
    public DashboardLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
 
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mMaxChildWidth = 0;
        mMaxChildHeight = 0;
 
        // Measure once to find the maximum child size.
 
        int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
                MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST);
        int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
                MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST);
 
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() == GONE) {
                continue;
            }
 
            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
 
            mMaxChildWidth = Math.max(mMaxChildWidth, child.getMeasuredWidth());
            mMaxChildHeight = Math.max(mMaxChildHeight, child.getMeasuredHeight());
        }
 
        // Measure again for each child to be exactly the same size.
 
        childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
                mMaxChildWidth, MeasureSpec.EXACTLY);
        childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
                mMaxChildHeight, MeasureSpec.EXACTLY);
 
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() == GONE) {
                continue;
            }
 
            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        }
 
        setMeasuredDimension(
                resolveSize(mMaxChildWidth, widthMeasureSpec),
                resolveSize(mMaxChildHeight, heightMeasureSpec));
    }
 
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int width = r - l;
        int height = b - t;
 
        final int count = getChildCount();
 
        // Calculate the number of visible children.
        int visibleCount = 0;
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() == GONE) {
                continue;
            }
            ++visibleCount;
        }
 
        if (visibleCount == 0) {
            return;
        }
 
        // Calculate what number of rows and columns will optimize for even horizontal and
        // vertical whitespace between items. Start with a 1 x N grid, then try 2 x N, and so on.
        int bestSpaceDifference = Integer.MAX_VALUE;
        int spaceDifference;
 
        // Horizontal and vertical space between items
        int hSpace = 0;
        int vSpace = 0;
 
        int cols = 1;
        int rows;
 
        while (true) {
            rows = (visibleCount - 1) / cols + 1;
 
            hSpace = ((width - mMaxChildWidth * cols) / (cols + 1));
            vSpace = ((height - mMaxChildHeight * rows) / (rows + 1));
 
            spaceDifference = Math.abs(vSpace - hSpace);
            if (rows * cols != visibleCount) {
                spaceDifference *= UNEVEN_GRID_PENALTY_MULTIPLIER;
            }
 
            if (spaceDifference < bestSpaceDifference) {
                // Found a better whitespace squareness/ratio
                bestSpaceDifference = spaceDifference;
 
                // If we found a better whitespace squareness and there's only 1 row, this is
                // the best we can do.
                if (rows == 1) {
                    break;
                }
            } else {
                // This is a worse whitespace ratio, use the previous value of cols and exit.
                --cols;
                rows = (visibleCount - 1) / cols + 1;
                hSpace = ((width - mMaxChildWidth * cols) / (cols + 1));
                vSpace = ((height - mMaxChildHeight * rows) / (rows + 1));
                break;
            }
 
            ++cols;
        }
 
        // Lay out children based on calculated best-fit number of rows and cols.
 
        // If we chose a layout that has negative horizontal or vertical space, force it to zero.
        hSpace = Math.max(0, hSpace);
        vSpace = Math.max(0, vSpace);
 
        // Re-use width/height variables to be child width/height.
        width = (width - hSpace * (cols + 1)) / cols;
        height = (height - vSpace * (rows + 1)) / rows;
 
        int left, top;
        int col, row;
        int visibleIndex = 0;
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() == GONE) {
                continue;
            }
 
            row = visibleIndex / cols;
            col = visibleIndex % cols;
 
            left = hSpace * (col + 1) + width * col;
            top = vSpace * (row + 1) + height * row;
 
            child.layout(left, top,
                    (hSpace == 0 && col == cols - 1) ? r : (left + width),
                    (vSpace == 0 && row == rows - 1) ? b : (top + height));
            ++visibleIndex;
        }
    }
}

6. 现在我们需要创建一个新的 xml 文件放在 src/layouts ,名为fragment_layout.xml

<!-- Your package folder -->
<com.androidhive.dashboard.DashboardLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    android:background="#f8f9fe" >
    <!--  News Feed Button -->
    <Button
        android:id="@+id/btn_news_feed"
;        style="@style/DashboardButton"
;        android:drawableTop="@drawable/btn_newsfeed"
;        android:text="News Feed" />
 
    <!--  Friends Button -->
    <Button
        android:id="@+id/btn_friends"
;        style="@style/DashboardButton"
;        android:drawableTop="@drawable/btn_friends"
;        android:text="Friends" />
 
    <!--  Messages Button -->
    <Button
        android:id="@+id/btn_messages"
;        style="@style/DashboardButton"
;        android:drawableTop="@drawable/btn_messages"
;        android:text="Messages" />
 
    <!--  Places Button -->
    <Button
        android:id="@+id/btn_places"
;        style="@style/DashboardButton"
;        android:drawableTop="@drawable/btn_places"
;        android:text="Places" />
 
    <!--  Events Button -->
    <Button
        android:id="@+id/btn_events"
;        style="@style/DashboardButton"
;        android:drawableTop="@drawable/btn_events"
;        android:text="Events" />
 
    <!--  Photos Button -->
    <Button
        android:id="@+id/btn_photos"
;        style="@style/DashboardButton"
;        android:drawableTop="@drawable/btn_photos"
;        android:text="Photos" />
 
</com.androidhive.dashboard.DashboardLayout>

该布局的运行结果如下图:

设计 Footer

7. 在 res/layout 创建新的布局 XML 文件,名为 footer_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/FooterBar" ;>
    <TextView android:text="www.facebook.com"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textColor="#606060"
            android:gravity="center"
            android:paddingTop="10dip"/>
</LinearLayout>

合并所有布局

8. 在 res/layouts 中创建布局文件 dashboard_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/home_root"
;    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
        <!-- Include Action Bar -->
        <include layout="@layout/actionbar_layout"/>
; 
        <!--  Include Fragmented dashboard -->
        <include layout="@layout/fragment_layout"/> ;  
 
        <!--  Include Footer -->
        <include layout="@layout/footer_layout"/>
; 
</LinearLayout>

在仪表版中切换 Activity

9. 打开并编辑主 Activity 类代码 (AndroidDashboardDesignActivity.java)

package com.androidhive.dashboard;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidhive.dashboard.R;
 
public class AndroidDashboardDesignActivity extends Activity {
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dashboard_layout);
 
        /**
         * Creating all buttons instances
         * */
        // Dashboard News feed button
        Button btn_newsfeed = (Button) findViewById(R.id.btn_news_feed);
 
        // Dashboard Friends button
        Button btn_friends = (Button) findViewById(R.id.btn_friends);
 
        // Dashboard Messages button
        Button btn_messages = (Button) findViewById(R.id.btn_messages);
 
        // Dashboard Places button
        Button btn_places = (Button) findViewById(R.id.btn_places);
 
        // Dashboard Events button
        Button btn_events = (Button) findViewById(R.id.btn_events);
 
        // Dashboard Photos button
        Button btn_photos = (Button) findViewById(R.id.btn_photos);
 
        /**
         * Handling all button click events
         * */
 
        // Listening to News Feed button click
        btn_newsfeed.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View view) {
                // Launching News Feed Screen
                Intent i = new Intent(getApplicationContext(), NewsFeedActivity.class);
                startActivity(i);
            }
        });
 
       // Listening Friends button click
        btn_friends.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View view) {
                // Launching News Feed Screen
                Intent i = new Intent(getApplicationContext(), FriendsActivity.class);
                startActivity(i);
            }
        });
 
        // Listening Messages button click
        btn_messages.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View view) {
                // Launching News Feed Screen
                Intent i = new Intent(getApplicationContext(), MessagesActivity.class);
                startActivity(i);
            }
        });
 
        // Listening to Places button click
        btn_places.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View view) {
                // Launching News Feed Screen
                Intent i = new Intent(getApplicationContext(), PlacesActivity.class);
                startActivity(i);
            }
        });
 
        // Listening to Events button click
        btn_events.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View view) {
                // Launching News Feed Screen
                Intent i = new Intent(getApplicationContext(), EventsActivity.class);
                startActivity(i);
            }
        });
 
        // Listening to Photos button click
        btn_photos.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View view) {
                // Launching News Feed Screen
                Intent i = new Intent(getApplicationContext(), PhotosActivity.class);
                startActivity(i);
            }
        });
    }
}

10. 创建一些新的 Activity 类

NewsFeedActivity.java
FriendsActivity.java
MessagesActivity.java
PlacesActivity.java
EventsActivity.java

PhotosActivity.java

package com.androidhive.dashboard;
 
import android.app.Activity;
import android.os.Bundle;
import androidhive.dashboard.R;
 
public class NewsFeedActivity extends Activity {
     /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.news_feed_layout);
    }
}

11. 为每个 Activity 创建布局
news_feed_layout.xml
friends_layout.xml
messages_layout.xml
places_layout.xml
events_layout.xml

photos_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#f8f9fe"
    android:orientation="vertical" >
 
    <include layout="@layout/actionbar_layout" ;/>
 
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >
 
        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:padding="15dip"
            android:text="News Feed Screen"
            android:textColor="#ff29549f"
            android:textSize="25dip"
            android:textStyle="bold" />
    </LinearLayout>
 
</LinearLayout>

添加 Activity 到 AndroidManifest.xml

12. 编辑 AndroidManifest.xml 代码如下

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="androidhive.dashboard"
    android:versionCode="1"
    android:versionName="1.0" >
 
    <uses-sdk android:minSdkVersion="8" />
 
    <application
        android:icon="@drawable/ic_launcher"
;        android:label="@string/app_name" ;>
        <activity
            android:label="@string/app_name"
;            android:name="com.androidhive.dashboard.AndroidDashboardDesignActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
        <!-- News Feed Activity -->
        <activity android:name="com.androidhive.dashboard.NewsFeedActivity" ></activity>
 
        <!-- Friends Activity -->
        <activity android:name="com.androidhive.dashboard.FriendsActivity" ></activity>
 
        <!-- Messages Activity -->
        <activity android:name="com.androidhive.dashboard.MessagesActivity" ></activity>
 
        <!-- Places Activity -->
        <activity android:name="com.androidhive.dashboard.PlacesActivity" ></activity>
 
        <!-- Events Activity -->
        <activity android:name="com.androidhive.dashboard.EventsActivity" ></activity>
 
        <!-- Photos Activity -->
        <activity android:name="com.androidhive.dashboard.PhotosActivity" ></activity>
    </application>
 
</manifest>

然后就开始运行吧,完整代码打包下载

加载中
0
黑菜妞妞
黑菜妞妞
这个不错,好好学学!!
0
r
rotiwen
多多学习!
0
LiangX
LiangX
好东西要                      顶!
0
星月
星月
真好 一定要好好看
0
ARTHURBEAR
ARTHURBEAR
学习了!要好好研究一下!
0
JavaGG
JavaGG
这个必需顶,不错
0
zhou-zhou
zhou-zhou
学习下,还不是很明白这个的作用
0
翟晓岩
太好了,楼主大爱
0
v
vinnie_mstr
this is sooooo good!
返回顶部
顶部