Android Material Design 詳解(使用support v7兼容5.0以下系統)

ybw8 9年前發布 | 69K 次閱讀 Android開發 移動開發 Material Design

Material Design是Google在2014年的I/O大會上推出的全新設計語言。Material Design是基于Android 5.0(API level 21)的,兼容5.0以下的設備時需要使用版本號v21.0.0以上的support v7包中的appcpmpat,不過遺憾的是support包只支持Material Design的部分特性。使用eclipse或Android Studio進行開發時,直接在Android SDK Manager中將Extras->Android Support Library升級至最新版即可。目前最新版本為:

    com.android.support:appcompat-v7:21.0.3  

本文中示例程序使用minSdkVersion=14,即屬于使用support包實現Material Design風格。

使用Material Design的步驟:

一、使用Material主題

1.創建一個Android應用,應用主題Theme.AppCompat(或其子主題,如Theme.AppCompat.Light.DarkActionBar)

2.自定義程序所使用的主題的某些屬性,示例:

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">  
            <!--ActionBar的顏色-->  
            <item name="colorPrimary">@color/primary</item>  
            <!-- 隨主題而改變的顏色(如CheckBox的顏色)-->  
            <item name="colorAccent">@color/accent</item>  
            <!--狀態欄的顏色 (使用support包時似乎無效。)-->  
            <item name="colorPrimaryDark">@color/primary_dark</item>  

            <!--ActionBar的樣式-->  
            <item name="actionBarStyle">@style/AppTheme.ActionBarStyle</item>  
        </style>  

        <style name="AppTheme.ActionBarStyle" parent="Widget.AppCompat.ActionBar.Solid">  
            <item name="android:titleTextStyle">@style/AppTheme.ActionBar.TitleTextStyle</item>  
        </style>  

        <style name="AppTheme.ActionBar.TitleTextStyle" parent="@style/TextAppearance.AppCompat.Widget.ActionBar.Title">  
            <!--ActionBar標題文字顏色-->  
            <item name="android:textColor">@android:color/white</item>  
        </style>  

3.所有需要使用ActionBar的Activity必須繼承自ActionBarActivity,因為即使使用了類似Theme.AppCompat.Light.DarkActionBar這樣的主題,系統也不會自動添加ActionBar.
效果圖:生氣

  

相對于普通的ActionBar的變化:

(1)右側三個小點的樣式變了。(這個無所謂。。。)

(2)點擊右側三個小點(更多)時,下拉菜單不是從ActionBar的下面開始展開,而是直接從ActionBar之上開始!也許的確有辦法把它改成舊的樣式,不過查閱官方文檔之后發現,Google對此的解釋是:菜單是一個臨時展現給用戶的組件,因此應該懸浮在上面。也就是說,新的設計規則推薦的就是這種默認的樣式。

二、使用RecyclerView

RecyclerView是Google在support v7包中提供的一個全新的組件。該組件是一個增強版的ListView,新特性:

1.提高了性能;

2.adapter中自動進行item復用,也就是說,以前的這種繁瑣的寫法不需要了:

    if (convertView == null) {  
                convertView = LayoutInflater.from(context).inflate(R.layout.friends_item, parent, false);  
                holder = new ViewHolder();  

                holder.nameTV = (TextView) convertView.findViewById(R.id.friends_item_name);  
                holder.phoneTV = (TextView) convertView.findViewById(R.id.friends_item_phone);  
                convertView.setTag(holder);  
            } else {  
                holder = (ViewHolder) convertView.getTag();  
            }  

3.預置了item的添加,刪除,移動,修改時的動畫,當且改動畫也可以自定義。

效果圖:

    

示例代碼:

(1)主頁面,獲取到RecyclerView,設置adapter即可。

    RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);  
     // use this setting to improve performance if you know that changes  
     // in content do not change the layout size of the RecyclerView  
      mRecyclerView.setHasFixedSize(true);  

     // use a linear layout manager  
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));  
    //data  
     List<CityInfoBean> myDataset = new ArrayList<CityInfoBean>();  
            for (int i = 0; i < 50; i++) {  
                CityInfoBean city = new CityInfoBean();  
                city.setCityName("Tianjin-" + i);  
                city.setCityPhone("022-" + i);  
                city.setLocation("Asia_" + i);  

                myDataset.add(city);  
            }  

            RecyclerViewAdapter mAdapter = new RecyclerViewAdapter(this, myDataset);  
            mRecyclerView.setAdapter(mAdapter);  

    //RecyclerView doesn't has a 'OnItemClickListener' or 'OnItemLongClickListener' like ListView,  
     // so you should add the callback in adapter   

(2)adapter,RecyclerViewAdapter.java:
    public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {  
        private Context context;  
        private List<CityInfoBean> mDataset;  

        public RecyclerViewAdapter(Context context, List<CityInfoBean> myDataset) {  
            this.context = context;  
            mDataset = myDataset;  
        }  

        // Create new views (invoked by the layout manager)  
        @Override  
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list_item, parent, false);  
            // set the view's size, margins, paddings and layout parameters  

            final ViewHolder vh = new ViewHolder(v);  
            v.setOnClickListener(new View.OnClickListener() {  
                @Override  
                public void onClick(View v) {  
                    int position = vh.getPosition();  
                    Toast.makeText(v.getContext(), "Item click. Position:" +  
                            position, Toast.LENGTH_SHORT).show();  
                }  
            });  

            v.setOnLongClickListener(new View.OnLongClickListener() {  
                @Override  
                public boolean onLongClick(View v) {  
                    int position = vh.getPosition();  
    //                Toast.makeText(v.getContext(), "Item long click. Position:" +  
    //                        position, Toast.LENGTH_SHORT).show();  

                    showDialog(position);  

                    return true;  
                }  
            });  

            return vh;  
        }  

        // Replace the contents of a view (invoked by the layout manager)  
        @Override  
        public void onBindViewHolder(ViewHolder holder, int position) {  
            holder.cityNameTV.setText(mDataset.get(position).getCityName());  
            holder.phoneTV.setText(mDataset.get(position).getCityPhone());  
            holder.addrTV.setText(mDataset.get(position).getLocation());  
        }  

        @Override  
        public int getItemCount() {  
            return mDataset.size();  
        }  

        private void showDialog(final int position) {  
            AlertDialog.Builder builder = new AlertDialog.Builder(context);  
            builder.setTitle("Choose operation");  

            String[] dialogItems = new String[]{  
                    context.getString(R.string.delete_one_item),  
                    context.getString(R.string.add_one_item),  
                    context.getString(R.string.move_one_item),  
                    context.getString(R.string.change_one_item),  
                    context.getString(R.string.add_many_items),  
            };  
            builder.setItems(dialogItems, new DialogInterface.OnClickListener() {  
                @Override  
                public void onClick(DialogInterface dialog, int which) {  
                    switch (which) {  
                        case 0:  
                            //delete this item  
                            mDataset.remove(position);  
                            notifyItemRemoved(position);  
                            break;  
                        case 1:  
                            //add one item  
                            mDataset.add(position, new CityInfoBean("New City", "010", "Asia"));  
                            notifyItemInserted(position);  
                            break;  
                        case 2:  
                            //TODO remember to change the data set...  
                            //move one item to another position  
                            notifyItemMoved(position, position + 2);  
                            //May cause IndexOutOfBoundsException. This is just a demo!  
                            break;  
                        case 3:  
                            //change one item  
                            mDataset.get(position).setCityName("City name changed");  
                            notifyItemChanged(position);  
                            break;  
                        case 4:  
                            //add many items  
                            List<CityInfoBean> insertList = new ArrayList<CityInfoBean>();  
                            insertList.add(new CityInfoBean("New City 01", "010", "Asia"));  
                            insertList.add(new CityInfoBean("New City 02", "020", "America"));  

                            mDataset.addAll(position, insertList);  
                            notifyItemRangeInserted(position, insertList.size());  
                            break;  
                        default:  
                            break;  
                    }  
                }  
            });  

            builder.create().show();  
        }  

        public static class ViewHolder extends RecyclerView.ViewHolder {  
            public TextView cityNameTV, phoneTV, addrTV;  

            public ViewHolder(View v) {  
                super(v);  

                cityNameTV = (TextView) v.findViewById(R.id.city_name);  
                phoneTV = (TextView) v.findViewById(R.id.city_phone);  
                addrTV = (TextView) v.findViewById(R.id.city_addr);  
            }  
        }  
    }  

(3)主頁面布局文件:

recycler_layout.xml:

    <?xml version="1.0" encoding="utf-8"?>  
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        android:orientation="vertical"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent">  

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

    </LinearLayout>  

二、使用CardView

CardView是Google在support v7包中提供了另一個全新組件,可以很方便的實現“卡片式布局”(具有投影/圓角 的立體效果)。CardView繼承自FrameLayout,因此如果內部需要互不重疊的放置多個組件時,可能需要再嵌套一個LinearLayout 或RelativeLayout等。

效果圖:

布局文件:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        xmlns:card_view="http://schemas.android.com/apk/res-auto">  

        <android.support.v7.widget.CardView  
            android:id="@+id/card_view"  
            android:layout_gravity="center"  
            android:layout_width="match_parent"  
            android:layout_height="200dp"  
            android:layout_margin="6dp"  
            card_view:cardCornerRadius="4dp"  
            card_view:cardBackgroundColor="@color/card_bg"  
            card_view:cardElevation="4dp">  

            <LinearLayout  
                android:layout_width="match_parent"  
                android:layout_height="match_parent"  
                android:layout_margin="6dp"  
                android:orientation="vertical">  

                <ImageView  
                    android:layout_width="wrap_content"  
                    android:layout_height="wrap_content"  
                    android:contentDescription="@null"  
                    android:src="@drawable/ic_launcher" />  

                <TextView  
                    android:id="@+id/info_text"  
                    android:layout_width="match_parent"  
                    android:layout_height="match_parent"  
                    android:textSize="18sp"  
                    android:text="@string/example_text" />  

            </LinearLayout>  

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

    </LinearLayout>  

屬性解釋:

cardCornerRadius:圓角大小;

cardElevation:投影的深度;

cardBackgroundColor:卡片的背景色。

 本文由用戶 ybw8 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!