我刚刚开始玩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指出target
和mode
是OnClick的属性。但是,当我使用mode
时,该项目将无法编译,因为在该命名空间中找不到该项目。
问题3:我使用的是正确的名称空间吗?
答案 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)
<OnClick
motion:targetId="@+id/rateUsButton"
motion:clickAction="transitionToEnd"/>
今天遇到了同样的问题。通过在代码中使用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。 然后,给它一颗星;)