MotionLayout:MotionScene OnClick会覆盖setOnClickListener

时间:2019-04-10 02:19:10

标签: android android-motionlayout

我刚刚开始玩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
    }

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

问题1:在MotionLayout过渡中,是否可以将ClickListener添加到OnClick的目标?

问题2:是否有一种方法可以使过渡成为一次性事件? 理想的结果是,如果在单击按钮时折叠了视图,则视图会扩展,但是如果它已经扩展,则它将保持扩展状态。

最后,我正在使用命名空间"http://schemas.android.com/apk/res-auto"和文档clearly指出targetmode是OnClick的属性。但是,当我使用mode时,该项目将无法编译,因为在该命名空间中找不到该项目。

问题3:我使用的是正确的名称空间吗?

8 个答案:

答案 0 :(得分:1)

我找到了一种更清洁,更正确的方法,您可以执行此操作....直接从视图中点击..

注意:它不适用于:<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
}

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:0)

  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表示此处未处理触摸,因此将由运动布局处理。

答案 3 :(得分:0)

您也可以从头开始以编程方式通过删除来处理点击

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

一共。通过检查过渡进度,很容易查看是否扩展了视图。因此,您可以使用

在Java / kotlin文件中以编程方式处理它
yourButton.setOnClickListener {
    if (yourMotionLayoutId.progress == 0.0)
        yourMotionLayoutId.transitionToEnd
}

这样,它将检查过渡是否处于未发生的状态(进度为0.0)并进行过渡,否则将不执行任何操作。

答案 4 :(得分:0)

我刚刚使用了这个技巧:单击是通过程序处理的,但是会触发隐藏的视图,在<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>

答案 5 :(得分: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) {

}

}

答案 6 :(得分:0)

这是一个简单的解决方案:

只需添加这个乐趣:

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

这是你如何使用它:

nextButton.setOnClick {
        //Do something 
}

答案 7 :(得分: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>

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