zoukankan      html  css  js  c++  java
  • Android Material Design NavigationView 及 Palette 颜色提取器

    DrawerLayout + NavigationView

    DrawerLayout布局,通常在里面添加两个子控件,程序主界面添加到NavitagionView前面。

    <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"
        android:fitsSystemWindows="true"
        tools:openDrawer="start">
        <include
            layout="@layout/app_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header_main" app:menu="@menu/activity_main_drawer" /> </android.support.v4.widget.DrawerLayout>

    这里有两个重要的属性headerLayout和menu,分别表示header部分布局和menu菜单资源。

    程序主界面布局app_main,包含AppBarLayout和content_main,以及一个FloatingActionButton。

    <android.support.design.widget.CoordinatorLayout 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:fitsSystemWindows="true">
    <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay">
    <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout>
    <include layout="@layout/content_main" />
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_margin="@dimen/fab_margin"
            android:src="@android:drawable/ic_dialog_email" />
    </android.support.design.widget.CoordinatorLayout>

    上面的主界面布局也以随意切换成其它布局。

    注意事项:

    1.DrawerLayout指定openDrawer为start,NavigationView指定layout_gravity为start。

    2.指定NavigationView的headerLayout属性和menu属性,分别为layout布局文件和menu文件。

    headerLayout

    <?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="@dimen/nav_header_height"
        android:background="@drawable/side_nav_bar"
        android:gravity="bottom"
        android:orientation="vertical"
        android:theme="@style/ThemeOverlay.AppCompat.Dark">
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingTop="@dimen/nav_header_vertical_spacing"
            android:src="@android:drawable/sym_def_app_icon" />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingTop="@dimen/nav_header_vertical_spacing"
            android:text="Android Studio"
            android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="android.studio@android.com" />
    </LinearLayout>

    menu菜单资源

    调用 setNavigationItemSelectedListener() 后,在菜单项被选中的时候,你会通过OnNavigationItemSelectedListener 得到回调。在处理回调时,你会知道是哪个菜单项被点击,此时你可以处理选择事件,修改选中状态,加载新的内容,以及通过代码来关闭 drawer,或者其他任何你想执行的操作。

    <menu xmlns:android="http://schemas.android.com/apk/res/android"><group android:checkableBehavior="single">
            <item
                android:id="@+id/nav_camera"
                android:icon="@drawable/ic_menu_camera"
                android:title="Import" />
            <item
                android:id="@+id/nav_gallery"
                android:icon="@drawable/ic_menu_gallery"
                android:title="Gallery" />
            <item
                android:id="@+id/nav_slideshow"
                android:icon="@drawable/ic_menu_slideshow"
                android:title="Slideshow" />
            <item
                android:id="@+id/nav_manage"
                android:icon="@drawable/ic_menu_manage"
                android:title="Tools" />
        </group>
        <item android:title="Communicate">
            <menu>
                <item
                    android:id="@+id/nav_share"
                    android:icon="@drawable/ic_menu_share"
                    android:title="Share" />
                <item
                    android:id="@+id/nav_send"
                    android:icon="@drawable/ic_menu_send"
                    android:title="Send" />
            </menu>
        </item>
    </menu>

    下面是涉及到的styles文件

    <resources>
        <!-- Base application theme. -->
        <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
        </style>
        <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" />
    </resources>

    Activity

    public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
            FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                            .setAction("Action", null).show();
                }
            });
            DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
            ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                    this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
            drawer.setDrawerListener(toggle);
            toggle.syncState();
            NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
            navigationView.setNavigationItemSelectedListener(this);
        }
        @Override
        public void onBackPressed() {
            DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
            if (drawer.isDrawerOpen(GravityCompat.START)) {
                drawer.closeDrawer(GravityCompat.START);
            } else {
                super.onBackPressed();
            }
        }
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
            if (id == R.id.action_settings) {
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
        @SuppressWarnings("StatementWithEmptyBody")
        @Override
        public boolean onNavigationItemSelected(MenuItem item) {
            int id = item.getItemId();
            DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
            drawer.closeDrawer(GravityCompat.START);
            return true;
        }
    }

    Toolbar设置

            mToolbar = (Toolbar) findViewById(R.id.toolbar);
            mToolbar.setTitle("Rocko");
            // 标题的文字需在setSupportActionBar之前,不然会无效
            // toolbar.setSubtitle("副标题");
            setSupportActionBar(mToolbar);
            /* 这些通过ActionBar来设置也是一样的,注意要在setSupportActionBar(toolbar);之后,不然就报错了 */
            // getSupportActionBar().setTitle("标题");
            // getSupportActionBar().setSubtitle("副标题");
            // getSupportActionBar().setLogo(R.drawable.ic_launcher);
            /* 菜单的监听可以在toolbar里设置,也可以像ActionBar那样,通过下面的两个回调方法来处理 */
            mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {
                    switch (item.getItemId()) {
                        case R.id.action_settings:
                            Toast.makeText(MainActivity.this, "action_settings", Toast.LENGTH_SHORT).show();
                            break;
                        case R.id.action_share:
                            Toast.makeText(MainActivity.this, "action_share", Toast.LENGTH_SHORT).show();
                            break;
                        default:
                            Log.e("tag", item.toString());
                            break;
                    }
                    return true;
                }
            });

    设置ActionBar及StatusBar背景颜色,在Api21及以上才有。

            if (null != vibrant) {
                    /* 界面颜色UI统一性处理,看起来更Material一些 */
                mPagerSlidingTabStrip.setBackgroundColor(vibrant.getRgb());
                mPagerSlidingTabStrip.setTextColor(vibrant.getTitleTextColor());
                // 其中状态栏、游标、底部导航栏的颜色需要加深一下,也可以不加,具体情况在代码之后说明
                mPagerSlidingTabStrip.setIndicatorColor(colorBurn(vibrant.getRgb()));
                mToolbar.setBackgroundColor(vibrant.getRgb());
                if (android.os.Build.VERSION.SDK_INT >= 21) {
                    Window window = getWindow();
                    // 很明显,这两货是新API才有的。
                    window.setStatusBarColor(colorBurn(vibrant.getRgb()));
                    window.setNavigationBarColor(colorBurn(vibrant.getRgb()));
                }
            }

    colorBurn

        private int colorBurn(int RGBValues) {
            int alpha = RGBValues >> 24;
            int red = RGBValues >> 16 & 0xFF;
            int green = RGBValues >> 8 & 0xFF;
            int blue = RGBValues & 0xFF;
            red = (int) Math.floor(red * (1 - 0.1));
            green = (int) Math.floor(green * (1 - 0.1));
            blue = (int) Math.floor(blue * (1 - 0.1));
            return Color.rgb(red, green, blue);
        }

    Palette

    根据图片来决定标题的颜色和标题栏的背景色,这样视觉上更具有冲击力和新鲜感,而不像统一色调那样呆板。 

    Palette是什么?它能让你从图像中提取突出的颜色。这个类能提取以下突出的颜色:

    1. Vibrant(充满活力的)

    2. Vibrant dark(充满活力的黑)

    3. Vibrant light(充满活力的亮)

    4. Muted(柔和的)

    5. Muted dark(柔和的黑)

    6. Muted lighr(柔和的亮)

    如何使用?

    要提取这些颜色,在你加载图片的后台线程中传递一个位图对象给Palette.generate()静态方法。如果不使用线程,则调用Palette.generateAsync()方法并且提供一个监听器去替代。

    你可以在Palette类中使用getter方法来从检索突出的颜色,比如Palette.getVibrantColor。

    Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
    @Override
    public void onGenerated(Palette palette) {
          xx.setBackgroundColor(palette.getVibrantColor(mContext
                 .getResources().getColor(R.color.black_translucent_60)));
      }
    });

    2.

    Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
    @Override
    public void onGenerated(Palette palette) {
          xx.setBackgroundColor(palette.getVibrantColor(mContext
                 .getResources().getColor(R.color.black_translucent_60)));
      }
    });
    Palette.generateAsync(bitmap,new Palette.PaletteAsyncListener() {  
       @Override  
       public void onGenerated(Palette palette) {  
            Palette.Swatch vibrant =palette.getVibrantSwatch();  
             if (swatch != null) {  
                 // If we have a vibrant color  
                 // update the title TextView  
                 titleView.setBackgroundColor(vibrant.getRgb());  
                 titleView.setTextColor(vibrant.getTitleTextColor());  
             }  
       }  
    });

    上面的代码展示了如何从一张图片中提取颜色将textView的背景色设置成图片的主色调,然后再使用getTitleTextColor()来设置一个匹配的文字颜色。

    比如如果你的TextView 有个背景图片,要想让字体颜色能够和背景图片匹配,则使用getBodyTextColor()比较合适,getTitleTextColor()其实应该和getBodyTextColor()差不多。

    size的问题

    你还可以使用如下方法一次性获得所有的swatch:

    List<Palette.Swatch> swatches = palette.getSwatches();

    在上面的代码中,你可能注意到了可以设置palette的size。size越大,花费的时间越长,而越小,可以选择的色彩也越小。最佳的选择是根据image的用途:

    • 头像之类的,size最好在24-32之间;
    • 风景大图之类的 size差不多在8-16;
    • 默认是16. 

    有四种创建Palette实例的方法:

    // Synchronous methods.
    // --------------------------------
    // These should be used when you have access to the underlying image loading thread.
    // Picasso allows this through a Transformation. For other libraries, YMMV.
    // Uses the default palette size (16).
    Palette p = Palette.generate(bitmap);
    // Allows you to specify the maximum palette size, in this case 24.
    Palette p = Palette.generate(bitmap, 24);
    // Asynchronous methods
    // --------------------------------
    // This is the quick and easy integration path. Internally uses an AsyncTask so
    // this may not be optimal (since you're dipping in and out of threads)
    // Uses the default palette size (16).
    Palette.generateAsync(bitmap, new Palette.PaletteAsyncListener() {
        @Override
        public void onGenerated(Palette palette) {
           // Here's your generated palette
        }
    });
    // Allows you to specify the maximum palette size, in this case 24.
    Palette.generateAsync(bitmap, 24, new Palette.PaletteAsyncListener() {
        @Override
        public void onGenerated(Palette palette) {
           // Here's your generated palette
        }
    });
     

    创建完一个实例之后,我们还需要得到一种采集的样本(swatch),有6中样本(swatch):

    Vibrant. Palette.getVibrantSwatch()
    Vibrant dark. Palette.getDarkVibrantSwatch()
    Vibrant light. Palette.getLightVibrantSwatch()
    Muted. Palette.getMutedSwatch()
    Muted dark. Palette.getDarkMutedSwatch()
    Muted light. Palette.getLightMutedSwatch()

    具体选择哪一种取决于你自己,大多数情况下我们都使用Vibrant and Dark Vibrant。

    使用样本(swatch)

    swatch有以下方法:

    getPopulation(): the amount of pixels which this swatch represents.
    getRgb(): the RGB value of this color.
    getHsl(): the HSL value of this color.
    getBodyTextColor(): the RGB value of a text color which can be displayed on top of this color.
    getTitleTextColor(): the RGB value of a text color which can be displayed on top of this color.
  • 相关阅读:
    Java实现代理服务器
    UML快速理解
    Linux常用命令
    线程数设置和CPU数的关系
    面试官:你在平时的工作中遇到过哪些问题让你印象深刻?
    常见的思考问题方法、处理问题工具
    分布式锁的几种使用方式(redis、zookeeper、数据库)
    MySQL数据库连不上?
    Oracle备份的几种方式
    ORACLE物理standby与逻辑standby简述
  • 原文地址:https://www.cnblogs.com/284628487a/p/5275471.html
Copyright © 2011-2022 走看看