部分筆記: canvas, permission , softInput , cardview

圖片上面兩個是圓角,下面不是圓角

1,使用自定義Imageview ,在onDraw裏面實現

    `
    @Override
    protected void onDraw(Canvas canvas) {
        BitmapShader shader;
        BitmapDrawable bitmapDrawable = (BitmapDrawable) getDrawable();
        shader = new BitmapShader(bitmapDrawable.getBitmap(),
                Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        //設置映射否則圖片顯示不全
        RectF rect = new RectF(0.0f, 0.0f, getWidth(), getHeight() + yRadius);
        int width = bitmapDrawable.getBitmap().getWidth();
        int height = bitmapDrawable.getBitmap().getHeight() + (int) yRadius;
        RectF src = new RectF(0.0f, 0.0f, width, height);
        Matrix matrix = new Matrix();
        matrix.setRectToRect(src, rect, Matrix.ScaleToFit.CENTER);
        shader.setLocalMatrix(matrix);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(shader);
        //根據圖片圓角矩形的半徑進行裁剪
        canvas.clipRect(new Rect(0, 0, (int) (rect.right), (int) (rect.bottom - yRadius)));
        //這樣就把下面的部分剪裁掉了,只剩下上面兩個圓角了
        canvas.drawRoundRect(rect, xRadius, yRadius, paint);
    }
    `
同理,可以實現左邊右邊上面下面四種建材,缺點是隻能兩兩實現圓角剪裁而不能自定義某一個角

ps:這個瞭解就好, 不適用, 未來的時候建議使用 glide 學習中的使用完美的剪裁方案, 方便快捷

關於Cavans的方法:

Canvas():創建一個空的畫布,可以使用setBitmap()方法來設置繪製的具體畫布;

Canvas(Bitmap bitmap):以bitmap對象創建一個畫布,則將內容都繪製在bitmap上,bitmap不得爲null;

Canvas(GL gl):在繪製3D效果時使用,與OpenGL有關;

drawColor:設置畫布的背景色;

setBitmap:設置具體的畫布;

clipRect:設置顯示區域,即設置裁剪區;

isOpaque:檢測是否支持透明;

rotate:旋轉畫布;

canvas.drawRect(RectF,Paint)方法用於畫矩形,第一個參數爲圖形顯示區域,第二個參數爲畫筆,設置好圖形顯示區域Rect和畫筆Paint後,即可畫圖;

canvas.drawRoundRect(RectF, float, float, Paint) 方法用於畫圓角矩形,第一個參數爲圖形顯示區域,第二個參數和第三個參數分別是水平圓角半徑和垂直圓角半徑。

canvas.drawLine(startX, startY, stopX, stopY, paint):前四個參數的類型均爲float,最後一個參數類型爲Paint。表示用畫筆paint從點(startX,startY)到點(stopX,stopY)畫一條直線;

canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint):第一個參數oval爲RectF類型,即圓弧顯示區域,startAngle和sweepAngle均爲float類型,分別表示圓弧起始角度和圓弧度數,3點鐘方向爲0度,useCenter設置是否顯示圓心,boolean類型,paint爲畫筆;

canvas.drawCircle(float,float, float, Paint)方法用於畫圓,前兩個參數代表圓心座標,第三個參數爲圓半徑,第四個參數是畫筆;

Rect(int left,int top,int right,int bottom)

left
          矩形左上角X座標值
top
          矩形左上角Y座標值
right
          矩形右下角X座標值
bottom
          矩形右下角Y座標值

ps:這個瞭解即可, 如果未來需要深入學習可以查看 愛哥 的 自定義控件其實很簡單系列

2,關於Android的權限結構: 危險權限(即需要不斷申請的權限)

權限組位於 #Manifest#permission_group 中

1,日曆權限組: CALENDAR “android.permission-group.CALENDAR”

讀取日曆 READ_CALENDAR “android.permission.READ_CALENDAR”

編輯日曆(比如添加行程等) WRITE_CALENDAR “android.permission.WRITE_CALENDAR”

2,攝像機組: CAMERA “android.permission-group.CAMERA”

打開攝像機 CAMERA “android.permission.CAMERA”

3,聯繫人組: CONTACTS “android.permission-group.CONTACTS”

讀取聯繫人 READ_CONTACTS “android.permission.READ_CONTACTS”

修改聯繫人(增加刪除聯繫人) WRITE_CONTACTS “android.permission.WRITE_CONTACTS”

4,麥克風組: MICROPHONE “android.permission-group.MICROPHONE”

打開麥克風 RECORD_AUDIO “android.permission.RECORD_AUDIO”

5,手機使用組: PHONE “android.permission-group.PHONE”

讀取手機狀態 READ_PHONE_STATE “android.permission.READ_PHONE_STATE”

撥打電話(直接自動撥打,不是跳轉到撥打電話界面,任何跳轉都不需要權限,如跳轉到打電話界面和發送短信界面) CALL_PHONE “android.permission.CALL_PHONE”

讀取通話記錄 READ_CALL_LOG “android.permission.READ_CALL_LOG”

修改通話記錄(添加和刪除通話記錄,如黑名單中掛斷電話後還把該通話記錄刪除) WRITE_CALL_LOG “android.permission.WRITE_CALL_LOG”

6,傳感器組: SENSORS “android.permission-group.SENSORS”

使用身體傳感器(其他傳感器沒題) BODY_SENSORS “android.permission.BODY_SENSORS”

7,短信組: SMS “android.permission-group.SMS”

發送短信(直接發送短信) SEND_SMS “android.permission.SEND_SMS”

接收短信 RECEIVE_SMS “android.permission.RECEIVE_SMS”

讀取短信 READ_SMS “android.permission.READ_SMS”

彩信相關 RECEIVE_MMS “android.permission.RECEIVE_MMS”

8,sd卡組: STORAGE “android.permission-group.STORAGE”

讀取sd卡數據 READ_EXTERNAL_STORAGE “android.permission.READ_EXTERNAL_STORAGE”

向sd卡寫數據 WRITE_EXTERNAL_STORAGE “android.permission.WRITE_EXTERNAL_STORAGE”

9,位置組: LOCATION “android.permission-group.LOCATION”

獲取精確位置 ACCESS_FINE_LOCATION “android.permission.ACCESS_FINE_LOCATION”

獲取大致位置 ACCESS_COARSE_LOCATION “android.permission.ACCESS_COARSE_LOCATION”

3,關於Fragment的小坑(不能叫坑,只是我自己的問題,記錄下來是爲了讓自己以後不犯錯)

一般在newInstence中的 fragment是 static的, 所以在合適的時機必須調用 fragment=null ,來銷燬該fragment, 否則下次調用的時候該fragment會使用,但是該fragment的各種狀態卻還在沒有重置

4,彈出dialog的時候彈出軟鍵盤

背景: 項目中任何界面都是 默認不彈出軟鍵盤的,所以 在baseactivity中有 開啓新界面的配置了不彈出軟鍵盤(在onCreate()之前調用:)

//有EditView的界面,默認不彈窗軟鍵盤
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

但是在支付界面是需要輸入支付密碼的, 這個密碼用的是dialog, 需求需要在這個dialog彈出的時候自動彈出軟鍵盤,所以這個時候是需要對軟鍵盤進行處理的,具體處理方法如下:

在dialog的oncreate方法中添加

getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);

如果使用的alertDialog,可以

AlertDialog.Builder builder = new Builder(context);
final View view = View.inflate(context, R.layout.dialog_enter_pwd, null);
builder.setView(view);
builder.setCancelable(false);
final AlertDialog dialog = builder.show();
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);

至此,我的問題就解決了

其他的方法如:

1,在調用dialog之前在activity中調用

getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);

2,在調用完畢後調用

getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

總之: SOFT_INPUT_STATE_ALWAYS_VISIBLE , 和 SOFT_INPUT_STATE_VISIBLE 都試試.

PS:

1, activity的getWindow 是獲取該activity依賴的窗口, 如果當前activity不可見,則值爲null,在當前activity調用該方法得到的Window爲當前的窗口

final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
    attachBaseContext(context);
    ....
    //創建對應的Window 並設置callback, 其實爲PhoneWindow
    mWindow = new PhoneWindow(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    ....
    // 設置Window的WindowManager, 對Window的mWindowManager賦值,
    // 事實上, Window中 並未使用傳遞進去的windowManager, 而是在此方法中 調用WindowManagerImpl.createLocalWindowManager 重新創建了一個
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    if (mParent != null) {
        mWindow.setContainer(mParent.getWindow());
    }
    // 把window對象中的 windowManager 關聯到 Activity的 mWindowManager
    mWindowManager = mWindow.getWindowManager();
    ...
  }

Activity創建之後, 在ActivityThread中 調用 Activity#attach, 進行一些初始化操作,在Activity#attach中, 創建了一個PhoneWindow對象,這個PhoneWindow就是getWindow中得到的window

2, dialog的getWindow 也是獲取該dialog創建時所new 出來的phonewindow窗口, 如果當前activity不可見,則值爲null,所以dialog調用該方法和activity中調用該方法得到的window是不一樣的…不一樣….不一樣

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
    ......
    // 用getSystemService獲取 WindowManger實例
    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    // 直接創建一個 PhoneWindow的實例
    final Window w = new PhoneWindow(mContext);
    mWindow = w;
    w.setCallback(this);
    w.setOnWindowDismissedCallback(this);
    w.setWindowManager(mWindowManager, null, null);
    w.setGravity(Gravity.CENTER);
    mListenersHandler = new ListenersHandler(this);
}

代碼很明顯, 首先獲取windowManager實例, 然後創建window對象,然後在設置callback,對PhoneWindow的實例設置WindowManager;(這裏有一點和Activity不同, Activity是調用Window的setWindowManager後, 把Window對應的WindowManger獲取,然後賦值給自己的變量Activity#mWindowManger, 而dialog沒這個操作; dialog對應的Window對象,就只是傳入的Context實例去getSystemService所得); 這個PhoneWindow就是getWindow中得到的window

所以他們獲取到的window是不一樣的

activity中window的地址爲:com.android.internal.policy.PhoneWindow@595fa83
dialog中window的地址爲:com.android.internal.policy.PhoneWindow@960ec5c

很明顯不一樣

可參考Activity和dialog的窗口添加源碼分析

1, Window是一個抽象類, 具體的實現是PhoneWindow

2,android系統中, 每個界面,對應着一個window; 但其實在android系統中window也是一個抽象的概率,它是以view的形式存在; 在使用中, 無法直接訪問Window, 只能通過WindowManager才能訪問Window; 每個Window都對應一個View和一個ViewRootImpl, ViewRootImpl是連接Window和WMS的橋樑, WMS的一些消息,通過ViewRootImpl轉發給View;

3, WindowManager繼承自ViewManager(間接證明Window其實對應的是View?),常用的只有三個方法:addView、updateView和removeView

4,各種Window的不同, 主要是 token及type的不同

5,app中控制window, 是通過WindowManager.LayoutParams去控制, eg: 通過x,y,gravity去控制位置…

CardView使用

參考資料: CardView的使用

1,基本使用

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"    
    xmlns:cardview="http://schemas.android.com/apk/res-auto"   
    cardview:cardElevation="5dp"   
    cardview:cardCornerRadius="6dp"   
    android:layout_width="match_parent"   
    android:layout_height="match_parent">
</android.support.v7.widget.CardView>

cardview:cardElevation 表示cardView 的陰影的 高度

cardview:cardCornerRadius 表示cardView 的圓角的邊緣弧度數

2,拓展屬性介紹

cardBackgroundColor   : 設置CardView的背景顏色
cardMaxElevation   : 設置最大高度
cardUseCompatPadding :設置內邊距
cardPreventCornerOverlap : 是否添加內邊距,爲了防止卡片內容和邊角的重疊
contentPadding : 設置CardView邊界跟內部的間距
contentPaddingLeft :設置CardView邊界跟內部的左間距
contentPaddingRight:設置CardView邊界跟內部的右間距
contentPaddingTop:設置CardView邊界跟內部的上間距
contentPaddingBottom:設置CardView邊界跟內部的下間距

3,一些問題和一些實現

1,在API21(5.0) 以上,使用起來沒有問題;

2,在API21以下,在CardView 與內部view會有默認的邊距, 圖 , 原因是因爲 在API21以下,爲了防止內容與CardView 重疊, 默認使用cardPreventCornerOverlap =true 使會有默認邊距 ,解決這個問題, 只需要添加代碼 cardPreventCornerOverlap =false 即可;

3,CardView設置不了與屏幕的間距, 只需要在CardView外面再套一層佈局 再設置CardView的margin值即可;

4,CardView繼承於FrameLayout 可以作爲根佈局來使用, 具有FrameLayout的一切特點,但是要注意第三點提到的問題,同時也要注意子View的位置;

5,去除陰影 card_view:cardElevation=”0dp” 即可;

6,設置點擊水波紋效果 android:foreground=”?attr/selectableItemBackground” 但是在5.0以下就沒有效果;

7,實現Material Design 點擊陰影效果 需要藉助5.0的屬性 android:stateListAnimator, 5.0以下沒有效果

創建一個Z軸方向的動畫,設置屬性爲android:stateListAnimator=”@anim/xxx

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="true" android:state_pressed="true">
        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="translationZ"
            android:valueTo="@dimen/touch_raise"
            android:valueType="floatType" />
    </item>
    <item>
        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="translationZ"
            android:valueTo="0dp"
            android:valueType="floatType" />
    </item>
</selector>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章