├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── allenliu │ │ └── floatview │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── allenliu │ │ │ └── floatview │ │ │ ├── CallShowReceiver.java │ │ │ └── FloatViewDemoActivity.java │ └── res │ │ ├── layout │ │ ├── activity_float_view_demo.xml │ │ ├── callshow_layout.xml │ │ └── floatview_layotu.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ ├── demo.png │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── allenliu │ └── floatview │ └── ExampleUnitTest.java ├── build.gradle ├── floatview.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── allenliu │ │ └── floatview │ │ └── library │ │ └── FloatView.java │ └── res │ └── values │ └── strings.xml ├── settings.gradle ├── z.gif └── z3.gif /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | FloatView -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FloatView 2 | floatview on windowmanager,and you can be easy to add call show by using it 3 | 4 | 自定义floatview,无需申明悬浮框权限,利用WindowManager TYPE_TOAST实现全站浮动式按钮,重写touch事件实现任意拖动,将view加入windowmanager层,可以使用控件实现类似来电秀的效果。 5 | 6 | ## MIUI使用TYPE_TOAST也会无效,所以MIUI系统中需要在manifest里面注册SYSTEM_ALERT_Winow权限,其他系统可以不用. 7 | 8 | 9 | 10 | 11 | ### 导入: 12 | 13 | `compile 'com.allenliu:floatview:1.0.1'` 14 | 15 | ### 初始化Floatview: 16 | 17 | FloatView(Context context, int x, int y, View childView) 18 | or 19 | FloatView(Context context, int x, int y, int layoutres) 20 | ### 其他方法: 21 | 22 | ``` 23 | updateFloatViewPosition(int x, int y)//更新位置 24 | 25 | setFloatViewClickListener(IFloatViewClick listener)` 26 | 27 | addToWindow()//加入窗口 28 | 29 | setIsAllowTouch(boolean flag)//是否允许拖动 30 | 31 | removeFromWindow()//移除窗口 32 | ``` 33 | 34 | 35 | 由于控件显示在windowmanager上,所以控件显示的生命周期需要自己手动管理,可以在Application或者基层Activity里控制显示和隐藏。 36 | 37 | ### 来电秀 38 | 利用控件也可以显示在来电秀上。 39 | 40 | 由于继承自linearlayout所以可以添加子view,可以初始化时将View或layout传入,也可以手动addview,在监听来电时加入view即可,有兴趣的朋友可以 41 | 参考下源码 42 | 43 | case TelephonyManager.CALL_STATE_RINGING: 44 | if (!viewIsShow) { 45 | viewIsShow = true; 46 | if (floatView == null) 47 | floatView = new FloatView(context, 0, 0, R.layout.callshow_layout); 48 | floatView.addToWindow(); 49 | } 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | 7 | defaultConfig { 8 | applicationId "com.allenliu.floatview" 9 | minSdkVersion 15 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.4.0' 26 | compile project(':library') 27 | } 28 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Eclipse\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/allenliu/floatview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.floatview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/allenliu/floatview/CallShowReceiver.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.floatview; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.telephony.PhoneStateListener; 7 | import android.telephony.TelephonyManager; 8 | import android.util.DisplayMetrics; 9 | import android.view.ViewGroup; 10 | import android.view.WindowManager; 11 | import android.widget.ImageView; 12 | import android.widget.TextView; 13 | 14 | import com.allenliu.floatview.library.FloatView; 15 | 16 | /** 17 | * Created by Allen Liu on 2016/5/25. 18 | */ 19 | public class CallShowReceiver extends BroadcastReceiver { 20 | private String TAG="CALLSHOWRECEIVER"; 21 | private boolean viewIsShow=false; 22 | private FloatView floatView; 23 | private PhoneStateListener phoneStateListener; 24 | @Override 25 | public void onReceive(Context context, Intent intent) { 26 | // if(intent.getAction().equals("com.allenliu.floatview.REGISTER_CALLSHOW")) 27 | initPhoneStateListener(context,intent); 28 | } 29 | private void initPhoneStateListener(final Context context, final Intent intent) { 30 | if(phoneStateListener==null) { 31 | phoneStateListener = new PhoneStateListener() { 32 | @Override 33 | public void onCallStateChanged(int state, String incomingNumber) { 34 | super.onCallStateChanged(state, incomingNumber); 35 | switch (state) { 36 | //挂机或没有电话时的状态 37 | case TelephonyManager.CALL_STATE_IDLE: 38 | if (floatView != null) { 39 | floatView.removeFromWindow(); 40 | viewIsShow = false; 41 | } 42 | break; 43 | //响铃中 44 | case TelephonyManager.CALL_STATE_RINGING: 45 | // Log.v(TAG,"SHOW"); 46 | if (!viewIsShow) { 47 | viewIsShow = true; 48 | if (floatView == null) 49 | floatView = new FloatView(context, 0, 0, R.layout.callshow_layout); 50 | TextView textView = (TextView) floatView.findViewById(R.id.tv_phone); 51 | ImageView imageView = (ImageView) floatView.findViewById(R.id.iv); 52 | ViewGroup.LayoutParams params = imageView.getLayoutParams(); 53 | params.width = getScreenWidth(context); 54 | // params.height=400; 55 | imageView.setLayoutParams(params); 56 | textView.setText(incomingNumber + "来电了"); 57 | 58 | floatView.addToWindow(); 59 | } 60 | break; 61 | //接听电话了 62 | case TelephonyManager.CALL_STATE_OFFHOOK: 63 | if (floatView != null) { 64 | floatView.removeFromWindow(); 65 | viewIsShow = false; 66 | } 67 | break; 68 | } 69 | } 70 | }; 71 | //注册监听, 72 | TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 73 | manager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); 74 | } 75 | } 76 | private int getScreenWidth(Context context) { 77 | WindowManager wm = (WindowManager) context 78 | .getSystemService(Context.WINDOW_SERVICE); 79 | DisplayMetrics outMetrics = new DisplayMetrics(); 80 | wm.getDefaultDisplay().getMetrics(outMetrics); 81 | return outMetrics.widthPixels; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/allenliu/floatview/FloatViewDemoActivity.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.floatview; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.widget.EditText; 9 | import android.widget.Toast; 10 | 11 | import com.allenliu.floatview.library.FloatView; 12 | 13 | public class FloatViewDemoActivity extends AppCompatActivity { 14 | FloatView floatView; 15 | EditText et1; 16 | EditText et2; 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_float_view_demo); 22 | init(); 23 | 24 | 25 | } 26 | 27 | private void init() { 28 | et1 = (EditText) findViewById(R.id.et1); 29 | et2 = (EditText) findViewById(R.id.et2); 30 | 31 | floatView = new FloatView(this, 0, 0, R.layout.floatview_layotu); 32 | floatView.setFloatViewClickListener(new FloatView.IFloatViewClick() { 33 | @Override 34 | public void onFloatViewClick() { 35 | Toast.makeText(FloatViewDemoActivity.this, "floatview is clicked", Toast.LENGTH_SHORT).show(); 36 | 37 | } 38 | }); 39 | } 40 | 41 | public void onClick(View view) { 42 | switch (view.getId()) { 43 | case R.id.btn1: 44 | floatView.removeFromWindow(); 45 | Log.v("SS", "REMOVE"); 46 | break; 47 | case R.id.btn2: 48 | floatView.addToWindow(); 49 | break; 50 | case R.id.btn_update: 51 | int x = Integer.parseInt(et1.getText().toString()); 52 | int y = Integer.parseInt(et2.getText().toString()); 53 | floatView.updateFloatViewPosition(x, y); 54 | break; 55 | case R.id.btn3: 56 | Intent intent = new Intent(); 57 | intent.setAction("com.allenliu.floatview.REGISTER_CALLSHOW"); 58 | sendBroadcast(intent); 59 | break; 60 | } 61 | 62 | } 63 | 64 | @Override 65 | protected void onStart() { 66 | floatView.addToWindow(); 67 | super.onStart(); 68 | } 69 | 70 | @Override 71 | protected void onStop() { 72 | floatView.removeFromWindow(); 73 | super.onStop(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_float_view_demo.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 |