1. 程式人生 > >Android Studio:增加蒙板/浮層特效

Android Studio:增加蒙板/浮層特效

寫在前面的話:每一個例項的程式碼都會附上相應的程式碼片或者圖片,保證程式碼完整展示在部落格中。最重要的是保證例程的完整性!!!方便自己也方便他人~歡迎大家交流討論~

接下來要在自定義相機上新增取景框,即中間掏空旁邊半透明的浮層/蒙板。我一開始搜尋的是“蒙板”,找到的基本是新手指引介面的做法,就是一進某個頁面就出現半透明蒙板告訴你應用哪裡內容有更新,點選檢視更新,另外點選螢幕任意處蒙板消失。我覺得這和我所要達到的結果是相類似的,只要把點選事件從任意螢幕處改為拍照按鈕即可。於是我決定先做一個蒙板,最後再和自定義相機的程式碼結合起來,不過還會有修改,下一篇中我會講到結合的過程。這一篇先講怎麼做蒙板,另外此篇蒙板程式碼是可以直接用作新手指引浮層的,再根據自己的需求修修改改就好。如果關心怎麼達到取景框效果的可以直接看下一篇了……(好的!下一篇我會盡快寫出來)

新建專案和檔案

新建名為的專案,檔名我直接截圖出來了,有畫重點哦,不然每次複製貼上手打實在是太麻煩了orz……
這裡寫圖片描述

values資料夾

themetranslucency.xml

這裡編輯了自定義view的style

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="ThemeOfTranslucency" parent="@android:style/Theme.Translucent.NoTitleBar">
        <item
name="android:windowAnimationStyle">@style/Animation</item> </style> <style name="Animation"> <item name="android:activityOpenEnterAnimation">@null</item> <item name="android:activityOpenExitAnimation">@null</item> <item name
="android:activityCloseEnterAnimation">@null</item> <item name="android:activityCloseExitAnimation">@null</item> <item name="android:taskOpenEnterAnimation">@null</item> <item name="android:taskOpenExitAnimation">@null</item> <item name="android:taskCloseEnterAnimation">@null</item> <item name="android:taskCloseExitAnimation">@null</item> <item name="android:taskToFrontEnterAnimation">@null</item> <item name="android:taskToFrontExitAnimation">@null</item> <item name="android:taskToBackEnterAnimation">@null</item> <item name="android:taskToBackExitAnimation">@null</item> </style> </resources>

layout資料夾

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    >

    <Button
        android:id="@+id/button1"
        android:gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="開始拍照"/>

</android.support.constraint.ConstraintLayout>

這裡寫圖片描述

activity_second.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true">
    </FrameLayout>

    <android.support.v7.widget.AppCompatButton
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/button3" />
</RelativeLayout>

這裡寫圖片描述
這裡還要放一下Button的圖,因為我不會用PS把原來方的圖弄成圓的,所以用PPT的神操作弄了個醜醜的,還有白色邊框……orz
這裡寫圖片描述

translucencyview.xml

這是自定義view,到時會通過編寫java檔案對這個view進行繪圖操作

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clickable="true"
    android:id="@+id/translucencyview">

</RelativeLayout>

manifests

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.administrator.translucency">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".MainActivity"/>
        <activity android:name=".TranslucencyActivity" android:theme="@style/ThemeOfTranslucency"/>
    </application>
</manifest>

Java檔案

MainActivity.java

package com.example.administrator.translucency;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button1=findViewById(R.id.button1);
        //點選監聽事件,點選Button1跳轉到帶有蒙版的第二個介面
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);
            }
        });
    }
}

SecondActivity.java

package com.example.administrator.translucency;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatButton;
import butterknife.BindView;
import butterknife.ButterKnife;

public class SecondActivity extends AppCompatActivity {
    private static final String TAG = "SecondActivity";
    @BindView(R.id.button2)
    AppCompatButton mBtCapture;
    private int mHeight;

    @Override
    protected void onCreate( Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        ButterKnife.bind(this);
        showMask();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
    }
    //onCreat中直接去測量view的大小是測不出來的 所以在這個demo中我延時500ms去測量
    //實際使用一般在網路載入完成後去測量view的大小然後去顯示蒙版
    private void showMask() {
        mBtCapture.postDelayed(new Runnable() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mHeight = getSupportActionBar().getHeight();
                        int left = mBtCapture.getLeft();
                        int right = mBtCapture.getRight();
                        int top = mBtCapture.getTop() + mHeight;
                        int bottom = mBtCapture.getBottom() + mHeight;
                        int mCoodinate[] = {left, top, right, bottom};
                        Intent intent = new Intent(SecondActivity.this, TranslucencyActivity.class);
                        intent.putExtra("Location", mCoodinate);
                        startActivity(intent);
                    }
                });
            }
        }, 500);
    }
}

注意:這裡有一個import butterknife.BindView;
import butterknife.ButterKnife;
不是安卓原來有的庫,要自己新增,新增方式如下
這裡寫圖片描述
然後點選右上方紅色圓圈圖示處,重新build一下
這裡寫圖片描述
文後附Butter Knife的官方文件地址和翻譯部落格。

TranslucencyActivity.java

package com.example.administrator.translucency;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.RelativeLayout;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class TranslucencyActivity extends Activity {
    private static final String TAG = "TranslucencyActivity";
    private  int[] mCoodinate;//定義一個放按鈕座標的陣列
    @BindView(R.id.translucencyview)
    RelativeLayout mtranslucencyview;
    @Override
    protected void onCreate( Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);//蒙板Activity不需要標題,所以去取消標題
        setContentView(R.layout.translucencyview);//蒙板介面
        Intent intent=getIntent();//從SecondActivity來的信使,信使攜帶座標資訊
        mCoodinate=intent.getIntArrayExtra("Location");//根據鍵key="Location"取得座標
        ButterKnife.bind(this);
        initView();

    }
    private void initView(){
        TranslucencyView translucencyView=new TranslucencyView(this); //新建一個自定義view物件,該物件構造蒙板
        translucencyView.setCircleLocation(mCoodinate);//設定座標自定義的蒙板view座標
        RelativeLayout.LayoutParams layoutParams=new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);//該layout專門用於展示蒙板,此處得到RelativeLayout引數
        mtranslucencyview.addView(translucencyView,layoutParams);//使自定義蒙板View匹配RelativeLayout
    }

   @OnClick(R.id.translucencyview)
   public void clickClose(){
       finish();
       overridePendingTransition(0, 0);
   }
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode==KeyEvent.KEYCODE_BACK){
            finish();
            overridePendingTransition(0, 0);
            return true; }
        return super.onKeyDown(keyCode, event);
    }
}

TranslucencyView.java

package com.example.administrator.translucency;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PathEffect;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.FrameLayout;

public class TranslucencyView extends FrameLayout {

    private  final Context mContext;
    private int[] mCircleLocation;//宣告存放座標的陣列

    public TranslucencyView(Context context){this(context,null);}
    public TranslucencyView(Context context, AttributeSet attributeSet){this(context,attributeSet,0);}
    public TranslucencyView(Context context,AttributeSet attributeSet,int defStyleAttr){
            super(context,attributeSet,defStyleAttr);
            this.mContext=context;
            initView();
        }
        private void initView(){setBackgroundColor(Color.parseColor("#7f000000"));}//設定半透明底色
        public void setCircleLocation(int[] location){
            this.mCircleLocation=location;
            invalidate();
        }

        @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if(mCircleLocation!=null){
        //掏空一個圓形
        Paint paintarc=new Paint(Paint.ANTI_ALIAS_FLAG);
        PorterDuffXfermode porterDuffXfermode=new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
        paintarc.setXfermode(porterDuffXfermode);
        paintarc.setAntiAlias(true);
        RectF rectF=new RectF(mCircleLocation[0],mCircleLocation[1],mCircleLocation[2],mCircleLocation[3]);
        canvas.drawArc(rectF,0,360,true,paintarc);
        //畫虛線
        Paint paintdashed=new Paint(Paint.ANTI_ALIAS_FLAG);
        paintdashed.setStyle(Paint.Style.STROKE);
        paintdashed.setColor(Color.WHITE);
        paintdashed.setStrokeWidth(5);
        PathEffect pathEffect=new DashPathEffect(new float[]{10,10},0);
        paintdashed.setPathEffect(pathEffect);
        canvas.drawArc(rectF,0,360,true,paintdashed);
        //畫矩形框
        Paint paintrect=new Paint(Paint.ANTI_ALIAS_FLAG);
        PorterDuffXfermode porterDuffXfermode1=new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
        paintrect.setXfermode(porterDuffXfermode1);
        paintrect.setAntiAlias(true);
        paintdashed.setStrokeWidth(5);
        canvas.drawRect(200, 400, 900, 1300, paintrect);
    }
}
}

執行結果:
這裡寫圖片描述