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) {
                }
            });
        }
    }

      运行效果图如下所示:

     

  • 相关阅读:
    word设置的密码忘了怎么办?
    Navicat Report Viewer 设置 HTTP 的方法
    如何处理Navicat Report Viewer 报表
    excel密码忘记了怎么办
    Beyond Compare文本比较搜索功能详解
    Popular Cows POJ
    Problem B. Harvest of Apples HDU
    网络流模型整理
    The Shortest Statement CodeForces
    Vasya and Multisets CodeForces
  • 原文地址:https://www.cnblogs.com/itgungnir/p/6756959.html
Copyright © 2011-2022 走看看