20

我刚开始玩MotionLayout。我已经定义了一个活动布局MotionLayout,使用它MotionScene来隐藏和显示一个视图。

MotionScene过渡如下所示:

<Transition
    app:constraintSetStart="@id/collapsed"
    app:constraintSetEnd="@id/expanded">

    <OnClick app:target="@id/nextButton"  />

</Transition>

麻烦的是,当我以编程方式将 ClickListener 添加到按钮时,什么也没有发生:

nextButton.setOnClickListener {
        //do some stuff
    }

此侦听器被完全忽略,但每次单击都会触发转换(视图展开/折叠)。我已经看到有人在哪里扩展 MotionLayout来处理点击事件,但似乎有一种更简单的方法可以为按钮添加另一个点击侦听器。

问题 1:有没有办法在 MotionLayout 过渡中将 ClickListener 添加到 OnClick 的目标?

问题 2:有没有办法让转换成为一次性事件? 期望的结果是,如果在单击按钮时视图是折叠的,则视图会展开,但如果它已经展开,则它会保持展开状态。

最后,我使用了命名空间"http://schemas.android.com/apk/res-auto",文档清楚地说明了这一点,target并且mode是 OnClick 的属性。但是当我使用该项目时将无法编译,mode因为在该命名空间中找不到它。

问题 3:我是否使用了正确的命名空间?

4

8 回答 8

13
  1. 不是我能找到的。
  2. 我发现使用带有“transitionToEnd”值的 clickAction 属性取得了成功。这将使运动布局无法返回到 startConstraintSet。
<OnClick
      motion:targetId="@+id/rateUsButton"
      motion:clickAction="transitionToEnd"/>
  1. 这就是我正在使用的命名空间,以及我见过的示例中使用的命名空间。

今天刚遇到同样的问题。我能够通过在我的代码中使用setOnTouchListener而不是拦截点击。setOnClickListener

rateUsButton.setOnTouchListener { _, event ->
    if (event.action == MotionEvent.ACTION_UP) {
        // handle the click
    }
    false
}

我知道这个解决方案不是最好的,但我没有找到其他选择。返回 false 表示此处未处理触摸,因此将由运动布局处理。

于 2019-04-13T16:14:17.797 回答
10

您也可以从一开始就以编程方式处理点击,方法是删除

 <OnClick app:target="@id/nextButton"  />

共。此外,通过检查转换的进度,很容易看到您的视图是否被扩展。所以你可以在你的 java/kotlin 文件中以编程方式处理它

yourButton.setOnClickListener {
    if (yourMotionLayoutId.progress == 0.0)
        yourMotionLayoutId.transitionToEnd
}

这样,它将检查转换是否处于未发生的状态(进度将为 0.0)和转换,否则,它将什么也不做。

于 2019-12-30T22:49:02.760 回答
2

我找到了一种更清洁,更正确的方法,您可以这样做.. OnClick 直接从视图中..

注意:它不适用于:<OnSwipe/><OnClick/>

PD。对不起,我来自墨西哥,我正在使用翻译器

<androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/play_pause_button_collapsed"
        android:layout_width="30dp"
        android:layout_height="50dp"
        app:srcCompat="@drawable/ic_play_arrow_black_48dp"
        android:layout_marginTop="25dp"
        android:elevation="2dp"
        android:alpha="0"

        android:onClick="handleAction"

        tools:ignore="ContentDescription" />



fun handleAction(view: View) { 
   //handle click
}
于 2019-08-15T18:47:34.527 回答
2

我刚刚使用了这个技巧:点击是通过编程方式处理的,但它会触发隐藏视图,在该视图上<OnClick>注册MotionScene

actualVisibleView.setOnClickListener {
            doSomeLogic()
            hiddenView.performClick()
        }

MotionScene

<Transition
        android:id="@+id/hackedTransitionThanksToGoogle"
        motion:constraintSetEnd="@layout/expanded"
        motion:constraintSetStart="@layout/closed"
        motion:duration="300"
        motion:motionInterpolator="linear">

        <OnClick
            motion:clickAction="transitionToEnd"
            motion:targetId="@+id/hiddenView" />
</Transition>
于 2020-10-21T15:02:12.453 回答
1

一般来说,如果您需要回调,您可能希望自己控制动画。因此,如果您要添加 onClick,您应该自己调用转换。

public void onClick(View v) {
   ((MotionLayout)v.getParent()).transitionToEnd());
   // you can decide all the actions and conditionals.
 }

意图是有用的,开发人员并不关心。在连接回调之前隐藏/显示 ui 元素等或进行测试。

于 2020-12-21T21:00:12.537 回答
0

我昨天遇到了这个问题,现在它解决了,我所做的只是在 MotionLayout 标签内添加一个 View 标签。然后给它一个onClick属性。

这是预览

<androidx.constraintlayout.motion.widget.MotionLayout
    android:id="@+id/buttonMotion"
    android:layout_width="70dp"
    android:layout_height="70dp"
    android:layout_gravity="center"
    app:layoutDescription="@xml/circle_to_square">
    <androidx.constraintlayout.utils.widget.ImageFilterView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/puthPic"
        android:scaleType="centerCrop"
        android:src="@drawable/red"
        android:onClick="toggleBroadcasting"
        />
    <View
        android:id="@+id/puthPicView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:onClick="toggleBroadcasting"/>
</androidx.constraintlayout.motion.widget.MotionLayout>

进一步访问我的要点。然后,给它一颗星;)

于 2021-02-18T03:47:33.893 回答
0

这是简单的解决方案:

只需添加这个乐趣:

 @SuppressLint("ClickableViewAccessibility")
fun View.setOnClick(clickEvent: () -> Unit) {
    this.setOnTouchListener { _, event ->
        if (event.action == MotionEvent.ACTION_UP) {
            clickEvent.invoke()
        }
        false
    }
}

这是你如何使用它:

nextButton.setOnClick {
        //Do something 
}
于 2021-02-08T10:59:03.127 回答
0

您可以在转换时将 MotionLayout.TransitionListener 实现到处理程序事件。

public class LoginActivity extends AppCompatActivity implements MotionLayout.TransitionListener {
private static final String TAG = "LoginActivity";
private FirebaseAuth mAuth;
private LoginLayoutBinding binding;

@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = LoginLayoutBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());

    // initialize the FirebaseAuth instance.
    mAuth = FirebaseAuth.getInstance();
    binding.getRoot().addTransitionListener(this);
}


@Override
public void onStart() {
    super.onStart();
    // Check if user is signed in (non-null) and update UI accordingly.
    FirebaseUser currentUser = mAuth.getCurrentUser();
    updateUI(currentUser);
}

private void updateUI(FirebaseUser currentUser) {
    hideProgressBar();
    if (currentUser != null) {
        Intent intent = new Intent(LoginActivity.this, MainActivity.class);
        startActivity(intent);
        finish();
    }
}

private void hideProgressBar() {
    binding.progressBar2.setVisibility(View.GONE);
}

private void createAccount(String email, String password) {
    mAuth.createUserWithEmailAndPassword(email, password)
            .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        // Sign in success, update UI with the signed-in user's information
                        Log.d(TAG, "createUserWithEmail:success");
                        FirebaseUser user = mAuth.getCurrentUser();
                        updateUI(user);
                    } else {
                        // If sign in fails, display a message to the user.
                        Log.w(TAG, "createUserWithEmail:failure", task.getException());
                        Toast.makeText(LoginActivity.this, "Authentication failed.",
                                Toast.LENGTH_SHORT).show();
                        updateUI(null);
                    }
                }
            });
}

private void signIn(String email, String password) {
    mAuth.signInWithEmailAndPassword(email, password)
            .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        // Sign in success, update UI with the signed-in user's information
                        Log.d(TAG, "signInWithEmail:success");
                        FirebaseUser user = mAuth.getCurrentUser();
                        updateUI(user);
                    } else {
                        // If sign in fails, display a message to the user.
                        Log.w(TAG, "signInWithEmail:failure", task.getException());
                        Toast.makeText(LoginActivity.this, "Authentication failed.",
                                Toast.LENGTH_SHORT).show();
                        updateUI(null);
                    }
                }
            });
}


@Override
public void onTransitionStarted(MotionLayout motionLayout, int startId, int endId) {

}

@Override
public void onTransitionChange(MotionLayout motionLayout, int startId, int endId, float progress) {

}

@Override
public void onTransitionCompleted(MotionLayout motionLayout, int currentId) {
    if (currentId==R.id.end){
        binding.btnLogin.setText(R.string.sign_up);
        binding.textView3.setEnabled(false);
        binding.textView2.setEnabled(true);
    }else {
        binding.btnLogin.setText(R.string.login);
        binding.textView2.setEnabled(false);
        binding.textView3.setEnabled(true);
    }

}

@Override
public void onTransitionTrigger(MotionLayout motionLayout, int triggerId, boolean positive, float progress) {

}

}

于 2020-12-18T11:23:37.963 回答