Extract expandable viewholder

This commit is contained in:
topjohnwu 2017-06-20 17:55:33 +08:00
parent 28649c07e3
commit dd3b716d85
3 changed files with 107 additions and 143 deletions

View File

@ -16,6 +16,7 @@ import android.widget.TextView;
import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.AlertDialogBuilder; import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.ExpandableViewHolder;
import com.topjohnwu.magisk.components.SnackbarMaker; import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.database.SuDatabaseHelper; import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.superuser.Policy; import com.topjohnwu.magisk.superuser.Policy;
@ -122,11 +123,10 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
return policyList.size(); return policyList.size();
} }
static class ViewHolder extends RecyclerView.ViewHolder { static class ViewHolder extends ExpandableViewHolder {
@BindView(R.id.app_name) TextView appName; @BindView(R.id.app_name) TextView appName;
@BindView(R.id.package_name) TextView packageName; @BindView(R.id.package_name) TextView packageName;
@BindView(R.id.expand_layout) LinearLayout expandLayout;
@BindView(R.id.app_icon) ImageView appIcon; @BindView(R.id.app_icon) ImageView appIcon;
@BindView(R.id.master_switch) Switch masterSwitch; @BindView(R.id.master_switch) Switch masterSwitch;
@BindView(R.id.notification_switch) Switch notificationSwitch; @BindView(R.id.notification_switch) Switch notificationSwitch;
@ -135,83 +135,14 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
@BindView(R.id.delete) ImageView delete; @BindView(R.id.delete) ImageView delete;
@BindView(R.id.more_info) ImageView moreInfo; @BindView(R.id.more_info) ImageView moreInfo;
private ValueAnimator mAnimator; public ViewHolder(View itemView) {
private boolean mExpanded = false;
private static int expandHeight = 0;
ViewHolder(View itemView) {
super(itemView); super(itemView);
ButterKnife.bind(this, itemView); ButterKnife.bind(this, itemView);
expandLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (expandHeight == 0) {
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
expandLayout.measure(widthSpec, heightSpec);
expandHeight = expandLayout.getMeasuredHeight();
}
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
expandLayout.setVisibility(View.GONE);
mAnimator = slideAnimator(0, expandHeight);
return true;
}
});
}
private void setExpanded(boolean expanded) {
mExpanded = expanded;
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = expanded ? expandHeight : 0;
expandLayout.setLayoutParams(layoutParams);
expandLayout.setVisibility(expanded ? View.VISIBLE : View.GONE);
}
private void expand() {
expandLayout.setVisibility(View.VISIBLE);
mAnimator.start();
mExpanded = true;
}
private void collapse() {
if (!mExpanded) return;
int finalHeight = expandLayout.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationEnd(Animator animator) {
expandLayout.setVisibility(View.GONE);
} }
@Override @Override
public void onAnimationStart(Animator animator) {} public void setExpandLayout(View itemView) {
expandLayout = itemView.findViewById(R.id.expand_layout);
@Override }
public void onAnimationCancel(Animator animator) {}
@Override
public void onAnimationRepeat(Animator animator) {}
});
mAnimator.start();
mExpanded = false;
}
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator -> {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = value;
expandLayout.setLayoutParams(layoutParams);
});
return animator;
}
} }
} }

View File

@ -1,17 +1,13 @@
package com.topjohnwu.magisk.adapters; package com.topjohnwu.magisk.adapters;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context; import android.content.Context;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.view.animation.RotateAnimation; import android.view.animation.RotateAnimation;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.thoughtbot.expandablerecyclerview.ExpandableRecyclerViewAdapter; import com.thoughtbot.expandablerecyclerview.ExpandableRecyclerViewAdapter;
@ -19,6 +15,7 @@ import com.thoughtbot.expandablerecyclerview.models.ExpandableGroup;
import com.thoughtbot.expandablerecyclerview.viewholders.ChildViewHolder; import com.thoughtbot.expandablerecyclerview.viewholders.ChildViewHolder;
import com.thoughtbot.expandablerecyclerview.viewholders.GroupViewHolder; import com.thoughtbot.expandablerecyclerview.viewholders.GroupViewHolder;
import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.ExpandableViewHolder;
import com.topjohnwu.magisk.superuser.SuLogEntry; import com.topjohnwu.magisk.superuser.SuLogEntry;
import java.util.ArrayList; import java.util.ArrayList;
@ -90,7 +87,7 @@ public class SuLogAdapter {
SuLogEntry logEntry = (SuLogEntry) group.getItems().get(childIndex); SuLogEntry logEntry = (SuLogEntry) group.getItems().get(childIndex);
holder.setExpanded(expandList.contains(logEntry)); holder.setExpanded(expandList.contains(logEntry));
holder.itemView.setOnClickListener(view -> { holder.itemView.setOnClickListener(view -> {
if (holder.mExpanded) { if (holder.getExpanded()) {
holder.collapse(); holder.collapse();
expandList.remove(logEntry); expandList.remove(logEntry);
} else { } else {
@ -150,92 +147,50 @@ public class SuLogAdapter {
} }
} }
// Wrapper class
static class LogViewHolder extends ChildViewHolder { static class LogViewHolder extends ChildViewHolder {
private InternalViewHolder expandableViewHolder;
@BindView(R.id.app_name) TextView appName; @BindView(R.id.app_name) TextView appName;
@BindView(R.id.action) TextView action; @BindView(R.id.action) TextView action;
@BindView(R.id.time) TextView time; @BindView(R.id.time) TextView time;
@BindView(R.id.fromPid) TextView fromPid; @BindView(R.id.fromPid) TextView fromPid;
@BindView(R.id.toUid) TextView toUid; @BindView(R.id.toUid) TextView toUid;
@BindView(R.id.command) TextView command; @BindView(R.id.command) TextView command;
@BindView(R.id.expand_layout) LinearLayout expandLayout;
private ValueAnimator mAnimator; LogViewHolder(View itemView) {
private boolean mExpanded = false;
private static int expandHeight = 0;
public LogViewHolder(View itemView) {
super(itemView); super(itemView);
ButterKnife.bind(this, itemView); ButterKnife.bind(this, itemView);
expandLayout.getViewTreeObserver().addOnPreDrawListener( expandableViewHolder = new InternalViewHolder(itemView);
new ViewTreeObserver.OnPreDrawListener() { }
private class InternalViewHolder extends ExpandableViewHolder {
InternalViewHolder(View itemView) {
super(itemView);
}
@Override @Override
public boolean onPreDraw() { public void setExpandLayout(View itemView) {
if (expandHeight == 0) { expandLayout = itemView.findViewById(R.id.expand_layout);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); }
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
expandLayout.measure(widthSpec, heightSpec);
expandHeight = expandLayout.getMeasuredHeight();
} }
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this); private boolean getExpanded() {
expandLayout.setVisibility(View.GONE); return expandableViewHolder.mExpanded;
mAnimator = slideAnimator(0, expandHeight);
return true;
}
});
} }
private void setExpanded(boolean expanded) { private void setExpanded(boolean expanded) {
mExpanded = expanded; expandableViewHolder.setExpanded(expanded);
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = expanded ? expandHeight : 0;
expandLayout.setLayoutParams(layoutParams);
expandLayout.setVisibility(expanded ? View.VISIBLE : View.GONE);
} }
private void expand() { private void expand() {
expandLayout.setVisibility(View.VISIBLE); expandableViewHolder.expand();
mAnimator.start();
mExpanded = true;
} }
private void collapse() { private void collapse() {
if (!mExpanded) return; expandableViewHolder.collapse();
int finalHeight = expandLayout.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationEnd(Animator animator) {
expandLayout.setVisibility(View.GONE);
}
@Override
public void onAnimationStart(Animator animator) {}
@Override
public void onAnimationCancel(Animator animator) {}
@Override
public void onAnimationRepeat(Animator animator) {}
});
mAnimator.start();
mExpanded = false;
}
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator -> {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = value;
expandLayout.setLayoutParams(layoutParams);
});
return animator;
} }
} }

View File

@ -0,0 +1,78 @@
package com.topjohnwu.magisk.components;
import android.animation.ValueAnimator;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
public abstract class ExpandableViewHolder extends RecyclerView.ViewHolder {
protected ViewGroup expandLayout;
private ValueAnimator expandAnimator, collapseAnimator;
private static int expandHeight = 0;
public boolean mExpanded = false;
public ExpandableViewHolder(View itemView) {
super(itemView);
setExpandLayout(itemView);
expandLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (expandHeight == 0) {
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
expandLayout.measure(widthSpec, heightSpec);
expandHeight = expandLayout.getMeasuredHeight();
}
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
expandLayout.setVisibility(View.GONE);
expandAnimator = slideAnimator(0, expandHeight);
collapseAnimator = slideAnimator(expandHeight, 0);
return true;
}
});
}
public void setExpanded(boolean expanded) {
mExpanded = expanded;
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = expanded ? expandHeight : 0;
expandLayout.setLayoutParams(layoutParams);
expandLayout.setVisibility(expanded ? View.VISIBLE : View.GONE);
}
public void expand() {
if (mExpanded) return;
expandLayout.setVisibility(View.VISIBLE);
expandAnimator.start();
mExpanded = true;
}
public void collapse() {
if (!mExpanded) return;
collapseAnimator.start();
mExpanded = false;
}
public abstract void setExpandLayout(View itemView);
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator -> {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = value;
expandLayout.setLayoutParams(layoutParams);
});
return animator;
}
}