1.Touch處理
MotionEventCompat.getActionMasked(ev)
等價于
event.getAction() & ACTION_MASK
/**
* Call {@link MotionEvent#getAction}, returning only the {@link #ACTION_MASK}
* portion.
*/
public static int getActionMasked(MotionEvent event) {
return event.getAction() & ACTION_MASK;
}
2.枚舉
enum
public enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY,THURSDAY, FRIDAY, SATURDAY
}
public enum Day {
MONDAY(1, "星期一", "星期一各種不在狀態(tài)"),
TUESDAY(2, "星期二", "星期二依舊犯困"),
WEDNESDAY(3, "星期三", "星期三感覺半周終于過去了"),
THURSDAY(4, "星期四", "星期四期待這星期五"),
FRIDAY(5, "星期五", "星期五感覺還不錯"),
SATURDAY(6, "星期六", "星期六感覺非常好"),
SUNDAY(7, "星期日", "星期日感覺周末還沒過夠。撩嚼。停士。");
Day(int index, String name, String value) {
this.index = index;
this.name = name;
this.value = value;
}
private int index;
private String name;
private String value;
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
ENUM中的每一個值都是一個Object,它的每個聲明都會占用運行時的部分內(nèi)存以便能夠引用到這個Object完丽。因此ENUM的值會比對應(yīng)的Integer和String所占用的內(nèi)存多恋技。過度在Android開發(fā)中使用ENUM將會增大DEX大小,并會增大運行時的內(nèi)存分配大小舰涌。
Android中的注解方式
添加支持注解的依賴到你的項目中猖任,需要在build.gradle文件中的依賴塊中添加:
dependencies { compile 'com.android.support:support-annotations:24.2.0' }
IntDef
和StringDef
是兩個神奇的注解常量,可以用來替代Enum的使用瓷耙。這些注解能夠幫助我們在編譯時對變量賦值進(jìn)行檢查朱躺。
public static final int SUNDAY= 0;
public static final int MONDAY= 1;
public static final int TUESDAY= 2;
public static final int WEDNESDAY= 3;
...
@IntDef({SUNDAY, MONDAY, TUESDAY, WEDNESDAY,THURSDAY, FRIDAY, SATURDAY})
@Retention(RetentionPolicy.SOURCE)
public @interface Day{}
// 使用
@Day int today;
// Constants
public static final String WINTER = "Winter";
public static final String SPRING = "Spring";
public static final String SUMMER = "Summer";
public static final String FALL = "Fall";
// Declare the @ StringDef for these constants:
@ StringDef ({WINTER, SPRING, SUMMER, FALL})
@Retention(RetentionPolicy.SOURCE)
public @interface Season {}
// 在使用的時候,例如我們有一個變量名稱為:
int color;
// 與此同時有一個函數(shù):
void setColor(@Color int COLOR){
color = COLOR;
}
//在調(diào)用此函數(shù)的時候搁痛,參數(shù)名稱如果不是IntDef中的變量名稱的時候长搀,例如
//setColor(2),Android Studio中就會提示錯誤(雖然編譯仍然會通過)鸡典。
Android 性能:避免在Android上使用ENUM
Android開發(fā)中用于替代Enum的@IntDef的使用
3.getResources().getDrawable() 過時的解決方法
- 當(dāng)你這個Drawable受當(dāng)前Activity主題的影響時
ContextCompat.getDrawable(getActivity(), R.drawable.name);
- 當(dāng)你這個Drawable不受主題影響時
ResourcesCompat.getDrawable(getResources(), R.drawable.name, null);
- 當(dāng)你這個Drawable想使用另外一個主題樣式時
ResourcesCompat.getDrawable(getResources(), R.drawable.name, anotherTheme);
4.填加分割線
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@drawable/setting_divider"
android:showDividers="middle"
android:background="@drawable/area_dialog_bg"
android:gravity="center">
5.獲取屏幕寬高
1. 通過WindowManager獲取
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
heigth = dm.heightPixels;
width = dm.widthPixels;
2. 通過Resources獲取
DisplayMetrics dm = getResources().getDisplayMetrics();
heigth = dm.heightPixels;
width = dm.widthPixels;
3. 獲取屏幕的默認(rèn)分辨率
Display display = getWindowManager().getDefaultDisplay();
heigth = display.getWidth();
width = display.getHeight();
1源请、3都是使用getWindowManager()得到的,但這個是建立在類Activity上的彻况,如果自己的類沒有繼承這個谁尸,則取不到數(shù)據(jù),故個人認(rèn)為通過Resources獲取最好。
在非Activity類中纽甘,拿到WindowManager
((WindowManager) MyApplicationContext.context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay()
.getMetrics(dm);
6.分享(不調(diào)用第三方SDK)
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, "來自WanAndroid" + detailLink);
startActivity(Intent.createChooser(shareIntent, "分享"));
7.RecyclerView點擊條目自動滑動到中央
public class CenterLayoutManager extends LinearLayoutManager {
public CenterLayoutManager(Context context) {
super(context);
}
public CenterLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public CenterLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private static class CenterSmoothScroller extends LinearSmoothScroller {
CenterSmoothScroller(Context context) {
super(context);
}
@Override
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
}
}
}
其中calculateDtToFit的參數(shù)良蛮,viewStart viewEnd
表示被點擊的條目需要移動的Start/End
,viewEnd - viewStart = View的寬度悍赢;boxStart boxEnd
表示當(dāng)前RecyclerView的Start/End
决瞳,boxEnd - boxStart = RecyclerView的寬度(無Padding)货徙。
public int calculateDyToMakeVisible(View view, int snapPreference) {
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
if (layoutManager == null || !layoutManager.canScrollVertically()) {
return 0;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
final int top = layoutManager.getDecoratedTop(view) - params.topMargin;
final int bottom = layoutManager.getDecoratedBottom(view) + params.bottomMargin;
final int start = layoutManager.getPaddingTop();
final int end = layoutManager.getHeight() - layoutManager.getPaddingBottom();
return calculateDtToFit(top, bottom, start, end, snapPreference);
}
8.自定義View的動畫還可以這么搞
mTabSelector = new Runnable() {
public void run() {
final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2;
smoothScrollTo(scrollPos, 0);
mTabSelector = null;
}
};
post(mTabSelector);
9.RecyclerView滾動到當(dāng)前界面第一個
scrollToPosition
會把不在屏幕的 Item 移動到屏幕上,原來在上方的 Item 移動到 可見 Item 的第一項皮胡,在下方的移動到屏幕可見 Item 的最后一項痴颊。已經(jīng)顯示的 Item 不會移動。
scrollToPositionWithOffset
會把 Item 移動到可見 Item 的第一項屡贺,即使它已經(jīng)在可見 Item 之中蠢棱。另外它還有 offset 參數(shù),表示 Item 移動到第一項后跟 RecyclerView 上邊界或下邊界之間的距離(默認(rèn)是 0)
10.MAC快捷鍵
大小寫轉(zhuǎn)換 Cmd + Shift + U Ctrl + Shift + U
注釋代碼(//) Cmd + / Ctrl + /
注釋代碼(/**/) Cmd + Option + / Ctrl + Alt + /
格式化代碼 Cmd + Option + L Ctrl + Alt + L
清除無效包引用 Option + Control + O Alt + Ctrl + O
查找 Cmd + F Ctrl + F
查找+替換 Cmd + R Ctrl + R
上下移動代碼 Option + Shift + Up/Down Alt + Shift + Up/Down
刪除行 Cmd + Delete Ctrl + Y
擴大縮小選中范圍 Option + Up/Down Ctrl + W/Ctrl + Shift + W
快捷生成結(jié)構(gòu)體 Cmd + Option + T Ctrl + Alt + T
快捷覆寫方法 Ctrl + O Ctrl + O
快捷定位到行首/尾 Cmd + Left/Right Ctrl + Left/Right
折疊展開代碼塊 Cmd + Plus,Minus Ctrl + Plus/Minus
折疊展開全部代碼塊 Cmd + Shift + Plus,Minus Ctrl + Shift + Plus,Minus
文件方法結(jié)構(gòu) Cmd + F12 Ctrl + F12
查找調(diào)用的位置 Ctrl + Option + H Ctrl + Alt + H
大小寫轉(zhuǎn)換 Cmd + Shift + U Ctrl + Shift + U
11.CoordinatorLayout相關(guān)注意事項
CoordinatorLayout繼承自viewgroup,但是使用類似于framLayout,有層次結(jié)構(gòu),后面的布局會覆蓋在前面的布局之上,但跟behavior屬性也有很大關(guān)系,的app:layout_behavior屬性,只有CoordinatorLayout的直接子布局才能響應(yīng),所以不要做徒勞無功的事
CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout結(jié)合起來才能產(chǎn)生這么神奇的效果,不要想當(dāng)然的光拿著CoordinatorLayout就要玩出來(剛接觸的時候我也有這種想法),累死你
AppBarLayout:繼承自lineLayout,使用時其他屬性隨lineLayou,已經(jīng)響應(yīng)了CoordinatorLayout的layout_behavior屬性,所以他能搞出那么多特效來
AppBarLayout的直接子控件可以設(shè)置的屬性:layout_scrollFlags
1.scroll|exitUntilCollapsed如果AppBarLayout的直接子控件設(shè)置該屬性,該子控件可以滾動,向上滾動NestedScrollView出父布局(一般為CoordinatorLayout)時,會折疊到頂端,向下滾動時NestedScrollView必須滾動到最上面的時候才能拉出該布局
2.scroll|enterAlways:只要向下滾動該布局就會顯示出來,只要向上滑動該布局就會向上收縮
3.scroll|enterAlwaysCollapsed:向下滾動NestedScrollView到最底端時該布局才會顯示出來
4.如果不設(shè)置改屬性,則改布局不能滑動
- CollapsingToolbarLayout,字面意思是折疊的toolbar,它確實是起到折疊作用的,可以把自己的自布局折疊 繼承自framLayout,所以它的直接子類可以設(shè)置layout_gravity來控制顯示的位置,它的直接子布局可以使用的屬性:app:layout_collapseMode(折疊模式):可取的值如下:
1.pin:在滑動過程中,此自布局會固定在它所在的位置不動,直到CollapsingToolbarLayout全部折疊或者全部展開
2.parallax:視察效果,在滑動過程中,不管上滑還是下滑都會有視察效果,不知道什么事視察效果自己看gif圖(layout_collapseParallaxMultiplier視差因子 0~1之間取值,當(dāng)設(shè)置了parallax時可以配合這個屬性使用,調(diào)節(jié)自己想要的視差效果)
3.不設(shè)置:跟隨NestedScrollView的滑動一起滑動,NestedScrollView滑動多少距離他就會跟著走多少距離
toobar最好是放在CollapsingToolbarLayout,也不是沒有其他用法,但是在這套系統(tǒng)中一般只能放在CollapsingToolbarLayout里面,才能達(dá)到好的效果,這里toolbar同時設(shè)置layout_gravity和app:layout_collapseMode時有一些比較復(fù)雜的情況.不一一作介紹,因為一般我們只會把toolbar放在最上面(不用設(shè)置layout_gravity屬性,默認(rèn)的),并且設(shè)置app:layout_collapseMode為pin,讓他固定在最頂端,有興趣的自己試試其他情況,
告你一個驚天大冪冪:只要CollapsingToolbarLayout里面包含有toolbar那么CollapsingToolbarLayout的折疊后高度就是toolbar的高度,相當(dāng)于CollapsingToolbarLayout設(shè)置了minHeight屬性,
再告訴你一個驚天大咪咪:CollapsingToolbarLayout折疊到最頂端時,它就是老大,會處于最上層,包括toolbar在內(nèi),所有的布局都會被他蓋住,顯示不出來.
CollapsingToolbarLayout 自己的屬性 說明,不是直接子布局可用的,是自己可以用的屬性
contentScrim折疊后的顏色也是展開時的漸變顏色,效果超贊.
title標(biāo)題,如果設(shè)置在折疊時會動畫的顯示到折疊后的部分上面,拉開時會展開,很好玩的
expandedTitleMargin當(dāng)title文字展開時文字的margin,當(dāng)然還有marginTop等屬性,腦補吧
app:collapsedTitleTextAppearance=”@style/Text”折疊時title的樣式里面可以定義字體大小顏色等
app:collapsedTitleTextAppearance=”@style/Text1”折疊時title的樣式里面可以定義字體大小顏色等
當(dāng)然還有一些,自己試試吧,現(xiàn)在的這些已經(jīng)完全夠用了還有最后一個問題:怎么實現(xiàn)固定表頭,這個也簡單,寫一個布局放在CollapsingToolbarLayout之后,AppBarLayout之內(nèi)即可,xml文件中自己找找看吧.你要是問如果放在CollapsingToolbarLayout之前,AppBarLayout之內(nèi)會怎么樣?這樣折疊布局就不起作用了.不會折疊了.
https://blog.csdn.net/qq_31340657/article/details/51918773
12. startActivities
fun multiIntent(view : View) {
val intent_1 = Intent(this,IntentActivityA::class.java)
val intent_2 = Intent(this,IntentActivityB::class.java)
val intent_3 = Intent(this,IntentActivityC::class.java)
startActivities(arrayOf(intent_1,intent_2,intent_3))
}
IntentActivity C onCreate
IntentActivity B onCreate
IntentActivity C onDestroy
IntentActivity A onCreate
IntentActivity B onDestroy
IntentActivity A onDestroy
注意不是全部創(chuàng)建壓入棧里的甩栈。相鄰原則I殉丁!谤职!
13.代碼中更改margin
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) tv.getLayoutParams();
layoutParams.setMargins(0, 0, DisplayUtils.dip2px(Main2Activity.this,12), DisplayUtils.dip2px(Main2Activity.this,12));
tv.setLayoutParams(layoutParams);
注意:getLayoutParams()
獲取到的是tv的父布局的類型!R谙省T黍凇!蒿柳!如果它的父布局是FrameLayout而你轉(zhuǎn)成LinearLayout.LayoutParams
饶套。程序會報錯!
14.Gson中的TypeToken使用
List<AdBean> result = new Gson().fromJson(cacheContent, new TypeToken<List<AdBean>>() { }.getType());
使用它可以將String轉(zhuǎn)換成List數(shù)組結(jié)構(gòu)垒探。
15. SparseArray和SparseArrayCompat
SparseArray以鍵值對的形式保存數(shù)據(jù)妓蛮,key是int類型,并且是唯一的不允許重復(fù)的key圾叼,而value可以是任何object蛤克。
優(yōu)點
相比HashMap更加節(jié)省內(nèi)存空間,數(shù)據(jù)存儲只依賴key和value2個數(shù)組夷蚊,數(shù)組空間是可復(fù)用的构挤,數(shù)據(jù)的存儲密度較高。
因為key數(shù)組是有序的惕鼓,通過key獲取value相對高效筋现。
缺點:
key數(shù)組是保持有序的,在插入和查找時箱歧,通過二分法確定位置key的下標(biāo)矾飞,比較耗時;
插入刪除等操作可能會移動數(shù)組數(shù)據(jù)呀邢。
綜合來說洒沦,SparseArray適用于小數(shù)據(jù)量的鍵值對場景。數(shù)據(jù)量達(dá)到幾百時驼鹅,效率優(yōu)勢和HashMap相比已不明顯微谓。
SparseArray只能在API19以上的系統(tǒng)里面 才有這個類森篷,也就是Android4.4以上。所以Android為我們提供了一個兼容的類SparseArrayCompat豺型,使用這個可以兼容更低的版本仲智。
private static final int BASE_ITEM_TYPE_HEADER = 100000;
private SparseArrayCompat<View> mHeaderViews = new SparseArrayCompat<>();
public void addHeaderView(View view) {
mHeaderViews.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER, view);
}
@Override
public int getItemViewType(int position) {
if (isHeaderViewPos(position)) {
return mHeaderViews.keyAt(position);
} else if (isFooterViewPos(position)) {
return mFootViews.keyAt(position - getHeadersCount() - getRealItemCount());
}
return mInnerAdapter.getItemViewType(position - getHeadersCount());
}
16.隱藏狀態(tài)欄
<style name="AppLaunch" parent="@android:style/Theme.Light.NoTitleBar.Fullscreen">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@drawable/app_window_bg</item>
<item name="windowActionBar">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
設(shè)置全屏?xí)詣与[藏狀態(tài)欄!R霭薄钓辆!但是不會隱藏標(biāo)題欄,所以想要全屏需要windowNoTitle肴焊、windowFullscreen一起設(shè)置前联!
17.List<T>中的T可以為接口
效果同List<?extends MyInterface>
18.從View中獲取Context的正確姿勢
在繼承自AppCompatActivity時娶眷,Android底層會將我們應(yīng)用的控件轉(zhuǎn)為v7包中對應(yīng)的控件似嗤,Context就被替換成了TintContextWrapper(它繼承自ContextWrapper)。
或者
View 可能繼承自 AppCompat 系的 View (比如 AppCompatTextView, AppCompatImageView)届宠,此時的context存儲于TintContextWrapper的getBaseContext中烁落,所以需要以下處理:
Context context = v.getContext();
if (context instanceof TintContextWrapper) {
context = ((TintContextWrapper) context).getBaseContext();
}
if (context instanceof Activity) {
((Activity) context).finish();
}
或者
public static Activity getActivityFromView(View view) {
Context context = view.getContext();
while (context instanceof ContextWrapper) {
if (context instanceof Activity) {
return (Activity) context;
}
context = ((ContextWrapper) context).getBaseContext();
}
return null;
}
Android 從 View 中獲取 Activity 時遇到 TintContextWrapper cannot be cast to 的問題
19.文件讀寫操作時,先進(jìn)行判斷
public static String getCachePath(Context context) {
if (Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState())) {
// 有sd卡
try {
return context.getExternalCacheDir().getAbsolutePath();
} catch (Exception e) {
e.printStackTrace();
return context.getCacheDir().getAbsolutePath();
}
} else {
// 無sd卡
return context.getCacheDir().getAbsolutePath();
}
}
20.點擊通知的跳轉(zhuǎn)邏輯
startActivities(new Intent[]{mainIntent, targetIntent});
這樣的話豌注,先跳轉(zhuǎn)目標(biāo)頁伤塌,點擊返回跳轉(zhuǎn)到主頁面。
21.RecyclerView的小技巧
使內(nèi)容等間距排列轧铁,spanCount是個數(shù)每聪,spacing是兩個Item的間距。
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item position
int column = position % spanCount; // item column
outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
if (position >= spanCount) {
outRect.top = spacing; // item top
}
}
22.判斷intent是否能跳轉(zhuǎn)/是否有效
public static boolean checkIntent(Intent intent) {
return checkIntent(intent, PackageManager.GET_INTENT_FILTERS);
}
public static boolean checkIntent(Intent intent, int flags) {
PackageManager pm = RootInit.getInstance().getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(intent, flags);
final int size = (activities == null) ? 0 : activities.size();
return size > 0;
}
23.WebView配置
private void initWebViewSetting() {
WebSettings ws = getSettings();
try {
ws.setJavaScriptEnabled(true);
// Logger
} catch (Exception e) {
e.printStackTrace();
}
ws.setSupportZoom(false);
String appCacheDir = Paths.getInternalCachePath(getContext());
ws.setDomStorageEnabled(true);
ws.setAppCacheMaxSize(1024 * 1024 * 4);//設(shè)置緩沖
ws.setAppCachePath(appCacheDir);
ws.setAllowFileAccess(true);
ws.setAppCacheEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ws.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
ws.setJavaScriptCanOpenWindowsAutomatically(true);
ws.setDefaultTextEncodingName("utf-8");
ws.setUseWideViewPort(true);
ws.setLoadWithOverviewMode(true);
ws.setBuiltInZoomControls(false);
// webView.setBackgroundColor(0);
ws.setCacheMode(WebSettings.LOAD_NO_CACHE);
removeJavascriptInterface("searchBoxJavaBridge_");
removeJavascriptInterface("accessibility");
removeJavascriptInterface("accessibilityTraversal");
ws.setAllowFileAccess(true);// 設(shè)置允許訪問文件數(shù)據(jù)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
ws.setAllowUniversalAccessFromFileURLs(false);
ws.setAllowFileAccessFromFileURLs(false);
}
setWebChromeClient(new BpWebChromeClient());
setWebViewClient(new BpWebViewClient());
setDownloadListener(new DownloadListener() {
@Override
public void onDownloadStart(String url, String userAgent, String contentDisposition,
String mimetype, long contentLength) {
if (null != url) {
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
if (ToolBox.checkIntent(intent)) {
try {
getActivity().startActivity(intent);
} catch (Throwable e) {
YLog.e(e);
}
}
}
}
});
}
24. PopupWindow 沉浸式
pop.setClippingEnabled(false)
25. Dialog 沉浸式
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
26.android studio預(yù)覽可視化
if (thisView.isInEditMode()) {//這段代碼在運行時不會執(zhí)行齿风,只會在Studio編輯預(yù)覽時運行药薯,不用在意性能問題
final int d = SmartUtil.dp2px(5);
final Context context = thisView.getContext();
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(0xcccccccc);
paint.setStrokeWidth(SmartUtil.dp2px(1));
paint.setPathEffect(new DashPathEffect(new float[]{d, d, d, d}, 1));
canvas.drawRect(d, d, thisView.getWidth() - d, thisView.getBottom() - d, paint);
TextView textView = new TextView(context);
textView.setText(context.getString(R.string.srl_component_falsify, getClass().getSimpleName(), SmartUtil.px2dp(thisView.getHeight())));
textView.setTextColor(0xcccccccc);
textView.setGravity(Gravity.CENTER);
//noinspection UnnecessaryLocalVariable
View view = textView;
view.measure(makeMeasureSpec(thisView.getWidth(), EXACTLY), makeMeasureSpec(thisView.getHeight(), EXACTLY));
view.layout(0, 0, thisView.getWidth(), thisView.getHeight());
view.draw(canvas);
}
27.descendantFocusability子布局獲取焦點
beforeDescendants:viewgroup會優(yōu)先其子類控件而獲取到焦點
afterDescendants:viewgroup只有當(dāng)其子類控件不需要獲取焦點時才獲取焦點
blocksDescendants:viewgroup會覆蓋子類控件而直接獲得焦點
注意:它只在RelativeLayout中設(shè)置生效!>劝摺果善!
28.注解生命周期
-
RetentionPolicy.SOURCE
源碼注解,編譯成.class文件后注解就不存在系谐,用來提示開發(fā)者 -
RetentionPolicy.CLASS CLASS
匯編注解巾陕,編譯成.class文件后注解也還存在,用于自動生成代碼 -
RetentionPolicy.RUNTIME
運行時動態(tài)注解纪他,生命周期一直程序運行時都存在鄙煤,常用于自動注入
29.繪制完加載布局
final View layout = findViewById(Window.ID_ANDROID_CONTENT);
ViewTreeObserver vto = layout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
initUIandEvent();
}
});
30.光暈效果(蒙層)
BlurMaskFilter
/**
* This takes a mask, and blurs its edge by the specified radius. Whether or
* or not to include the original mask, and whether the blur goes outside,
* inside, or straddles, the original mask's border, is controlled by the
* Blur enum.
*/
/* 翻譯成大白話的意思就是BlurMaskFilter可以在原本的View上添加一層指定模糊半徑的蒙層,具體模糊的方式茶袒,由Blur枚舉類型控制 */
// 光暈的paint
private val outPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
// 光暈的顏色
color = Color.parseColor("#e6e8db")
// 使用BlurMaskFilter制作陰影效果
maskFilter = BlurMaskFilter(shadowRadius.toFloat(), BlurMaskFilter.Blur.SOLID)
}
31.RecyclerView融邊效果
android:fadingEdgeLength="30dp"
android:requiresFadingEdge="horizontal"
32.DialogFragment全屏顯示
final Window window = getDialog().getWindow();
window.setBackgroundDrawableResource(R.color.transparent);
window.getDecorView().setPadding(0, 0, 0, 0);
WindowManager.LayoutParams lp = window.getAttributes();
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
注意:第二行和第三行必須設(shè)置才能全屏梯刚,親測!
33. 自定義控件調(diào)整位置
offsetTopAndBottom薪寓、offsetLeftAndRight
43.鍵盤彈出背景不動
手機屏幕的高為1920px亡资,那么整個Activity的布局高度也為1920px澜共。當(dāng)設(shè)置該屬性后點擊界面中的EditText,此時彈出軟鍵盤其高度為800px锥腻。為了完整地顯示此軟鍵盤搔体,系統(tǒng)會調(diào)整Activity布局的高度為1920px-800px=1120px置森。
當(dāng) windowSoftInputMode 被設(shè)置為 adjustResize 時候,當(dāng)布局調(diào)整的時候被調(diào)整的布局均會重繪制,并走了onMeasure绳泉,onSizeChanged蓄氧,onLayout 弧满。
當(dāng) windowSoftInputMode 被設(shè)置為 adjustPan 時候俊庇,當(dāng)布局調(diào)整的時候被調(diào)整的布局均會重繪制,并走了onMeasure, onLayout 甲葬。
這里只需要注意 兩者都走了 onMeasure 方法廊勃,至于 adjustPan 沒走 onSizeChanged。
所以只需重寫onMeasure方法经窖,即可實現(xiàn)供搀。
44.PopupWindow透傳致其它View響應(yīng)點擊事件
解決:只需要讓PopupWindow持有焦點即可。
this.setFocusable(true);
或
//最后一個參數(shù)為true
new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
45. dialog相關(guān)背景設(shè)置
1.設(shè)置透明度(Dialog自身的透明度)
WindowManager.LayoutParams lp=dialog.getWindow().getAttributes();
lp.alpha=1.0f;
dialog.getWindow().setAttributes(lp);
alpha在0.0f到1.0f之間钠至。1.0完全不透明,0.0f完全透明
2.設(shè)置黑暗度(Dialog自身的黑暗度)
dialog.setContentView(R.layout.dialog);
WindowManager.LayoutParams lp=dialog.getWindow().getAttributes();
lp.dimAmount=1.0f;
dialog.getWindow().setAttributes(lp);
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
dimAmount在0.0f和1.0f之間胎源,0.0f完全不暗棉钧,1.0f全暗
3.設(shè)置Dialog底背景模糊和黑暗度
WindowManager.LayoutParams.FLAG_BLUR_BEHIND(設(shè)置模糊)
WindowManager.LayoutParams.FLAG_DIM_BEHIND(設(shè)置暗淡)
4.清除Dialog底背景模糊和黑暗度
getDialog().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND | WindowManager.LayoutParams.FLAG_DIM_BEHIND)
46.防止多點觸控
android:splitMotionEvents=false
全局禁用:
<style name="MyStyle">
<item name="android:windowEnableSplitTouch">false</item>
<item name="android:splitMotionEvents>false</item>
</style>
47.DialogFragment 在5.0手機上適配的各種問題
如果出現(xiàn)彈窗在5.0手機上位置不對,設(shè)置Gravity不好使涕蚤,大小尺寸不對宪卿,你可能需要如下設(shè)置來解決
1、布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/add_friend_popup_bg">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="0.5dp"
android:layout_marginBottom="0.5dp"
android:fadeScrollbars="true" />
</FrameLayout>
</FrameLayout>
你需要在內(nèi)容外部在再套一層万栅,這樣彈窗大小的問題就能解決佑钾!
2、設(shè)置主題
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 必須設(shè)置烦粒,不然會出現(xiàn)5.0及以下手機不適配
setStyle(DialogFragment.STYLE_NORMAL, R.style.DialogStyle);
}
<style name="DialogStyle" parent="@android:style/Theme.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowFrame">@null</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsTranslucent">true</item>
</style>
5.0及以下手機dialogFragment 有默認(rèn)主題休溶,顯示位置不對一般是這個導(dǎo)致的!
48.虛擬導(dǎo)航鍵顯示判斷
public static boolean isNavBarVisible(Context context) {
ViewGroup rootLinearLayout = findRootLinearLayout(context);
int navigationBarHeight = 0;
if (rootLinearLayout != null) {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) rootLinearLayout.getLayoutParams();
navigationBarHeight = layoutParams.bottomMargin;
}
return navigationBarHeight != 0;
}
private static ViewGroup findRootLinearLayout(Context context) {
Activity activity = ActivityUtils.getActivityByContext(context);
if (activity != null) {
Window window = activity.getWindow();
if (window != null) {
ViewGroup decorView = (ViewGroup) window.getDecorView();
if (decorView != null) {
View contentView = activity.findViewById(android.R.id.content);
if (contentView != null) {
ViewGroup parent = (ViewGroup) contentView.getParent();
while (parent != decorView) {
if (parent == null) {
return null;
}
if (parent instanceof LinearLayout && !(parent instanceof FitWindowsLinearLayout)) {
return parent;
}
parent = (ViewGroup) parent.getParent();
}
}
}
}
}
return null;
}
51.recyclerView禁用多指
android:splitmotionevents=”false”
或者
recyclerView.setMotionEventSplittingEnabled(false);
52.recyclerView滑動到指定位置,并指定位置在頂部
1.第一種方法
此方法能實現(xiàn)指定位置位于屏幕頂部,但是不具有平滑滾動視覺效果:
if (position != -1) {
mRecycleview.scrollToPosition(position);
LinearLayoutManager mLayoutManager =
(LinearLayoutManager) mRecycleview.getLayoutManager();
mLayoutManager.scrollToPositionWithOffset(position, 0);
}
2.第二種方法
此方法能實現(xiàn)指定位置位于屏幕頂部,具有平滑滾動視覺效果:
首先獲取第一個可見位置和最后一個可見位置,分三種情況:
1.如果如果跳轉(zhuǎn)位置在第一個可見位置之前扰她,就smoothScrollToPosition()可以直接跳轉(zhuǎn);
2.如果跳轉(zhuǎn)位置在第一個可見項之后兽掰,最后一個可見項之前smoothScrollToPosition()不會滾動,此時調(diào)用smoothScrollBy來滑動到指定位置;
3.如果要跳轉(zhuǎn)的位置在最后可見項之后徒役,則先調(diào)用smoothScrollToPosition()將要跳轉(zhuǎn)的位置滾動到可見位置,在addOnScrollListener()里通過onScrollStateChanged控制,調(diào)用smoothMoveToPosition孽尽,再次執(zhí)行判斷;
//目標(biāo)項是否在最后一個可見項之后
private boolean mShouldScroll;
//記錄目標(biāo)項位置
private int mToPosition;
/**
* 滑動到指定位置
*/
private void smoothMoveToPosition(RecyclerView mRecyclerView, final int position) {
// 第一個可見位置
int firstItem = mRecyclerView.getChildLayoutPosition(mRecyclerView.getChildAt(0));
// 最后一個可見位置
int lastItem = mRecyclerView.getChildLayoutPosition(mRecyclerView.getChildAt(mRecyclerView.getChildCount() - 1));
if (position < firstItem) {
// 第一種可能:跳轉(zhuǎn)位置在第一個可見位置之前
mRecyclerView.smoothScrollToPosition(position);
} else if (position <= lastItem) {
// 第二種可能:跳轉(zhuǎn)位置在第一個可見位置之后
int movePosition = position - firstItem;
if (movePosition >= 0 && movePosition < mRecyclerView.getChildCount()) {
int top = mRecyclerView.getChildAt(movePosition).getTop();
mRecyclerView.smoothScrollBy(0, top);
}
} else {
// 第三種可能:跳轉(zhuǎn)位置在最后可見項之后
mRecyclerView.smoothScrollToPosition(position);
mToPosition = position;
mShouldScroll = true;
}
}
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (mShouldScroll&& RecyclerView.SCROLL_STATE_IDLE == newState) {
mShouldScroll = false;
smoothMoveToPosition(irc, mToPosition);
}
}
});
if (position != -1) {
smoothMoveToPosition(irc,position);
}else {
smoothMoveToPosition(irc,position+1);
}
53.RecyclerVIew內(nèi)的Item布局超出來了?
事情是這樣的忧勿,項目升級androidx后發(fā)現(xiàn)杉女,RecyclerVIew內(nèi)的Item布局超出來瞻讽,即外層限制不住它了,相關(guān)代碼:
GridLayoutManager.LayoutParams params = (GridLayoutManager.LayoutParams) rvVoiceRoom.getLayoutParams();
//超過一行需要動態(tài)修改左邊和底部的距離
params.setMargins(DisplayUtil.dip2px(getContext(), 14), 0, 0, 0);
rvVoiceRoom.setLayoutParams(params);
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), spanCount, GridLayoutManager.HORIZONTAL, false);
rvVoiceRoom.setLayoutManager(gridLayoutManager);
明明限制了左邊距是14dp熏挎,為什么顯示效果是直接加在第一個item里了呢速勇,無法限制整個滑動的區(qū)域。
查看布局文件發(fā)現(xiàn)婆瓜,這個RecyclerView沒有父布局快集。
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rv_voice_room"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"/>
由此可以想到,應(yīng)該是androidx修改了RecyclerView的源碼廉白,當(dāng)RecyclerView沒有父布局時个初,對他的layoutParam(GridLayoutManager.LayoutParams)進(jìn)行修改,相當(dāng)于在加在第一個item(最后一個 item里)猴蹂。
故院溺,修復(fù)這個問題也很簡單,套一層父布局即可解決磅轻,布局修改如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_voice_room"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never" />
</FrameLayout>
別忘了修改params的類型
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) rvVoiceRoom.getLayoutParams();
效果和分析的一樣珍逸,確實是這個原因。有時間還是比較下源碼聋溜,MarkW簧拧!撮躁!todo