zoukankan      html  css  js  c++  java
  • 【Android

      首先来介绍一下这个自定义View:

    • (1)这个自定义View的名称叫做 GradientTab ,继承自View类;
    • (2)这个自定义View实现了颜色渐变的Tab导航栏(仿微信主菜单),用户在左右滑动的时候,当前页对应的Tab逐渐变淡,目标页的Tab逐渐变深;
    • (3)用户可以在XML布局中自定义变色的颜色、图标、文本、文本大小、文本颜色、图文间隔等属性。

      接下来简单介绍一下在这个自定义View中用到的技术点:

    • (1)自定义属性;
    • (2)在 onMeasure() 方法中对View进行测量;
    • (3)在 onLayout() 方法中进行一些在获取到测量值之后才能进行的操作,避免代码多次调用影响性能;
    • (4)使用 Canvas 、 Paint 、 Bitmap 类对自定义View进行绘制;
    • (5)通过 onSaveInstanceState() 和 onRestoreInstanceState() 方法保存和重置View状态(透明度)。

      下面是这个自定义View—— GradientTab 的实现代码:

      自定义View类 GradientTab.java 中的代码:

    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Matrix;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.os.Bundle;
    import android.os.Parcelable;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.util.TypedValue;
    import android.view.View;
    
    /**
     * 与ViewPager连用的拖动可渐变色的Tab按钮
     */
    public class GradientTab extends View {
        private int width, height; // View最终显示的宽高
    
        private int backColor = Color.GREEN; // 自定义属性:Tab按钮的背景颜色
        private int spacing = -1; // 自定义属性:Tab按钮中图标和文本的间隔
        private StringBuffer text = new StringBuffer(); // 自定义属性:Tab按钮中显示的文本
        private int textColor = Color.BLACK; // 自定义属性:Tab按钮中文本的颜色
        private int textSize = -1; // 自定义属性:Tab按钮的文本大小
    
        private Bitmap tabBitmap; // 绘制元素的Bitmap
        private Bitmap tmpBm; // 临时Bitmap
        private Paint tabPaint; // 绘制元素的画笔
        private Paint iconPaint; // 绘制图标的画笔
        private Paint textPaint; // 绘制文本的画笔
        private Bitmap iconBm; // 图标图片对应的Bitmap
    
        private float iconWidth; // 图标图片的宽度
        private float iconHeight; // 图标图片的高度
    
        private int alpha = 0; // 透明度
    
        public GradientTab(Context context) {
            this(context, null);
        }
    
        public GradientTab(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public GradientTab(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            // 加载自定义属性
            TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.GradientTab, defStyleAttr, 0);
            int count = array.getIndexCount();
            for (int i = 0; i < count; i++) {
                int attr = array.getIndex(i);
                switch (attr) {
                    case R.styleable.GradientTab_backColor:
                        backColor = array.getColor(attr, Color.GREEN);
                        break;
                    case R.styleable.GradientTab_iconImg:
                        int iconRes = array.getResourceId(attr, -1); // 自定义属性:Tab按钮中显示的图标的资源ID
                        if (iconRes != -1) {
                            iconBm = BitmapFactory.decodeResource(getResources(), iconRes);
                            iconWidth = iconBm.getWidth();
                            iconHeight = iconBm.getHeight();
                        }
                        break;
                    case R.styleable.GradientTab_spacing:
                        textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                                array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, context.getResources().getDisplayMetrics())),
                                context.getResources().getDisplayMetrics());
                        break;
                    case R.styleable.GradientTab_text:
                        text.delete(0, text.length());
                        text.append(array.getString(attr));
                        break;
                    case R.styleable.GradientTab_textColor:
                        textColor = array.getColor(attr, Color.BLACK);
                        break;
                    case R.styleable.GradientTab_textSize:
                        textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                                array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, context.getResources().getDisplayMetrics())),
                                context.getResources().getDisplayMetrics());
                        break;
                }
            }
            array.recycle();
            // 为一些自定义属性设置默认值
            if (textSize == -1) {
                textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, context.getResources().getDisplayMetrics());
            }
            if (spacing == -1) {
                spacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, context.getResources().getDisplayMetrics());
            }
            // 进行一些对象的初始化操作
            init();
        }
    
        /**
         * 进行一些对象的初始化操作
         */
        private void init() {
            // 初始化绘制图标的画笔
            iconPaint = new Paint();
            iconPaint.setAntiAlias(true);
            iconPaint.setDither(true);
            // 初始化绘制文本的画笔
            textPaint = new Paint();
            textPaint.setAntiAlias(true);
            textPaint.setDither(true);
            textPaint.setColor(textColor);
            textPaint.setTextSize(textSize);
            // 初始化绘制元素的画笔
            tabPaint = new Paint();
            tabPaint.setAntiAlias(true);
            tabPaint.setDither(true);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            width = getMeasuredWidth();
            height = getMeasuredHeight();
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            // 初始化绘制元素的画布
            tabBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            Canvas tabCanvas = new Canvas(tabBitmap);
            // 对图标进行缩放
            int widthLeft = width - getPaddingLeft() - getPaddingRight();
            int heightLeft = height - getPaddingTop() - getPaddingBottom() - textSize - spacing;
            float scale = (float) Math.min(widthLeft * 1.0 / iconWidth, heightLeft * 1.0 / iconHeight);
            Matrix matrix = new Matrix();
            matrix.postScale(scale, scale);
            iconBm = Bitmap.createBitmap(iconBm, 0, 0, (int) iconWidth, (int) iconHeight, matrix, true);
            iconWidth *= scale;
            iconHeight *= scale;
            // 将图标和文本绘制到绘制元素的画布上
            tabCanvas.drawBitmap(iconBm, (widthLeft - iconWidth) / 2, getPaddingTop(), iconPaint);
            int textWidth = (int) textPaint.measureText(text.toString());
            tabCanvas.drawText(text.toString(), (widthLeft - textWidth) / 2, height - getPaddingBottom(), textPaint);
            tmpBm = tabBitmap.copy(Bitmap.Config.ARGB_8888, false);
            tabPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            tabPaint.setColor(backColor);
            tabCanvas.drawRect(0, 0, width, height, tabPaint);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawBitmap(tmpBm, 0, 0, null);
            // 绘制图标和文本
            Paint paint = new Paint();
            paint.setAlpha(alpha);
            canvas.drawBitmap(tabBitmap, 0, 0, paint);
        }
    
        public void setAlpha(float alpha) {
            this.alpha = (int) Math.ceil(255 * alpha);
            invalidate();
        }
    
        /**
         * 当这个View所在的Activity临时结束时,保存当前状态(透明度)
         */
        @Override
        protected Parcelable onSaveInstanceState() {
            Bundle bundle = new Bundle();
            bundle.putParcelable("default", super.onSaveInstanceState());
            bundle.putInt("alpha", alpha);
            return bundle;
        }
    
        /**
         * 当这个View所在的Activity重新打开时,重置当前状态(透明度)
         */
        @Override
        protected void onRestoreInstanceState(Parcelable state) {
            if (state instanceof Bundle) {
                Bundle bundle = (Bundle) state;
                alpha = bundle.getInt("alpha");
                super.onRestoreInstanceState(bundle.getParcelable("default"));
            }
            super.onRestoreInstanceState(state);
        }
    }

      自定义属性文件 attr.xml 中的代码:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <attr name="backColor" format="color" />
        <attr name="iconImg" format="reference" />
        <attr name="spacing" format="dimension" />
        <attr name="text" format="string" />
        <attr name="textColor" format="color" />
        <attr name="textSize" format="dimension" />
    
        <declare-styleable name="GradientTab">
            <attr name="backColor" />
            <attr name="iconImg" />
            <attr name="spacing" />
            <attr name="text" />
            <attr name="textColor" />
            <attr name="textSize" />
        </declare-styleable>
    </resources>

      主界面布局 activity_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"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <LinearLayout
            android:id="@+id/gradienttab_main_ly_tabs"
            android:layout_width="match_parent"
            android:layout_height="60.0dip"
            android:layout_alignParentBottom="true"
            android:background="#EEEEEE"
            android:orientation="horizontal">
    
            <my.itgungnir.custom_gradientmenu.GradientTab
                android:id="@+id/gradienttab_main_tab_tab1"
                android:layout_width="0.0dip"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:padding="3.0dip"
                app:backColor="#008800"
                app:iconImg="@mipmap/menu_tab1"
                app:spacing="2.0dip"
                app:text="Tab1"
                app:textColor="#888888"
                app:textSize="8.0sp" />
    
            <my.itgungnir.custom_gradientmenu.GradientTab
                android:id="@+id/gradienttab_main_tab_tab2"
                android:layout_width="0.0dip"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:padding="3.0dip"
                app:backColor="#880000"
                app:iconImg="@mipmap/menu_tab2"
                app:spacing="2.0dip"
                app:text="Tab2"
                app:textColor="#888888"
                app:textSize="8.0sp" />
    
            <my.itgungnir.custom_gradientmenu.GradientTab
                android:id="@+id/gradienttab_main_tab_tab3"
                android:layout_width="0.0dip"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:padding="3.0dip"
                app:backColor="#000088"
                app:iconImg="@mipmap/menu_tab3"
                app:spacing="2.0dip"
                app:text="Tab3"
                app:textColor="#888888"
                app:textSize="8.0sp" />
    
            <my.itgungnir.custom_gradientmenu.GradientTab
                android:id="@+id/gradienttab_main_tab_tab4"
                android:layout_width="0.0dip"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:padding="3.0dip"
                app:backColor="#888888"
                app:iconImg="@mipmap/menu_tab4"
                app:spacing="2.0dip"
                app:text="Tab4"
                app:textColor="#888888"
                app:textSize="8.0sp" />
        </LinearLayout>
    
        <android.support.v4.view.ViewPager
            android:id="@+id/gradienttab_main_vp_pages"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/gradienttab_main_ly_tabs" />
    
    </RelativeLayout>

      主界面JAVA文件 MainActivity.java 中的代码:

    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentActivity;
    import android.support.v4.app.FragmentPagerAdapter;
    import android.support.v4.view.ViewPager;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends FragmentActivity {
        private ViewPager viewpager;
    
        private List<GradientTab> tabList;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            viewpager = (ViewPager) findViewById(R.id.gradienttab_main_vp_pages);
            initData();
            initEvents();
        }
    
        private void initData() {
            // 初始化盛放Fragment的列表
            final List<Fragment> list = new ArrayList<>();
            for (int i = 1; i <= 4; i++) {
                PageFragment fragment = new PageFragment();
                Bundle bundle = new Bundle();
                bundle.putString("title", "This is page " + i);
                fragment.setArguments(bundle);
                list.add(fragment);
            }
            // 为ViewPager适配数据
            viewpager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
                @Override
                public Fragment getItem(int position) {
                    return list.get(position);
                }
    
                @Override
                public int getCount() {
                    return list.size();
                }
            });
            // 初始化四个Tab按钮,添加到List列表中
            tabList = new ArrayList<>();
            tabList.add((GradientTab) findViewById(R.id.gradienttab_main_tab_tab1));
            tabList.add((GradientTab) findViewById(R.id.gradienttab_main_tab_tab2));
            tabList.add((GradientTab) findViewById(R.id.gradienttab_main_tab_tab3));
            tabList.add((GradientTab) findViewById(R.id.gradienttab_main_tab_tab4));
        }
    
        private void initEvents() {
            // ViewPager的滚动事件
            viewpager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                    tabList.get(position).setAlpha(1 - positionOffset);
                    tabList.get((int) Math.ceil(position + positionOffset)).setAlpha(positionOffset == 0 ? 1 : positionOffset);
                }
    
                @Override
                public void onPageSelected(int position) {
                }
    
                @Override
                public void onPageScrollStateChanged(int state) {
                }
            });
        }
    }

      运行效果图如下所示:

     

  • 相关阅读:
    JDK1.8源码之String
    C# MySQL数据库的备份 还原 初始化
    c# 校验文本框的正则
    生成条形码和二维码并实现打印的功能
    获取一张图片的字节数组及字节数组的合并
    多线程以及抓取图片。
    C#获取URL参数值(NameValueCollection)
    键值对
    SqLiter
    生成机器码
  • 原文地址:https://www.cnblogs.com/itgungnir/p/6756959.html
Copyright © 2011-2022 走看看