【Android】MaterialDesign使用

北城以北 提交于 2020-02-01 02:13:01

MaterialDesign使用

  • Material DesignGoogle2014年的I/O大会上推出的全新设计语言。
  • Material Design是基于Android 5.0``(API level 21)的,兼容5.0以下的设备时需要使用版本号v21.0.0以上的
    support v7包中的appcpmpat,不过遗憾的是support包只支持Material Design的部分特性。
    使用eclipseAndroid Studio进行开发时,直接在Android SDK Manager中将Extras->Android Support Library
    升级至最新版即可。

下面我就简单讲解一下如何通过support v7包来使用Material Design进行开发。

Material Design Theme

Material主题:

  • @android:style/Theme.Material (dark version) – Theme.AppCompat
  • @android:style/Theme.Material.Light (light version) – Theme.AppCompat.Light
  • @android:style/Theme.Material.Light.DarkActionBar – Theme.AppCompat.Light.DarkActionBar

对应的效果分别如下:

Image

使用ToolBar

  • 禁止Action Bar
    可以通过使用Material theme来让应用使用Material Design。想要使用ToolBar需要先禁用ActionBar
    可以通过自定义theme继承Theme.AppCompat.Light.NoActionBar或者在theme中通过以下配置来进行。

    <item name="windowActionBar">false</item>
    <item name="android:windowNoTitle">true</item>
    

    下面我通过第二种方式来看一下具体的实现:

    style.xml中自定义AppTheme:

    <!-- Base application theme. -->
    <style name="AppTheme" parent="AppTheme.Base"/>
    
    <style name="AppTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
    	<!-- Tell Android System that we will use ToolBar instead of ActionBar -->
    	<item name="windowNoTitle">true</item>
    	<item name="windowActionBar">false</item>
    	<!-- colorPrimary is used for the default action bar background -->
    	<item name="colorPrimary">@color/colorPrimary</item>
    
    	<!-- colorPrimaryDark is used for the status bar -->
    	<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    
    	<!-- colorAccent is used as the default value for colorControlActivated
    		 which is used to tint widgets -->
    	<item name="colorAccent">@color/colorAccent</item>
    </style>
    

    配置的这几种颜色分别如下图所示:
    Image
    里面没有colorAccent的颜色,这个颜色是设置Checkbox等控件选中时的颜色。

    values-v21中的style.xml中同样自定义AppTheme主题:

    <style name="AppTheme" parent="AppTheme.Base">
        <!-- Customize your theme using Material Design here. -->
    	<item name="android:windowContentTransitions" >true</item>
    	<item name="android:windowAllowEnterTransitionOverlap" >true</item>
    	<item name="android:windowAllowReturnTransitionOverlap">true</item>
    	<item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
    	<item name="android:windowSharedElementExitTransition">@android:transition/move</item>
    </style>
    
  • Manifest文件中设置AppTheme主题:

    <application
    	android:allowBackup="true"
    	android:icon="@mipmap/ic_launcher"
    	android:label="@string/app_name"
    	android:theme="@style/AppTheme" >
    	<activity
    		...
    	</activity>
    	<activity android:name="com.charon.materialsample.FriendsActivity"></activity>
    </application>
    

    这里说一下为什么要在values-v21中也自定义个主题,这是为了能让在21以上的版本能更好的使用Material Design
    在21以上的版本中会有更多的动画、特效等。

  • 让Activity继承AppCompatActivity

    public class MainActivity extends AppCompatActivity {
    	...
    }
    
  • 在布局文件中进行声明

    声明toolbar.xml,我们把他单独放到一个文件中,方便多布局使用:

    <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:local="http://schemas.android.com/apk/res-auto"
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        local:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
    

    Activity的布局中使用ToolBar:

    <LinearLayout
    	android:layout_width="match_parent"
    	android:layout_height="match_parent"
    	android:orientation="vertical">
    
    	<include
    		android:id="@+id/toolbar"
    		layout="@layout/toolbar" />
    
    	<com.charon.materialsample.view.PagerSlidingTabStrip
    		android:id="@+id/psts_main"
    		android:layout_width="match_parent"
    		android:layout_height="48dip"
    		android:background="@color/colorPrimary" />
    
    	<android.support.v4.view.ViewPager
    		android:id="@+id/vp_main"
    		android:layout_width="match_parent"
    		android:layout_height="match_parent"></android.support.v4.view.ViewPager>
    
    </LinearLayout>
    
  • 在Activity中设置ToolBar

    public class MainActivity extends AppCompatActivity{
        private Context mContext;
        private Toolbar mToolbar;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mContext = this;
    		mToolbar = (Toolbar) findViewById(R.id.toolbar);
    		mToolbar.setTitle(R.string.app_name);
    		// 将ToolBar设置为ActionBar,这样一设置后他就能像ActionBar一样直接显示menu目录中的菜单资源
    		// 如果不用该方法,那ToolBar就只是一个普通的View,对menu要用inflateMenu去加载布局。
    		setSupportActionBar(mToolbar);
    		getSupportActionBar().setDisplayShowHomeEnabled(true);
        }
    }
    

到这里运行项目就可以了,就可以看到一个简单的ToolBar实现。

接下来我们看一下ToolBar中具体有哪些内容:

Image

我们可以通过对应的方法来修改他们的属性:
Image

对于ToolBar中的Menu部分我们可以通过一下方法来设置:

toolbar.inflateMenu(R.menu.menu_main);
toolbar.setOnMenuItemClickListener();

或者也可以直接在ActivityonCreateOptionsMenuonOptionsItemSelected来处理:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
	// Inflate the menu; this adds items to the action bar if it is present.
	getMenuInflater().inflate(R.menu.menu_main, menu);
	return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
	// Handle action bar item clicks here. The action bar will
	// automatically handle clicks on the Home/Up button, so long
	// as you specify a parent activity in AndroidManifest.xml.
	int id = item.getItemId();

	//noinspection SimplifiableIfStatement
	if (id == R.id.action_settings) {
		return true;
	}
	if (id == R.id.action_search) {
		Toast.makeText(getApplicationContext(), "Search action is selected!", Toast.LENGTH_SHORT).show();
		return true;
	}
	return super.onOptionsItemSelected(item);
}

menu的实现如下:

<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" tools:context=".MainActivity">

        <item
            android:id="@+id/action_search"
            android:title="@string/action_search"
            android:orderInCategory="100"
            android:icon="@drawable/ic_action_search"
            app:showAsAction="ifRoom" />

        <item
            android:id="@+id/action_settings"
            android:title="@string/action_settings"
            android:orderInCategory="100"
            app:showAsAction="never" />

</menu>

如果想要对NavigationIcon添加点击实现:

toolbar.setNavigationOnClickListener(new View.OnClickListener() {
	@Override
	public void onClick(View v) {
		onBackPressed();
	}
});

运行后发现我们强大的Activity切换动画怎么在5.0一下系统上实现呢?support v7包也帮我们考虑到了。使用ActivityOptionsCompat
ActivityCompat.startActivity,但是悲剧了,他对4.0一下基本都无效,而且就算在4.0上很多动画也不行,具体还是用其他
大神在github写的开源项目吧。

  • 动态取色Palette

    Palette这个类中可以提取一下集中颜色:

    • Vibrant (有活力)
    • Vibrant dark(有活力 暗色)
    • Vibrant light(有活力 亮色)
    • Muted (柔和)
    • Muted dark(柔和 暗色)
    • Muted light(柔和 亮色)
    //目标bitmap,代码片段
    Bitmap bm = BitmapFactory.decodeResource(getResources(),
    		R.drawable.kale);
    Palette palette = Palette.generate(bm);
    if (palette.getLightVibrantSwatch() != null) {
    	//得到不同的样本,设置给imageview进行显示
    	iv.setBackgroundColor(palette.getLightVibrantSwatch().getRgb());
    	iv1.setBackgroundColor(palette.getDarkVibrantSwatch().getRgb());
    	iv2.setBackgroundColor(palette.getLightMutedSwatch().getRgb());
    	iv3.setBackgroundColor(palette.getDarkMutedSwatch().getRgb());
    }
    
    

使用DrawerLayout

  • 布局中的使用
<android.support.v4.widget.DrawerLayout 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:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--主页面-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <include
            android:id="@+id/toolbar"
            layout="@layout/toolbar" />

        <com.charon.materialsample.view.PagerSlidingTabStrip
            android:id="@+id/psts_main"
            android:layout_width="match_parent"
            android:layout_height="48dip"
            android:background="@color/colorPrimary" />

        <android.support.v4.view.ViewPager
            android:id="@+id/vp_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent"></android.support.v4.view.ViewPager>

    </LinearLayout>

    <!--侧边栏部分-->
    <fragment
        android:id="@+id/fragment_navigation_drawer"
        android:name="com.charon.materialsample.fragment.FragmentDrawer"
        android:layout_width="@dimen/nav_drawer_width"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:layout="@layout/fragment_navigation_drawer"
        tools:layout="@layout/fragment_navigation_drawer" />

</android.support.v4.widget.DrawerLayout>

使用DrawerLayout后可以实现类似SlidingMenu的效果。但是怎么将DrawerLayout与ToolBar结合起来呢? 还有再结合Navigation Tabs
以及ViewPager。下面我就直接上代码了。

先看布局: activity_main.xml

<android.support.v4.widget.DrawerLayout 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:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--主页面-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <include
            android:id="@+id/toolbar"
            layout="@layout/toolbar" />

        <com.charon.materialsample.view.PagerSlidingTabStrip
            android:id="@+id/psts_main"
            android:layout_width="match_parent"
            android:layout_height="48dip"
            android:background="@color/colorPrimary" />

        <android.support.v4.view.ViewPager
            android:id="@+id/vp_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </LinearLayout>

    <!--侧边栏部分-->
    <fragment
        android:id="@+id/fragment_navigation_drawer"
        android:name="com.charon.materialsample.fragment.DrawerFragment"
        android:layout_width="wrap_content"
        android:layout_marginRight="56dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:layout="@layout/fragment_navigation_drawer"
        tools:layout="@layout/fragment_navigation_drawer" />

</android.support.v4.widget.DrawerLayout>

MainActivity的代码:

public class MainActivity extends AppCompatActivity {

    private Context mContext;

    private Toolbar mToolbar;
    private PagerSlidingTabStrip mScrollingTabs;
    private ViewPager mViewPager;
    private MainPagerAdapter mPagerAdapter;
    private ActionBarDrawerToggle mDrawerToggle;
    private DrawerLayout mDrawerLayout;

    private List<String> mTitles;
    private List<Fragment> mFragments;

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

        findView();
        setToolBar();
        initView();
        initDrawerFragment();
    }

    private void findView() {
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        mScrollingTabs = (PagerSlidingTabStrip) findViewById(R.id.psts_main);
        mViewPager = (ViewPager) findViewById(R.id.vp_main);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    }


    private void setToolBar() {
        mToolbar.setTitle(R.string.app_name);
        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
    }

    private void initView() {
        mFragments = new ArrayList<>();
        for (int xxx = 0; xxx < 5; xxx++) {
            mFragments.add(new FriendsFragment());
        }

        mTitles = new ArrayList<>();
        for (int xxx = 0; xxx < 5; xxx++) {
            mTitles.add("Tab : " + xxx);
        }

        mPagerAdapter = new MainPagerAdapter(getSupportFragmentManager(), mFragments, mTitles);
        mViewPager.setAdapter(mPagerAdapter);
        mScrollingTabs.setDividerColor(Color.TRANSPARENT);
        mScrollingTabs.setIndicatorHeight(10);
        mScrollingTabs.setUnderlineHeight(0);
        mScrollingTabs.setTextSize(50);
        mScrollingTabs.setTextColor(Color.BLACK);
        mScrollingTabs.setSelectedTextColor(Color.WHITE);
        mScrollingTabs.setViewPager(mViewPager);

    }

    private void initDrawerFragment() {
        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.drawer_open, R.string.drawer_close) {
            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                MainActivity.this.invalidateOptionsMenu();
            }

            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                MainActivity.this.invalidateOptionsMenu();
            }

            @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {
                super.onDrawerSlide(drawerView, slideOffset);
                mToolbar.setAlpha(1 - slideOffset / 2);
            }
        };

        mDrawerLayout.setDrawerListener(mDrawerToggle);
        mDrawerToggle.syncState();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }
        if (id == R.id.action_search) {
            Toast.makeText(getApplicationContext(), "Search action is selected!", Toast.LENGTH_SHORT).show();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

}

最后再看一下DrawerFragment的代码:

public class DrawerFragment extends Fragment {
    private Context mContext;
    private RecyclerView mRecyclerView;
    private NavigationDrawerAdapter mAdapter;
    private static String[] titles = null;

    public DrawerFragment() {

    }

    public static List<NavDrawerItem> getData() {
        List<NavDrawerItem> data = new ArrayList<>();

        // preparing navigation drawer items
        for (int i = 0; i < titles.length; i++) {
            NavDrawerItem navItem = new NavDrawerItem();
            navItem.setTitle(titles[i]);
            data.add(navItem);
        }
        return data;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = getActivity();
        // drawer labels
        titles = getActivity().getResources().getStringArray(R.array.nav_drawer_labels);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflating view layout
        View layout = inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
        mRecyclerView = (RecyclerView) layout.findViewById(R.id.drawerList);
        mRecyclerView.setHasFixedSize(true);
        mAdapter = new NavigationDrawerAdapter(getActivity(), getData());
        mRecyclerView.setAdapter(mAdapter);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        mAdapter.setOnRecyclerViewListener(new NavigationDrawerAdapter.OnRecyclerViewListener() {
            @Override
            public void onItemClick(int position) {
                Toast.makeText(mContext, getData().get(position).getTitle(), Toast.LENGTH_SHORT).show();
                startActivity(new Intent(getActivity(), FriendsActivity.class));
            }

            @Override
            public boolean onItemLongClick(int position) {
                return false;
            }
        });
        return layout;
    }

}

上面的PagerSlidingTabStrip是开源项目,我改了下,添加了一个选中时的文字颜色改变。

Demo地址

Ripple效果

个人非常喜欢的效果。相当于给点击事件加上了动态的赶脚。。。

假设现在有一个Buttonselector,我们想给这个Button加上Ripple效果,肿么办?
新建一个xml文件,用ripple包裹selector,然后在Buttonbackgroud直接引用这个xml就好了。

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/whatever">
<selector xmlns:android="http://schemas.android.com/apk/res/android"
<item android:state_pressed="false" android:state_focused="true"
android:drawable="@drawable/some_focused_blah"/>
<item android:state_pressed="true" android:drawable="@drawable/some_pressed_blah"/>
<item android:drawable="@android:color/whatever"/>
</selector>
</ripple>


但是很遗憾,ripple是5.0才有的,而且support包中没有实现该功能的扩展。
5.0的这些效果还是无法在低版本上实现,包括一些TextView等样式,现在可以用大神的开源项目
MaterialDesignLibrary

RecyclerView

ListView的升级版,还有什么理由不去用呢? 同样他也在support v7包中。

compile 'com.android.support:recyclerview-v7:21.+'  

通过mRecyclerView.setLayoutManager(new LinearLayoutManager(this));设置为LinearLayoutManager来实现水平或者竖直
方向的ListView

阴影

通过对View设置backgroud后再添加android:elevation="2dp"来实现背景大小。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!