親ビューのサイズ変更後にカスタムViewGroup
で子ビューの配置中に望ましくない遷移を避けるためにいくつか問題があります。この問題は、setContentView()
の代わりにWindowManager
を使用した場合にのみ存在するようです。ここで簡単な例である:Androidビューのサイズ変更とWindowManager:子ビューの配置中の不要な切り替え
MainActivity
:
public class MainActivity extends AppCompatActivity {
private static final int MY_PERMISSIONS_DRAW_OVER_OTHER_APPS = 1;
CustomViewGroup mCustomViewGroup;
WindowManager mWindowManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, MY_PERMISSIONS_DRAW_OVER_OTHER_APPS);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
if (ContextCompat.checkSelfPermission(this,
android.Manifest.permission.SYSTEM_ALERT_WINDOW)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
android.Manifest.permission.SYSTEM_ALERT_WINDOW)) {
} else {
ActivityCompat.requestPermissions(this,
new String[]{android.Manifest.permission.SYSTEM_ALERT_WINDOW},
MY_PERMISSIONS_DRAW_OVER_OTHER_APPS);
}
}
}
mCustomViewGroup =
(CustomViewGroup) LayoutInflater.from(this).inflate(R.layout.activity_main,null);
final WindowManager.LayoutParams floatingViewLayoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
);
floatingViewLayoutParams.gravity = Gravity.BOTTOM | Gravity.LEFT;
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mWindowManager.addView(mCustomViewGroup,floatingViewLayoutParams);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MY_PERMISSIONS_DRAW_OVER_OTHER_APPS) {
//Check if the permission is granted or not.
if (resultCode == RESULT_OK) {
} else {
Toast.makeText(this,
"Draw over other app permission not available. Closing the application",
Toast.LENGTH_SHORT).show();
finish();
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
CustomViewGroup
:
public class CustomViewGroup extends ViewGroup {
private boolean mIsTouchEventActive;
public CustomViewGroup(Context context) {
this(context,null,0);
}
public CustomViewGroup(Context context, AttributeSet attrs) {
this(context,attrs,0);
}
public CustomViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mIsTouchEventActive = false;
setWillNotDraw(false);
// Add the fab view
LayoutInflater layoutInflater = LayoutInflater.from(context);
View fabView = layoutInflater.inflate(R.layout.fab_view,null,false);
this.addView(fabView);
}
@Override
public boolean shouldDelayChildPressedState() {
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mIsTouchEventActive = true;
requestLayout();
return true;
case MotionEvent.ACTION_UP:
mIsTouchEventActive = false;
requestLayout();
return true;
}
return false;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int maxHeight = 0;
int maxWidth = 0;
int childState = 0;
final View child = getChildAt(0);
if (child.getVisibility() != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
childState = combineMeasuredStates(childState, child.getMeasuredState());
}
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
if (mIsTouchEventActive == true) {
final Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
Point deviceDisplay = new Point();
display.getSize(deviceDisplay);
maxHeight = deviceDisplay.x;
maxWidth = deviceDisplay.y;
}
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
resolveSizeAndState(maxHeight, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final Rect fabChildRect = new Rect();
final View child = getChildAt(0);
if (child.getVisibility() != GONE) {
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
fabChildRect.left = 0;
fabChildRect.right = width;
fabChildRect.top = 0;
fabChildRect.bottom = height;
child.layout(fabChildRect.left, fabChildRect.top,
fabChildRect.right, fabChildRect.bottom);
}
}
}
activity_main.xml
:
<?xml version="1.0" encoding="utf-8"?>
<packagename.CustomViewGroup
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/custom_view_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"/>
fab_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.design.widget.FloatingActionButton
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:srcCompat="@android:drawable/ic_dialog_email"/>
</LinearLayout>
マニフェストファイルはandroid.permission.SYSTEM_ALERT_WINDOW
許可を含まなければならないとbuild.gradle
の私の依存関係のリストは以下の通りです:
を私は継承カスタムビューCustomViewGroup
を持っています。ここでは
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:design:24.2.1'
testCompile 'junit:junit:4.12'
}
は私がやっているものですViewGroup
私の短い例ではFloatingActionButton
があり、親ビューの左下隅に配置されています。 CustomViewGroup
のデフォルトサイズは、FloatingActionButton
:264x264のものです。
ACTION_DOWN
イベントの場合にはCustomViewGroup
のサイズはディスプレイ全体に拡大されるように、私はCustomViewGroup
でonClick
とonMeasure
メソッドを実装しました。 ACTION_UP
イベントの場合、サイズはデフォルト値に戻ります。 CustomViewGroup
内FloatingActionButton
の位置は、親ビューのサイズは、ユーザのタッチした後に変更されたとき、したがってボタン自体は異なる位置に配置され、常に
fabChildRect.left = 0;
fabChildRect.right = width;
fabChildRect.top = 0;
fabChildRect.bottom = height;
width
と
height
が共に264に等しい
あります。
私の質問は、ユーザータッチイベントの場合のアクションボタンの配置中にアニメーションを削除する方法は?私はボタンビューの垂直方向の動きを意味します。私はすでにすべてのトランジションタイプでdisableTransitionType
メソッドを試しましたが、何も変わりません。 xmlファイルのトランジションを無効にしようとした場合と同じです。 CustomViewGroup
ビューは、次のactivity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/activity_main"
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="packagename.MainActivity">
<packagename.CustomViewGroup
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/custom_view_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"/>
</RelativeLayout>
で例えば、XMLから、それを膨らませる代わりにWindowManager
を使用することにより、メインアクティビティビューに追加された場合は、この移行は存在していないあなたが解決する方法上の任意のアドバイスはありますか私の問題と、おそらく私が観察しているものの説明もありますか?おそらく私のコードから推測できるように、私はAndroidプログラミングの初心者なので、このスレッドのトピックに厳密に関連していない一般的なアドバイスは大歓迎です!
ありがとうございます。
UPDATE:私はWindowManager
を使用するViewRootImpl
(ライン5415)、不要な可視変化は、この方法の実行中に行われる内
int relayoutResult = mWindowSession.relayout(
mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,mWinFrame,
mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface);
への呼び出しがあることを見つけました。私がCustomViewGroup
を主なアクティビティのxmlから膨らませると、上記のメソッドはタッチイベントの場合には呼び出されず、この状態でも遷移は見えないので、私はmWindowSession
データメンバーのrelayout
メソッドを考えることができると思いますタイプはIWindowSession
)です。