尾声
如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
这里,笔者分享一份从架构哲学的层面来剖析的视频及资料给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。
Android进阶学习资料库
一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
大厂面试真题
PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
《2019-2021字节跳动Android面试历年真题解析》
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
003 import com.pupa.common.util.StringHelper;
004 import com.pupa.TabBarDemo.R;
005
006 import android.annotation.SuppressLint;
007 import android.content.Context;
008 import android.content.res.Resources;
009 import android.content.res.TypedArray;
010 import android.graphics.Bitmap;
011 import android.graphics.BitmapFactory;
012 import android.graphics.Canvas;
013 import android.graphics.Color;
014 import android.graphics.Paint;
015 import android.graphics.Rect;
016 import android.graphics.drawable.Drawable;
017 import android.util.AttributeSet;
018 import android.view.Display;
019 import android.view.Gravity;
020 import android.view.View;
021 import android.view.WindowManager;
022 import android.widget.ImageView;
023 import android.widget.ImageView.ScaleType;
024 import android.widget.LinearLayout;
025 import android.widget.TextView;
026
027 public class TabBar extends LinearLayout {
028 private static final String TAG = “TabBar”;
029 private final TabBar mTabBar; // 自己
030 private final Context mContext;
031 private final AttributeSet mAttrs;
032 private int mDefStyle;
033
034 private Paint mPaint;
035 private int mCurrentTabMaskColor;
036 private int mCurrentTabMaskAlpha;
037
038 private String mResPackageName;
039 private CharSequence[] mTitles;
040 private CharSequence[] mIconNames;
041 private Drawable[] mIcons;
042 private Drawable mSeperator;
043 private int mSeperatorResId;
044 private int mSeperatorWidth;
045
046 private boolean mIconAboveTitle;
047
048 private int mCurrentTabIndex;
049 private int mTabCount;
050 private int mTabWidth;
051 private int mPosition;
052 private OnCurrentTabChangedListener mTabChangedListener;
053
054 public static final int POSITION_TOP = 1; // 位于顶部或者底部
055 public static final int POSITION_BOTTOM = 2;
056
057 public TabBar(Context context) {
058 this(context, null);
059 // TODO Auto-generated constructor stub
060 }
061
062 public TabBar(Context context, AttributeSet attrs) {
063 super(context, attrs);
064 setWillNotDraw(false); // 重要!!!
065 mContext = context;
066 mAttrs = attrs;
067 mCurrentTabIndex = -1;
068 mTabCount = 0;
069 mSeperatorWidth = 0;
070 mPosition = POSITION_TOP;
071 mCurrentTabMaskColor = Color.BLACK;
072 mCurrentTabMaskAlpha = 0x5f;
073 mPaint = new Paint();
074 mTabBar = this;
075 init();
076 // TODO Auto-generated constructor stub
077 }
078
079 @SuppressWarnings(“deprecation”)
080 public void init() {
081 getResourcesFromXml();
082 this.setOrientation(LinearLayout.HORIZONTAL);
083 this.setPadding(0, 0, 0, 0);
084
085 WindowManager wm = (WindowManager) mContext
086 .getSystemService(Context.WINDOW_SERVICE);
087 Display dp = wm.getDefaultDisplay();
088 mTabWidth = dp.getWidth();
089
090 mTabCount = mTitles.length;
091
092 if (mTabCount > 0) {
093 if (mSeperator != null) {
094 Bitmap bmp = BitmapFactory.decodeResource(getResources(),
095 mSeperatorResId);
096 mSeperatorWidth = bmp.getWidth();
097 mTabWidth = mTabWidth - (mTabCount - 1) * mSeperatorWidth;
098 bmp.recycle();
099 bmp = null;
100 }
101 mTabWidth = mTabWidth / mTabCount; // 计算每个tab的宽度
102 mCurrentTabIndex = 0;
103 }
104
105 LayoutParams inParams = new LayoutParams(LayoutParams.MATCH_PARENT,
106 LayoutParams.WRAP_CONTENT);
107 LayoutParams outParams = new LayoutParams(mTabWidth,
108 LayoutParams.WRAP_CONTENT);
109 LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
110 LayoutParams.WRAP_CONTENT);
111 View.OnClickListener clkListener = new View.OnClickListener() {
112
113 @Override
114 public void onClick(View v) {
115 // TODO Auto-generated method stub
116 int index = (Integer) v.getTag();
117 if (index != mCurrentTabIndex) {
118 if (mTabChangedListener != null)
119 mTabChangedListener.onCurrentTabChanged(index);
120 mCurrentTabIndex = index;
121 mTabBar.invalidate();
122 }
123 }
124 };
125
126 //逐个添加Tab
127 for (int i = 0; i < mTabCount; ++i) {
128 LinearLayout tab = new LinearLayout(mContext);
129 tab.setOrientation(LinearLayout.VERTICAL);
130 tab.setPadding(0, 0, 0, 0);
131 tab.setTag(i); // 设置内部标号
132 tab.setClickable(true);
133 ImageView imv = new ImageView(mContext);
134 imv.setScaleType(ScaleType.CENTER);
135 if (i < mIcons.length)
136 imv.setImageDrawable(mIcons[i]);
137 TextView tv = new TextView(mContext);
138 tv.setGravity(Gravity.CENTER_HORIZONTAL);
139 tv.setText(mTitles[i]);
140 if (mIconAboveTitle) { // 图标在标题之上
141 tab.addView(imv, inParams);
142 tab.addView(tv, inParams);
143 } else { // 标题在图标之上
144 tab.addView(tv, inParams);
145 tab.addView(imv, inParams);
146 }
147 tab.setOnClickListener(clkListener);
148 this.addView(tab, outParams);
149 if (mSeperator != null && i < mTabCount - 1) {
150 ImageView sep = new ImageView(mContext);
151 sep.setImageDrawable(mSeperator);
152 this.addView(sep, params);
153 }
154 }
155 }
156
157 /**
158 * 设置当前Tab的序号
159 *
160 * @param index
161 * 你想指定的Tab的序号
162 */
163 public void setCurrentTab(int index) {
164 if (index > -1 && index < mTabCount&&index!=mCurrentTabIndex) {
165 mCurrentTabIndex = index;
166 this.invalidate();
167 if (mTabChangedListener != null)
168 mTabChangedListener.onCurrentTabChanged(mCurrentTabIndex);
169 }
170 }
171
172 public void setOnCurrentTabChangedListener(
173 OnCurrentTabChangedListener listener) {
174 mTabChangedListener = listener;
175 }
176
177 /**
178 * 设置TabBar在顶端还是底端。真实位置由你的Activity的布局文件决定,这里仅仅是作一个标识, 根据这个信息可以增加一些自定义的效果
179 *
180 * @param i
181 * 顶端TabBar.POSITION_TOP或底端TabBar.POSITION_BOTTOM
182 */
183 public void setTabBarPosition(int i) {
184 mPosition = i;
185 }
186
187 /**
188 * 设定工程中R.java文件的包名,因为在解析出各个Tab的icon时要用到。如果是默认值则无需指定
189 *
190 * @param name
191 * R.java文件的包名
192 */
193 public void setResourcesPackageName(String name) {
194 mResPackageName = name;
195 }
196
197 /**
198 * 设置Tab选中后的颜色,默认alpha为0x5f
199 *
200 * @param c
201 * rgb颜色值
202 */
203 public void setCurrentTabMaskColor(int rgb) {
204 mCurrentTabMaskColor = rgb;
205 }
206
207 /**
208 * 设置Tab选中后的颜色。为什么要重载这个方法呢?因为我总是记不住Alpha值0和255谁是全透明, 于是宁愿把ARGB颜色中A跟RGB分开设置……
209 *
210 * @param rgb
211 * rgb颜色值
212 * @param a
213 * alpha值
214 */
215 public void setCurrentTabMaskColor(int rgb, int a) {
216 mCurrentTabMaskColor = rgb;
217 mCurrentTabMaskAlpha = a;
218 }
219
220 /**
221 * 获取Tab个数
文末
架构师不是天生的,是在项目中磨练起来的,所以,我们学了技术就需要结合项目进行实战训练,那么在Android里面最常用的架构无外乎 MVC,MVP,MVVM,但是这些思想如果和模块化,层次化,组件化混和在一起,那就不是一件那么简单的事了,我们需要一个真正身经百战的架构师才能讲解透彻其中蕴含的深理。
一线互联网Android面试题总结含详解(初级到高级专题)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
MVP,MVVM,但是这些思想如果和模块化,层次化,组件化混和在一起,那就不是一件那么简单的事了,我们需要一个真正身经百战的架构师才能讲解透彻其中蕴含的深理。
[外链图片转存中…(img-fyV8k7bz-1715717416826)]
[外链图片转存中…(img-bJWpu6kI-1715717416826)]
一线互联网Android面试题总结含详解(初级到高级专题)
[外链图片转存中…(img-S1RjLpOD-1715717416827)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!