自定义底部按钮控件

按钮的代码:

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;
import java.util.List;


public class BottomBar extends View {

    private Context context;

    public BottomBar(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

    //
    //提供的api 并且根据api做一定的物理基础准备
    //

    private int containerId;

    private List<Class> fragmentClassList = new ArrayList<>();
    private List<String> titleList = new ArrayList<>();
    private List<Integer> iconResBeforeList = new ArrayList<>();
    private List<Integer> iconResAfterList = new ArrayList<>();

    private List<Fragment> fragmentList = new ArrayList<>();

    private int itemCount;

    private Paint paint = new Paint();

    private List<Bitmap> iconBitmapBeforeList = new ArrayList<>();
    private List<Bitmap> iconBitmapAfterList = new ArrayList<>();
    private List<Rect> iconRectList = new ArrayList<>();

    private int currentCheckedIndex;
    private int firstCheckedIndex;

    private int titleColorBefore = Color.parseColor("#999999");
    private int titleColorAfter = Color.parseColor("#ff5d5e");

    private int titleSizeInDp = 10;
    private int iconWidth = 20;
    private int iconHeight = 20;
    private int titleIconMargin = 5;

    public BottomBar setContainer(int containerId) {
        this.containerId = containerId;
        return this;
    }

    public BottomBar setTitleBeforeAndAfterColor(String beforeResCode, String AfterResCode) {//支持"#333333"这种形式
        titleColorBefore = Color.parseColor(beforeResCode);
        titleColorAfter = Color.parseColor(AfterResCode);
        return this;
    }

    public BottomBar setTitleSize(int titleSizeInDp) {
        this.titleSizeInDp = titleSizeInDp;
        return this;
    }

    public BottomBar setIconWidth(int iconWidth) {
        this.iconWidth = iconWidth;
        return this;
    }

    public BottomBar setTitleIconMargin(int titleIconMargin) {
        this.titleIconMargin = titleIconMargin;
        return this;
    }

    public BottomBar setIconHeight(int iconHeight) {
        this.iconHeight = iconHeight;
        return this;
    }

    public BottomBar addItem(Class fragmentClass, String title, int iconResBefore, int iconResAfter) {
        fragmentClassList.add(fragmentClass);
        titleList.add(title);
        iconResBeforeList.add(iconResBefore);
        iconResAfterList.add(iconResAfter);
        return this;
    }

    public BottomBar setFirstChecked(int firstCheckedIndex) {//从0开始
        this.firstCheckedIndex = firstCheckedIndex;
        return this;
    }

    public void build() {
        itemCount = fragmentClassList.size();
        //预创建bitmap的Rect并缓存
        //预创建icon的Rect并缓存
        for (int i = 0; i < itemCount; i++) {
            Bitmap beforeBitmap = getBitmap(iconResBeforeList.get(i));
            iconBitmapBeforeList.add(beforeBitmap);

            Bitmap afterBitmap = getBitmap(iconResAfterList.get(i));
            iconBitmapAfterList.add(afterBitmap);

            Rect rect = new Rect();
            iconRectList.add(rect);

            Class clx = fragmentClassList.get(i);
            try {
                Fragment fragment = (Fragment) clx.newInstance();
                fragmentList.add(fragment);
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        currentCheckedIndex = firstCheckedIndex;
        switchFragment(currentCheckedIndex);

        invalidate();
    }

    private Bitmap getBitmap(int resId) {
        BitmapDrawable bitmapDrawable = (BitmapDrawable) context.getResources().getDrawable(resId);
        return bitmapDrawable.getBitmap();
    }

    //
    //初始化数据基础
    //

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        initParam();
    }

    private int titleBaseLine;
    private List<Integer> titleXList = new ArrayList<>();

    private int parentItemWidth;

    private void initParam() {
        if (itemCount != 0) {
            //单个item宽高
            parentItemWidth = getWidth() / itemCount;
            int parentItemHeight = getHeight();

            //图标边长
            int iconWidth = dp2px(this.iconWidth);//先指定20dp
            int iconHeight = dp2px(this.iconHeight);

            //图标文字margin
            int textIconMargin = dp2px(((float)titleIconMargin)/2);//先指定5dp,这里除以一半才是正常的margin,不知道为啥,可能是图片的原因

            //标题高度
            int titleSize = dp2px(titleSizeInDp);//这里先指定10dp
            paint.setTextSize(titleSize);
            Rect rect = new Rect();
            paint.getTextBounds(titleList.get(0), 0, titleList.get(0).length(), rect);
            int titleHeight = rect.height();

            //从而计算得出图标的起始top坐标、文本的baseLine
            int iconTop = (parentItemHeight - iconHeight - textIconMargin - titleHeight)/2;
            titleBaseLine = parentItemHeight - iconTop;

            //对icon的rect的参数进行赋值
            int firstRectX = (parentItemWidth - iconWidth) / 2;//第一个icon的左
            for (int i = 0; i < itemCount; i++) {
                int rectX = i * parentItemWidth + firstRectX;

                Rect temp = iconRectList.get(i);

                temp.left = rectX;
                temp.top = iconTop ;
                temp.right = rectX + iconWidth;
                temp.bottom = iconTop + iconHeight;
            }

            //标题(单位是个问题)
            for (int i = 0; i < itemCount; i ++) {
                String title = titleList.get(i);
                paint.getTextBounds(title, 0, title.length(), rect);
                titleXList.add((parentItemWidth - rect.width()) / 2 + parentItemWidth * i);
            }
        }
    }

    private int dp2px(float dpValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    //
    //根据得到的参数绘制
    //

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);//这里让view自身替我们画背景 如果指定的话

        if (itemCount != 0) {
            //画背景
            paint.setAntiAlias(false);
            for (int i = 0; i < itemCount; i++) {
                Bitmap bitmap = null;
                if (i == currentCheckedIndex) {
                    bitmap = iconBitmapAfterList.get(i);
                } else {
                    bitmap = iconBitmapBeforeList.get(i);
                }
                Rect rect = iconRectList.get(i);
                canvas.drawBitmap(bitmap, null, rect, paint);//null代表bitmap全部画出
            }

            //画文字
            paint.setAntiAlias(true);
            for (int i = 0; i < itemCount; i ++) {
                String title = titleList.get(i);
                if (i == currentCheckedIndex) {
                    paint.setColor(titleColorAfter);
                } else {
                    paint.setColor(titleColorBefore);
                }
                int x = titleXList.get(i);
                canvas.drawText(title, x, titleBaseLine, paint);
            }
        }
    }

    //
    //点击事件:我观察了微博和掌盟,发现down和up都在该区域内才响应
    //

    int target = -1;

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN :
                target = withinWhichArea((int)event.getX());
                break;
            case MotionEvent.ACTION_UP :
                if (event.getY() < 0) {
                    break;
                }
                if (target == withinWhichArea((int)event.getX())) {
                    //这里触发点击事件
                    switchFragment(target);
                    currentCheckedIndex = target;
                    invalidate();
                }
                target = -1;
                break;
        }
        return true;
        //这里return super为什么up执行不到?是因为return super的值,全部取决于你是否
        //clickable,当你down事件来临,不可点击,所以return false,也就是说,而且你没
        //有设置onTouchListener,并且控件是ENABLE的,所以dispatchTouchEvent的返回值
        //也是false,所以在view group的dispatchTransformedTouchEvent也是返回false,
        //这样一来,view group中的first touch target就是空的,所以intercept标记位
        //果断为false,然后就再也进不到循环取孩子的步骤了,直接调用dispatch-
        // TransformedTouchEvent并传孩子为null,所以直接调用view group自身的dispatch-
        // TouchEvent了
    }

    private int withinWhichArea(int x) { return x/parentItemWidth; }//从0开始

    //
    //碎片处理代码
    //
    private Fragment currentFragment;

    //注意 这里是只支持AppCompatActivity 需要支持其他老版的 自行修改
    protected void switchFragment(int whichFragment) {
        Fragment fragment = fragmentList.get(whichFragment);
        int frameLayoutId = containerId;

        if (fragment != null) {
            FragmentTransaction transaction = ((AppCompatActivity)context).getSupportFragmentManager().beginTransaction();
            if (fragment.isAdded()) {
                if (currentFragment != null) {
                    transaction.hide(currentFragment).show(fragment);
                } else {
                    transaction.show(fragment);
                }
            } else {
                if (currentFragment != null) {
                    transaction.hide(currentFragment).add(frameLayoutId, fragment);
                } else {
                    transaction.add(frameLayoutId, fragment);
                }
            }
            currentFragment = fragment;
            transaction.commit();
        }
    }
}

Mainactivity.class:

public class MainActivity extends AppCompatActivity {

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

        BottomBar bottomBar = findViewById(R.id.bottom_bar);
        bottomBar.setContainer(R.id.fl_container)
                .setTitleBeforeAndAfterColor("#999999", "#ff5d5e")
                .addItem(Fragment1.class,
                        "首页",
                        R.drawable.item1_before,
                        R.drawable.item1_after)
                .addItem(Fragment2.class,
                        "订单",
                        R.drawable.item2_before,
                        R.drawable.item2_after)
                .addItem(Fragment3.class,
                        "我的",
                        R.drawable.item3_before,
                        R.drawable.item3_after)
                .build();
    }
}

activity_main。xml

<?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="match_parent"
android:orientation="vertical">

<FrameLayout
    android:id="@+id/fl_container"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1">

</FrameLayout>

<com.example.bottombar.BottomBar
    android:background="#FFFFFF"
    android:id="@+id/bottom_bar"
    android:layout_width="match_parent"
    android:layout_height="46dp"
    android:layout_gravity="bottom" />
</LinearLayout>

好了,可以用了。其他需要优化的地方,根据需求自己优化即可

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Android 中高级按钮控件有: 1. SwitchButton:带有开关功能的按钮。 2. CheckBox:带有复选框功能的按钮。 3. RadioButton:带有单选功能的按钮。 4. ToggleButton:带有切换功能的按钮。 5. FloatingActionButton:浮动操作按钮,常用于执行主要操作。 6. ImageButton:带有图片显示的按钮。 7. Button:普通按钮。 8. CompoundButton: 继承自Button,是CheckBox和RadioButton的父类。 ### 回答2: Android中提供了多种高级按钮控件,以下是其中一些常用的控件: 1. FloatingActionButton(浮动操作按钮):是一个圆形按钮,常用于主要的操作按钮,如新增、发布等。可以通过设置图标、背景颜色等进行个性化定制。 2. ToggleButton(切换按钮):提供了两个状态(开/关)的按钮,用户点击后可以切换状态。可以通过设置文字、图标、背景等进行样式的自定义。 3. Switch(开关按钮):类似于ToggleButton,提供了两个状态的切换按钮,用户可以通过滑动来切换开关状态。可以设置背景颜色、文字等进行个性化修改。 4. CheckBox(复选框):允许用户选择一个或多个选项的按钮控件。通常用于多选的场景,用户可以通过点击勾选或取消勾选。 5. RadioButton(单选按钮):与CheckBox类似,但是RadioButton只允许用户单选一个选项。常用于从多个互斥选项中选择一个。 6. ImageButton(图像按钮):是一个可以显示图像的按钮控件,用户可以通过点击图像进行相关操作。适合用于具有图标化操作的场景。 7. SwitchButton(滑动开关按钮):与Switch类似,但SwitchButton提供更多的自定义功能,用户可以通过滑动开关进行状态的切换。 这些高级按钮控件可以帮助开发者实现更加丰富、灵活的用户交互,提升应用的用户体验。开发者可以根据实际需求选择合适的按钮控件,并通过相关属性进行样式和行为的定制。 ### 回答3: 在Android中,有许多高级按钮控件可用于创建具有各种功能和样式的按钮。以下是几个常见的高级按钮控件: 1. ImageView按钮控件:ImageView按钮是一个高级按钮控件,可以显示图片,为按钮添加更具吸引力的外观和交互效果。可以使用setImageResource()方法设置按钮的图像。 2. ToggleButton控件:ToggleButton控件是一种具有两种状态(开/关)的高级按钮控件,可以使用ToggleButton组件将其呈现为具有两种不同状态的切换按钮。可以使用setChecked()方法设置按钮的状态。 3. FloatingActionButton控件:FloatingActionButton是一种圆形的高级按钮控件,通常位于界面的底部右下角,以引起用户的注意,常用于执行主要操作。可以使用setImageResource()方法设置按钮的图像。 4. CheckBox控件:CheckBox控件是一种高级按钮控件,允许用户选择多个选项,可用于支持多选功能,比如在设置界面中的选项。可以使用setChecked()方法设置按钮的状态。 5. RadioButton控件:RadioButton控件是一种高级按钮控件,类似于CheckBox,但是RadioButton只允许用户选择其中一个选项,通常用于支持单选功能,例如在调查问卷中的问题选项。可以使用setChecked()方法设置按钮的状态。 以上是一些常见的Android高级按钮控件,开发者可以根据需求选择适合自己应用程序的控件来创建更具吸引力和交互性的按钮

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值