Android Studio:增加蒙板/浮層特效
阿新 • • 發佈:2019-01-05
寫在前面的話:每一個例項的程式碼都會附上相應的程式碼片或者圖片,保證程式碼完整展示在部落格中。最重要的是保證例程的完整性!!!方便自己也方便他人~歡迎大家交流討論~
接下來要在自定義相機上新增取景框,即中間掏空旁邊半透明的浮層/蒙板。我一開始搜尋的是“蒙板”,找到的基本是新手指引介面的做法,就是一進某個頁面就出現半透明蒙板告訴你應用哪裡內容有更新,點選檢視更新,另外點選螢幕任意處蒙板消失。我覺得這和我所要達到的結果是相類似的,只要把點選事件從任意螢幕處改為拍照按鈕即可。於是我決定先做一個蒙板,最後再和自定義相機的程式碼結合起來,不過還會有修改,下一篇中我會講到結合的過程。這一篇先講怎麼做蒙板,另外此篇蒙板程式碼是可以直接用作新手指引浮層的,再根據自己的需求修修改改就好。如果關心怎麼達到取景框效果的可以直接看下一篇了……(好的!下一篇我會盡快寫出來)
新建專案和檔案
新建名為的專案,檔名我直接截圖出來了,有畫重點哦,不然每次複製貼上手打實在是太麻煩了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);
}
}
}
執行結果: