忘了跟谁学习的了,写一个自定义的底部导航控件:直接上代码
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 BottomBarextends View {
private Contextcontext;
public BottomBar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
//////////////////////////////////////////////////
//提供的api 并且根据api做一定的物理基础准备
//////////////////////////////////////////////////
private int containerId;
private ListfragmentClassList =new ArrayList<>();
private ListtitleList =new ArrayList<>();
private ListiconResBeforeList =new ArrayList<>();
private ListiconResAfterList =new ArrayList<>();
private ListfragmentList =new ArrayList<>();
private int itemCount;
private Paintpaint =new Paint();
private ListiconBitmapBeforeList =new ArrayList<>();
private ListiconBitmapAfterList =new ArrayList<>();
private ListiconRectList =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 BottomBarsetContainer(int containerId) {
this.containerId = containerId;
return this;
}
public BottomBarsetTitleBeforeAndAfterColor(String beforeResCode, String AfterResCode) {//支持"#333333"这种形式
titleColorBefore = Color.parseColor(beforeResCode);
titleColorAfter = Color.parseColor(AfterResCode);
return this;
}
public BottomBarsetTitleSize(int titleSizeInDp) {
this.titleSizeInDp = titleSizeInDp;
return this;
}
public BottomBarsetIconWidth(int iconWidth) {
this.iconWidth = iconWidth;
return this;
}
public BottomBarsetTitleIconMargin(int titleIconMargin) {
this.titleIconMargin = titleIconMargin;
return this;
}
public BottomBarsetIconHeight(int iconHeight) {
this.iconHeight = iconHeight;
return this;
}
public BottomBaraddItem(Class fragmentClass, String title, int iconResBefore, int iconResAfter) {
fragmentClassList.add(fragmentClass);
titleList.add(title);
iconResBeforeList.add(iconResBefore);
iconResAfterList.add(iconResAfter);
return this;
}
public BottomBarsetFirstChecked(int firstCheckedIndex) {//从0开始
this.firstCheckedIndex = firstCheckedIndex;
return this;
}
public void build() {
itemCount =fragmentClassList.size();
//预创建bitmap的Rect并缓存
//预创建icon的Rect并缓存
for (int i =0; 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 BitmapgetBitmap(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 ListtitleXList =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
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
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
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
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 FragmentcurrentFragment;
//注意 这里是只支持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();
}
}
}
使用方法:
主activity的布局
<?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>
用法:
public class MainActivityextends 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();
}
}
网友评论