跳到主要內容

Material Design - Card View and Recycler View

build.gradle (Module.app)

添加CardView,RecyclerView和Glide依賴關係。
  •  RecyclerView用於以網格方式顯示相冊。
  •  CardView用於顯示單個專輯項目。
  •  Glide用於顯示專輯封面圖片。

dependencies { 
    //CardView
    compile 'com.android.support:cardview-v7:25.3.1'
    //RecyclerView
    compile 'com.android.support:recyclerview-v7:25.3.1'
    //Glide ImageLoader....
    compile 'com.github.bumptech.glide:glide:3.7.0'
}

將以下字符串,顏色和調整資源添加到strings.xml,colors.xml和dimensions.xml文件。
string.xml
<resources>
    <string name="app_name">Card View</string>
    <string name="action_settings">Settings</string>
    <string name="action_add_favourite">Add to Favourites</string>
    <string name="action_play_next">Play Next</string>
    <string name="backdrop_title">LOVE MUSIC</string>
    <string name="backdrop_subtitle">This season top 20 albums</string>
</resources>

colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#F50057</color>
    <color name="colorPrimaryDark">#F50057</color>
    <color name="colorAccent">#FF4081</color>
    <color name="viewBg">#f1f5f8</color>
    <color name="album_title">#4c4c4c</color>
</resources>

dimensions.xml
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="fab_margin">16dp</dimen>
    <dimen name="item_offset">10dp</dimen>
    <dimen name="detail_backdrop_height">250dp</dimen>
    <dimen name="backdrop_title">30sp</dimen>
    <dimen name="backdrop_subtitle">18sp</dimen>
    <dimen name="card_margin">5dp</dimen>
    <dimen name="card_album_radius">0dp</dimen>
    <dimen name="album_cover_height">160dp</dimen>
    <dimen name="album_title_padding">10dp</dimen>
    <dimen name="album_title">15dp</dimen>
    <dimen name="songs_count_padding_bottom">5dp</dimen>
    <dimen name="songs_count">12sp</dimen>
    <dimen name="ic_album_overflow_width">20dp</dimen>
    <dimen name="ic_album_overflow_height">30dp</dimen>
    <dimen name="ic_album_overflow_margin_top">10dp</dimen>
</resources>

創建一個名為Album.java的類並添加以下代碼:

/**

 * Created by claire on 2017/10/12.

 * Album 專輯

 */

public class Album {
    private String name;
    private int numOfSongs;
    private int thumbnail; //縮圖

    public Album(){

    }

    public Album(String name, int numOfSongs, int thumbnail) {
        this.name = name;
        this.numOfSongs = numOfSongs;
        this.thumbnail = thumbnail;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getNumOfSongs() {
        return numOfSongs;
    }

    public void setNumOfSongs(int numOfSongs) {
        this.numOfSongs = numOfSongs;
    }

    public int getThumbnail() {
        return thumbnail;
    }

    public void setThumbnail(int thumbnail) {
        this.thumbnail = thumbnail;
    }
}

新增一個xm佈局來顯示專輯相冊。
1.在res⇒佈局下創建名為album_card.xml的xml佈局。
2.添加<android.support.v7.widget.CardView>,並添加了所有的相冊屬性, 如名稱,歌曲數量和封面圖像。
3.還添加了一個3點圖標,顯示一個彈出菜單點擊它。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.CardView
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_margin="@dimen/card_margin"
        android:elevation="3dp"
        card_view:cardCornerRadius="@dimen/card_album_radius">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ImageView
                android:id="@+id/thumbnail"
                android:layout_width="match_parent"
                android:layout_height="@dimen/album_cover_height"
                android:background="?attr/selectableItemBackgroundBorderless"
                android:clickable="true"
                android:scaleType="fitXY" />

            <TextView
                android:id="@+id/title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/thumbnail"
                android:paddingLeft="@dimen/album_title_padding"
                android:paddingRight="@dimen/album_title_padding"
                android:paddingTop="@dimen/album_title_padding"
                android:textColor="@color/album_title"
                android:textSize="@dimen/album_title" />

            <TextView
                android:id="@+id/count"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/title"
                android:paddingBottom="@dimen/songs_count_padding_bottom"
                android:paddingLeft="@dimen/album_title_padding"
                android:paddingRight="@dimen/album_title_padding"
                android:textSize="@dimen/songs_count" />

            <ImageView
                android:id="@+id/overflow"
                android:layout_width="@dimen/ic_album_overflow_width"
                android:layout_height="@dimen/ic_album_overflow_height"
                android:layout_alignParentRight="true"
                android:layout_below="@id/thumbnail"
                android:layout_marginTop="@dimen/ic_album_overflow_margin_top"
                android:scaleType="centerCrop"
                android:src="@drawable/ic_dots" />

        </RelativeLayout
    </android.support.v7.widget.CardView>
</LinearLayout>

在res⇒menu folder下創建名為menu_album.xml的菜單文件。
點擊每張專輯卡片上的點圖標,此菜單將顯示為彈出菜單。
menu_album.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <item
        android:id="@+id/action_add_favourite"
        android:orderInCategory="100"
        android:title="@string/action_add_favourite" />

    <item
        android:id="@+id/action_play_next"
        android:orderInCategory="101"
        android:title="@string/action_play_next" />
</menu>

為RecyclerView添加一個適配器 AlbumsAdapter.java,
album_card.xml來顯示內容
public class AlbumsAdapter extends RecyclerView.Adapter<AlbumsAdapter.MyViewHolder>{

    private Context mContext;

    private List<Album> albumList;



    public class MyViewHolder extends RecyclerView.ViewHolder {

        public TextView title, count;

        public ImageView thumbnail, overflow;

        public MyViewHolder(View itemView) {

            super(itemView);

            title = (TextView)itemView.findViewById(R.id.title);

            count = (TextView)itemView.findViewById(R.id.count);

            thumbnail = (ImageView)itemView.findViewById(R.id.thumbnail);

            overflow = (ImageView)itemView.findViewById(R.id.overflow);

        }

    }

    public AlbumsAdapter (Context mContext, List<Album> albumList){

        this.mContext = mContext;

        this.albumList = albumList;

    }



    @Override

    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View itemView = LayoutInflater.from(parent.getContext())

                .inflate(R.layout.album_card, parent, false);

        return new MyViewHolder(itemView);

    }

    @Override

    public void onBindViewHolder(final MyViewHolder holder, int position) {

        Album album = albumList.get(position);

        holder.title.setText(album.getName());

        holder.count.setText(album.getNumOfSongs() + " songs");

        //loading album cover using Glide library

        Glide.with(mContext).load(album.getThumbnail()).into(holder.thumbnail);

        holder.overflow.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                showPopupMenu(holder.overflow);

            }

        });

    }

    /**
     * Showing popup menu when tapping on 3 dots
     * @param view
     * Android 作業系統中,彈出式選單(PopupMenu)只能依附在 View 型別之物件
     */

    private void showPopupMenu(View view) {

        //inflate menu

        PopupMenu popup = new PopupMenu(mContext, view);

        MenuInflater inflater = popup.getMenuInflater();

        inflater.inflate(R.menu.menu_album, popup.getMenu());

        popup.setOnMenuItemClickListener(new MymenuItemClickListener());

        popup.show();

    }

    /**
     * Click listener for popup menu items
     */

    class MymenuItemClickListener implements PopupMenu.OnMenuItemClickListener{

        @Override

        public boolean onMenuItemClick(MenuItem menuItem) {

            switch (menuItem.getItemId()){

                case R.id.action_add_favourite:

                    Toast.makeText(mContext, "Add to favorite", Toast.LENGTH_SHORT).show();

                    return true;

                case R.id.action_play_next:

                    Toast.makeText(mContext, "Play next", Toast.LENGTH_SHORT).show();

                    return true;

                default:

            }

            return false;

        }

    }

    @Override

    public int getItemCount() {

        return albumList.size();

    }

}

開啟 main activity activity_main.xml and content_main.xml,
加上 AppBarLayout, CollapsingToolbarLayout, Toolbar and RecyclerView

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/detail_backdrop_height"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleTextAppearance="@android:color/transparent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

                <ImageView
                    android:id="@+id/backdrop"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:fitsSystemWindows="true"
                    android:scaleType="centerCrop"
                    app:layout_collapseMode="parallax" />

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:gravity="center_horizontal"
                    android:orientation="vertical">

                    <TextView
                        android:id="@+id/love_music"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/backdrop_title"
                        android:textColor="@android:color/white"
                        android:textSize="@dimen/backdrop_title" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/backdrop_subtitle"
                        android:textColor="@android:color/white"
                        android:textSize="@dimen/backdrop_subtitle" />

                </LinearLayout>
            </RelativeLayout>

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />


        </android.support.design.widget.CollapsingToolbarLayout>


    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main"/>

</android.support.design.widget.CoordinatorLayout>


content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/viewBg"
                app:layout_behavior="@string/appbar_scrolling_view_behavior"
                tools:context="com.admin.claire.cardviewandrecyclerview.MainActivity"
                tools:showIn="@layout/activity_main">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipToPadding="false"
        android:scrollbars="vertical" />

</RelativeLayout>

最後打開 MainActivity.java 並進行必要的
  • initCollapsingToolbar()-當工具欄折疊或展開時顯示或隱藏工具欄標題
  • prepareAlbums() – Adds sample albums data required for the recycler view.
  • GridLayoutManager用於以Grid格式顯示RecyclerView而不是列表。
  • GridSpacingItemDecoration用於在RecyclerView網格項周圍給出相等的邊距。
  • AlbumAdapter實例被創建並分配給RecyclerView,它以網格方式呈現CardView專輯。
package com.admin.claire.cardviewandrecyclerview;

import android.content.res.Resources;
import android.graphics.Rect;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.TypedValue;
import android.view.View;
import android.widget.ImageView;

import com.bumptech.glide.Glide;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private AlbumsAdapter adapter;
    private List<Album> albumList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        initCollapsingToolbar();

        recyclerView = (RecyclerView)findViewById(R.id.recycler_view);

        albumList = new ArrayList<>();
        adapter = new AlbumsAdapter(this, albumList);

        RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(this, 2);
        recyclerView.setLayoutManager(mLayoutManager);
        //RecyclerView項目裝飾 - 在網格項目周圍給予相等的邊距
        recyclerView.addItemDecoration(new GridSpacingItemDecoration(2,dpToPx(10),true));
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setAdapter(adapter);

        prepareAlbums();

        try{
            Glide.with(this).load(R.drawable.cover)
                    .into((ImageView)findViewById(R.id.backdrop));
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * Initializing collapsing toolbar
     * Will show and hide the toolbar title on scroll
     */
    private void initCollapsingToolbar() {
        final CollapsingToolbarLayout collapsingToolbar =
                (CollapsingToolbarLayout)findViewById(R.id.collapsing_toolbar);
        collapsingToolbar.setTitle("");
        AppBarLayout appBarLayout = (AppBarLayout)findViewById(R.id.appbar);
        appBarLayout.setExpanded(true);

        //隱藏並顯示工具欄,展開和折疊時的標題
        appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {

            boolean isShow = false;
            int scrollRange = -1;

            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (scrollRange == -1){
                    scrollRange = appBarLayout.getTotalScrollRange();
                }

                if (scrollRange + verticalOffset == 0){
                    collapsingToolbar.setTitle(getString(R.string.app_name));
                    isShow = true;
                } else if(isShow){
                    collapsingToolbar.setTitle("");
                    isShow = false;
                }
            }
        });
    }

    /**
     * Adding few albums for testing
     */
    private void prepareAlbums() {
        int[] covers = new int[]{
                R.drawable.album1,
                R.drawable.album2,
                R.drawable.album3,
                R.drawable.album4,
                R.drawable.album5,
                R.drawable.album6,
                R.drawable.album7,
                R.drawable.album8,
                R.drawable.album9,
                R.drawable.album10,
                R.drawable.album11};

        Album a = new Album("True Romance", 13, covers[0]);
        albumList.add(a);

        a = new Album("Xscpae", 8, covers[1]);
        albumList.add(a);

        a = new Album("Maroon 5", 11, covers[2]);
        albumList.add(a);

        a = new Album("Born to Die", 12, covers[3]);
        albumList.add(a);

        a = new Album("Honeymoon", 14, covers[4]);
        albumList.add(a);

        a = new Album("I Need a Doctor", 1, covers[5]);
        albumList.add(a);

        a = new Album("Loud", 11, covers[6]);
        albumList.add(a);

        a = new Album("Legend", 14, covers[7]);
        albumList.add(a);

        a = new Album("Hello", 11, covers[8]);
        albumList.add(a);

        a = new Album("Greatest Hits", 17, covers[9]);
        albumList.add(a);

        adapter.notifyDataSetChanged();

    }

    /**
     * RecyclerView項目裝飾 - 在網格項目周圍給予相等的邊距
     */
    public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration{

        private int spanCount;
        private int spacing;
        private boolean includeEdge;

        public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
            this.spanCount = spanCount;
            this.spacing = spacing;
            this.includeEdge = includeEdge;
        }

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                                   RecyclerView.State state) {
            int position = parent.getChildAdapterPosition(view); //item position
            int column = position % spanCount; //item column

            if (includeEdge){
                // spacing - column * ((1f / spanCount) * spacing)
                outRect.left = spacing - column * spacing / spanCount;
                // (column + 1) * ((1f / spanCount) * spacing)
                outRect.right = (column + 1) * spacing / spanCount;

                if (position < spanCount){ //top edge 上邊緣
                    outRect.top = spacing;
                }

                outRect.bottom = spacing; //item bottom
            } else {
                outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
                outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
                if (position >= spanCount) {
                    outRect.top = spacing; // item top
                }
            }
        }
    }

    /**
     * Converting dp to pixel 將dp轉換為像素
     */
    private int dpToPx(int dp) {
        Resources r = getResources();
        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()));
    }

}


style.xml
<style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

AndroidManifest.xml
android:theme="@style/AppTheme.NoActionBar"

原文:

Android working with Card View and Recycler View

留言

這個網誌中的熱門文章

SQLite - RecyclerView and SearchView

設計資料庫表格 建立資料庫表格使用SQL的「CREATE TABLE」指令,這個指令需要指定表格的名稱, 還有這個表格用來儲存每一筆資料的欄位(Column)。 這些需要的表格欄位可以對應到主要類別中的欄位變數, 不過SQLite資料庫的資料型態只有下面這幾種,使用它們來決定表格欄位可以儲存的資料型態: INTEGER – 整數,對應Java 的byte、short、int 和long。 REAL – 小數,對應Java 的float 和double。 TEXT – 字串,對應Java 的String。 一個SQLite表格建議一定要包含一個可以自動為資料編號的欄位,欄位名稱固定為「 _id 」,型態為「INTEGER」。 後面加上「 PRIMARY KEY AUTOINCREMENT 」的設定,就可以讓SQLite自動為每一筆資料編號。 建立SQLiteOpenHelper類別 Android 提供許多方便與簡單的資料庫API,可以簡化應用程式處理資料庫的工作。 這些API都在「android.database.sqlite」套件,它們可以用來執行資料庫的管理和查詢的工作。 這個套件中的「 SQLiteOpenHelper 」類別,可以在應用程式中執行 建立資料庫與表格 的工作,應用程式第一次在裝置執行的時候,由它負責建立應用程式需要的資料庫與表格, 後續執行的時候開啟已經建立好的資料庫讓應用程式使用。 還有應用程式在運作一段時間以後,如果增加或修改功能,資料庫的表格也增加或修改了 ,它也可以為應用程式執行資料庫的修改工作,讓新的應用程式可以正常的運作。 Create New Java Class public class MyDBHelper extends SQLiteOpenHelper{ //資料庫名稱 public static final String DATABASE_NAME = "mydata.db"; //資料庫版本,資料結構改變的時後要更改這個數字,通常是加一 public static final int VERSION = 1; //資料庫物件,固定的欄位變數 private static SQLiteDatabase

Android using BottomNavigationView

Creating Navigation Menu menu_navigation.xml <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/action_home" android:icon="@drawable/ic_home" android:title="@string/action_home"/> <item android:id="@+id/action_profile" android:icon="@drawable/ic_person" android:title="@string/action_profile"/> <item android:id="@+id/action_settings" android:icon="@drawable/ic_settings" android:title="@string/action_settings"/> </menu> Creating Layout main_activity.xml <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://