Android development
A few ways to avoid a splash screen when switching themes
While there is no change in the activity’s setTheme, there is a need to call the activity’s setTheme (see “setTheme”) to make the activity’s setTheme (see “setTheme”) functional. There is a flash screen after the activity calls the Concrete method
The topic of this article today is how to avoid the setTheme that calls the concept flash screen after switching the theme. The article on how to change the theme by changing the theme can be read if you haven’t already or do a search for it
recreate |
---|
Effect of implementation
1. Property animation implementation
Use the property animation in conjunction with the ArgbEvaluator class to animate gradients for all views that need to change colors
Attribute animation |
---|
The disadvantages of this approach are as follows:
- Any View that needs to have a color change you’re going to have to set the ID and get its object by findViewById, and you’re going to have to add a lot of code to it, and you know how painful it is to set the ID to findViewById.
- Each attR color setting requires a property animation, which increases the amount of code
- RecyclerView or ListView and how to change the color of some special controls (such as MD-style Button, RadioButton Switch and other controls that cannot change the color by setting background)
So let’s see how we do that in code
Get the attrs color set in the theme using the following method
/ * * * @paramTheme Requires the theme * of the attrs color @paramId Id of the ATTRs color to be obtained @return color
*/
public static int getColorFromTheme(Resources.Theme theme, @AttrRes int id)
{
TypedValue typedValue = new TypedValue();
theme.resolveAttribute(id, typedValue, true);
return typedValue.data;
}Copy the code
All we need to do is get the current color and the changed Theme color and use getTheme in the activity to get the Theme object
int startColorPrimary = ThemeUtil.getColorFromTheme(getTheme()R.attr.colorPrimary);
setTheme(R.style.NightTheme);
int endColorPrimary = ThemeUtil.getColorFromTheme(getTheme(),R.attr.colorPrimary);Copy the code
The next step is to set up a property animation with ArgbEvaluator for color gradient
ValueAnimator animator = ValueAnimator
.ofObject(new ArgbEvaluator(),
startColorPrimary, endColorPrimary)
.setDuration(300);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int color = (int) animation.getAnimatedValue();
// Set the background color control (Toolbar, background Layout, etc.)
mView.setBackgroundColor(color);
//TextView font color
mTextView.setTextColor(color);
/ / ImageView Tint
mImageView.setColorFilter(color);
// Set the status bar or navigation bar color (API>=21)getWindow().setStatusBarColor(color); getWindow().setNavigationBarColor(color); }}); animator.start();Copy the code
The switching effect is achieved by manipulating all the controls that need to change colors
The following is about RecyclerView and MD style Button RadioButton Switch more color change method (which RadioButton Switch implementation is not perfect if you know welcome to add)
Change the color of the Item currently displayed on the screen by obtaining RecyclerView
int childCount = mRecyclerView.getChildCount();
for (int childIndex = 0; childIndex < childCount; childIndex++) {
ViewGroup childView = (ViewGroup) mRecyclerView.getChildAt(childIndex);
// childView is the outermost view of each item in RecyclerView
// We can get the control of each item by id
View mView = childView.findViewById(R.id.item_view);
// Set the property animation to change the color of the view
....
}Copy the code
Void RecyclerView cache Pool Item The idea here is to get the RecycleBin object in the AbsListView class by reflection and then use reflection again to call the Clear method which picks up the night mode implementation of the zhizhihouji and Simple book
Class<RecyclerView> recyclerViewClass = RecyclerView.class;
try {
Field declaredField = recyclerViewClass.getDeclaredField("mRecycler");
declaredField.setAccessible(true);
Method declaredMethod = Class.forName(RecyclerView.Recycler.class.getName()).getDeclaredMethod("clear", (Class<? >[]) new Class[0]);
declaredMethod.setAccessible(true);
declaredMethod.invoke(declaredField.get(mRecyclerView), new Object[0]);
RecyclerView.RecycledViewPool recycledViewPool = mRecyclerView.getRecycledViewPool(a);
recycledViewPool.clear(a);
} catch (Exception e) {
e.printStackTrace(a);
}Copy the code
Button RadioButton Switch Progressbar changes its color by setting Tint
//Switch(not perfect, will change the color of thumb to grey when not selected)
mSwitch.setThumbTintList(ColorStateList.valueOf(color));
//RadioButton(not perfect, will change the color of the unselected circle to grey by default)
CompoundButtonCompat.setButtonTintList(mRadioButton, ColorStateList.valueOf(color));
//Button Progressbar
ViewCompat.setBackgroundTintList(mBotton, ColorStateList.valueOf(color));Copy the code
The disadvantages of animated properties are obvious, the more complex the layout is, the more difficult it is to write and the amount of code, the final effect is not very perfect, the difficulty is how to change the color of the special control, here interested readers can study, the following is a simpler way
2. StartActivity implementation
This approach is similar to the concept of calling Concrete in that flashscreens can be avoided by creating an identical activity and adding an animation
startActivity |
---|
The difficulty with this method is:
- How do I restore the state of the previous activity so that the user does not notice the change in the control
So here’s the code
Create a new same activity and set the fade in and out animation to end the current activity
startActivity(new Intent(this, MainActivity.class));
overridePendingTransition(R.anim.start_anim, R.anim.out_anim);
finish();Copy the code
So you start the intent that you create for the activity to pass data from the old interface like EditText input and RecyclerView data and slide distance
Here is a list of save RecyclerView sliding distance specific need to save data need to be written according to the content of the interface
// Get the sliding distance of RecyclerView
// Call getScrollY to get the data 0, also can listen to the slide event to save the slide distance
private int getScrollYDistance() {
LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
int position = layoutManager.findFirstVisibleItemPosition();
View firstVisibleChildView = layoutManager.findViewByPosition(position);
int itemHeight = firstVisibleChildView.getHeight();
return (position) * itemHeight - firstVisibleChildView.getTop();
}
// Pass data to a new activity with an intent
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("scrollY",getcrollYDistance());
Restore the data in the activity's onCreate method
// The RecyclerView setScrollBy method can only take effect after the view is measured
mRecyclerView.post(new Runnable() {
@Override
public void run() {
mRecyclerView.scrollBy(0,getIntent().getIntExtra("scrollY".0)); }});Copy the code
The difficulty is how to transfer and save the list data in the network request. Passing too much data in the intent can cause a crash because it is a new activity created, and the result is perfect
conclusion
This is my first time to write a technical summary, there must be a lot of problems, I hope the friends need to be able to learn from the kind of new knowledge, finally attached to the Demo link github.com/Misutesu/Ni… (There seems to be something wrong with the selected status of RadioButton in this Demo when selecting switching mode. I haven’t found the reason yet. If you find it, please leave a message and tell me.)