当前位置:网站首页>A blog allows you to understand the use of material design
A blog allows you to understand the use of material design
2022-06-23 01:13:00 【Lao Ma's programming journey】
Material Design Basic concepts of
Material Design yes Google Design of a set of visual language , Combine the priority classical design principles with scientific and technological innovation , Provide a set of visual and interactive design specifications for developers . Mobile device is the basic object of this design language , Let users work on different platforms 、 Consistent experience on devices of different sizes . Material Design Emphasize immediate feedback on interactions , That is, the user's touch and other behaviors app Need to give an immediate response . meanwhile Material Design The application is required to bring a sense to the user , Let users immerse themselves in the current application when using . for example Google The immersive status bar is given “ Tools ”, Hope to change StatusBar and NavigationBar To give users a stronger sense of integration , Focus on the content provided by the application itself . Google From animation 、 Color 、 style 、 Touch feedback 、 Layout, etc Material Design Design requirements . Whether it is a single control or graphic layout ,Google Have given clear design instructions , Interested students can go to the official link mentioned above to learn more .
RecyclerView Use
Write entry layout :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>Write Adapter And its internal classes are customized ViewHolder:
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.MyViewHolder> {
private List<String> mDatas;
private Context mContext;
public MyRecyclerViewAdapter(Context context, List<String> datas) {
mContext = context;
mDatas = datas;
}
// Customize ViewHolder
class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv_item;
MyViewHolder(View itemView) {
super(itemView);
tv_item = (TextView) itemView.findViewById(R.id.tv_item);
}
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// establish ViewHolder
View itemView = View.inflate(parent.getContext(), R.layout.item_list, null);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
// Data binding
holder.tv_item.setText(mDatas.get(position));
// Set Click to listen
holder.tv_item.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, mDatas.get(position), Toast.LENGTH_SHORT).show();
}
});
}
@Override
public int getItemCount() {
// Dataset size
return mDatas.size();
}
}stay Activity The use of , By setting up different LayoutManager You can achieve different layout effects :
public class MDRecyclerViewActivity extends AppCompatActivity {
private RecyclerView rv_list;
private MyRecyclerViewAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_md_recyclerview);
rv_list = (RecyclerView) findViewById(R.id.rv_list);
List<String> datas = new ArrayList<>();
for (int i = 0; i < 100; i++) {
datas.add(" The first " + i + " Data ");
}
mAdapter = new MyRecyclerViewAdapter(this, datas);
// Vertical linearity , Do not reverse the layout
// rv_list.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
// Table layout
// rv_list.setLayoutManager(new GridLayoutManager(this, 3));
// Waterfall flow layout
rv_list.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL));
rv_list.setAdapter(mAdapter);
}
}Inflate What to pay attention to when :
stay Adapter Medium onCreateViewHolder, need Inflate Layout file , There are three ways of writing :
View itemView = View.inflate(parent.getContext(), R.layout.item_list, null);
View itemView = View.inflate(parent.getContext(), R.layout.item_list, parent);
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false);Generally speaking, there is no problem with the writing , But when we were onBindViewHolder In the layout TextView Of LayoutParams When , It is possible to return null . Writing 2 is direct Crash, because ItemView The layout already has a Parent 了 (Inflate When the time is right ItemView Add to Recycleview 了 ), You cannot add another Parent(Recycleview Add again ItemView). Three is one 、 Two compatible schemes of II , Recommend this style of writing .
Add / delete interface stay Adapter Interfaces added and deleted in :
// Addition and deletion of entries
public void addItem(String data, int position) {
mDatas.add(position, data);
notifyItemInserted(position);
}
public void removeItem(int position) {
mDatas.remove(position);
notifyItemRemoved(position);
}Note if you want to use RecyclerView Add / delete animation provided , Then you need to use the new notify Method .
Add an entry and click listen Customize a click callback interface :
// Click on the entry
ItemClickListener mItemClickListener;
public interface ItemClickListener {
void onclick(int position, String data);
}
public void setItemClickListener(ItemClickListener listener) {
mItemClickListener = listener;
}
public abstract class ItemClickListenerPosition implements View.OnClickListener {
private int mPosition;
public ItemClickListenerPosition(int position) {
mPosition = position;
}
public int getPosition() {
return mPosition;
}
}ItemClickListenerPosition Is a custom OnClickListener, The purpose is to make Position And listening , It also uses getLayoutPosition Method . Prevents clicking Position Confused questions .
(onBindViewHolder() Method position It's not real-time , For example, after we delete the element ,item Of position It hasn't changed .)
And then in onBindViewHolder Listen inside :
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
// Data binding
// Set entry listening
holder.itemView.setOnClickListener(new ItemClickListenerPosition(holder.getLayoutPosition()) {
@Override
public void onClick(View v) {
if (mItemClickListener != null) {
mItemClickListener.onclick(getPosition(), mDatas.get(getPosition()));
}
}
});
}Want to learn more RecyclerView Use , Please refer to 《 A blog understands Recyclerview Use 》
DrawerLayout+NavigationView
Use DrawerLayout Achieve sideslip : Define a layout :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#D197F2"
app:title=" I'm the title "
app:titleTextColor="#fff"/>
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=" Content "/>
</LinearLayout>
<LinearLayout
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@android:color/holo_blue_light"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=" Sideslip menu 1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=" Sideslip menu 2"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=" Sideslip menu 3"/>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
</LinearLayout>The layout sideslip menu includes the menu section and the content section , use DrawerLayout Come and wrap it up . among , The root layout of the menu section needs to be added android:layout_gravity=”start”, If it is right sliding , Change it to end that will do .
In this way, a basic side sliding effect can be achieved .
DrawerLayout Is actually realized through ViewDragHelper To achieve ,DrawerLayout The relevant code of the constructor is as follows :
public DrawerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mLeftCallback = new ViewDragCallback(Gravity.LEFT);
mRightCallback = new ViewDragCallback(Gravity.RIGHT);
mLeftDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mLeftCallback);
mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
mLeftDragger.setMinVelocity(minVel);
mLeftCallback.setDragger(mLeftDragger);
}utilize DrawerLayout Some effects can be achieved by monitoring for example , When we can achieve sideslip ,Toolbar The button in the upper left corner changes in real time , We can add a listener ActionBarDrawerToggle:
toolbar = (Toolbar) findViewById(R.id.toolbar);
drawer = (DrawerLayout) findViewById(R.id.drawer);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.drawer_open, R.string.drawer_close);
toggle.syncState();
drawer.addDrawerListener(toggle);Analyze the implementation principle : among ,ActionBarDrawerToggle Realized DrawerLayout.DrawerListener. And in the process of sliding Refresh the... In the upper left corner Drawerable:
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
setPosition(Math.min(1f, Math.max(0, slideOffset)));
}setPosition The implementation is as follows :
private void setPosition(float position) {
if (position == 1f) {
mSlider.setVerticalMirror(true);
} else if (position == 0f) {
mSlider.setVerticalMirror(false);
}
mSlider.setProgress(position);
}In fact, it changes constantly in the process of sliding mSlider( A custom Drawerable object ) Of Progress, So as to constantly refresh the status .
therefore , We can do some custom effects , For example, zoom when sliding 、 translation :
drawer.addDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerStateChanged(int newState) {
// The state changes
}
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
// In the process of sliding, it continuously calls back slideOffset:0~1
View content = drawer.getChildAt(0);
float scale = 1 - slideOffset;//1~0
float leftScale = (float) (1 - 0.3 * scale);
float rightScale = (float) (0.7f + 0.3 * scale);//0.7~1
drawerView.setScaleX(leftScale);//1~0.7
drawerView.setScaleY(leftScale);//1~0.7
content.setScaleX(rightScale);
content.setScaleY(rightScale);
content.setTranslationX(drawerView.getMeasuredWidth() * (1 - scale));//0~width
}
@Override
public void onDrawerOpened(View drawerView) {
// open
}
@Override
public void onDrawerClosed(View drawerView) {
// close
}
});DrawerLayout+NavigationView Achieve sideslip
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The content part -->
<FrameLayout
android:id="@+id/fl"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
<!-- Part of the menu -->
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/navigation_headerlayout"
app:menu="@menu/navigation_menu"
/>
</android.support.v4.widget.DrawerLayout>We specified the following headers :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_icon"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginTop="20dp"
android:src="@drawable/icon_people"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text=" Lu baobao "
android:textSize="20sp"/>
</LinearLayout>The menu section is as follows (menu Create under folder ), Menus can be nested :
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_gallery"
android:icon="@android:drawable/ic_menu_gallery"
android:orderInCategory="100"
android:title=" Photo album "
/>
<item
android:id="@+id/action_details"
android:icon="@android:drawable/ic_menu_info_details"
android:orderInCategory="100"
android:title=" details "
/>
<item
android:id="@+id/action_about"
android:icon="@android:drawable/ic_menu_help"
android:orderInCategory="100"
android:title=" About "
/>
<item
android:id="@+id/action_music"
android:icon="@android:drawable/ic_menu_more"
android:orderInCategory="100"
android:title=" music "
>
<menu>
<item
android:id="@+id/action_play"
android:icon="@android:drawable/ic_media_play"
android:title=" Play "/>
<item
android:id="@+id/action_pause"
android:icon="@android:drawable/ic_media_pause"
android:title=" Pause "/>
</menu>
</item>
</menu>Up to now , You can achieve side sliding , Finally, we add the corresponding click event , Then close the menu :
nav_view = (NavigationView) findViewById(R.id.nav_view);
drawer = (DrawerLayout) findViewById(R.id.drawer);
nav_view.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Toast.makeText(NavigationViewActivity.this, item.getTitle(), Toast.LENGTH_SHORT).show();
drawer.closeDrawer(nav_view);
return false;
}
});
nav_view.getHeaderView(0).findViewById(R.id.iv_icon).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(NavigationViewActivity.this, " Click on the icon in the head ", Toast.LENGTH_SHORT).show();
drawer.closeDrawer(nav_view);
}
});SnackBar
// among View It's an anchor
Snackbar snackbar = Snackbar.make(v, " Whether to open XXX Pattern ", Snackbar.LENGTH_SHORT);
// You can only set one Action
snackbar.setAction(" open ", new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, " open XXX Pattern ");
}
});
// Monitor on and off
snackbar.setCallback(new Snackbar.Callback() {
@Override
public void onShown(Snackbar snackbar) {
super.onShown(snackbar);
Log.e(TAG, " Show ");
}
@Override
public void onDismissed(Snackbar snackbar, int event) {
super.onDismissed(snackbar, event);
Log.e(TAG, " close ");
}
});
snackbar.show();Snackbar Of Duration There are three kinds of :
Snackbar.LENGTH_SHORT Snackbar.LENGTH_LONG Snackbar.LENGTH_INDEFINITE— Infinite length make Method passes in an anchor , Here comes a Button object . Then you can also set actions and callback monitoring .
Snackbar For details on the use of 《 Lightweight controls SnackBar Use and source code analysis 》
TextInputLayout
Layout :
<android.support.design.widget.TextInputLayout
android:id="@+id/til_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintAnimationEnabled="true">
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint=" Please enter a user name "/>
</android.support.design.widget.TextInputLayout>hintAnimationEnabled Property is to set whether it is enabled Hint Animation .
It should be noted that ,TextInputLayout Must contain a EditText.
Here is a basic example :
public class TextInputMainActivity extends AppCompatActivity {
private TextInputLayout til_input;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text_input);
til_input = (TextInputLayout) findViewById(R.id.til_input);
til_input.getEditText().addTextChangedListener(new MaxTextTextWatcher(til_input, " The number of words cannot be greater than 6", 6));
// Opening count
til_input.setCounterEnabled(true);
til_input.setCounterMaxLength(6);
}
class MaxTextTextWatcher implements TextWatcher {
private TextInputLayout mTextInputLayout;
private String mErrorString;
private int maxTextCount;
public MaxTextTextWatcher(TextInputLayout textInputLayout, String errorString, int maxTextCount) {
mTextInputLayout = textInputLayout;
mErrorString = errorString;
this.maxTextCount = maxTextCount;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String str = mTextInputLayout.getEditText().getText().toString().trim();
if (!TextUtils.isEmpty(str)) {
if (str.length() > maxTextCount) {
// Display error
// Set the error prompt
mTextInputLayout.setError(mErrorString);
mTextInputLayout.setErrorEnabled(true);
} else {
// Closing error
mTextInputLayout.setErrorEnabled(false);
}
}
}
}
}In this case , We used TextInputLayout Error prompt for 、 Word count function , The basic use is relatively simple .
stay TextInputLayout Can easily pass through getEditText Method to find what it contains EditText.、 When an error is displayed , You need to set the error prompt first , Set each time you display . Most of the attributes can be passed through xml How to set , The dynamic setting through the code here is just for the convenience of demonstration .
TextInputLayout For details, see Powerful prompt control TextInputLayout Use and source code analysis
Toolbar
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:logo="@drawable/ic_launcher"
app:subtitle=" Subtitle "
app:navigationIcon="@drawable/abc_ic_ab_back_mtrl_am_alpha"
app:subtitleTextColor="#fff"
app:title=" I'm the title "
app:titleTextColor="#fff"></android.support.v7.widget.Toolbar>Toolbar It's a ViewGroup, Child controls can be placed inside . therefore , If you want to center the title , Then put in one TextView Well .
there ?attr/colorPrimary Is the color value of the system used , Of course, we can also rewrite in the topic .
Be careful :Toolbar Need to use Appcompat A set of things .
Return to listening :
toolbar.setNavigationOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});Realization Toolbar As the interface slides, the transparency changes First we need a layout , By relative arrangement Toolbar Press on ScrollView( perhaps ListView、RecyclerView) On top of .Toolbar The height of ScrollView Both the upper and inner margins use the system's actionBarSize.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.nan.advancedui.toolbar.MyScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingTop="?attr/actionBarSize">
<!-- Here is our content layout -->
</com.nan.advancedui.toolbar.MyScrollView>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:title=" title "
>
</android.support.v7.widget.Toolbar>
</RelativeLayout>Also pay attention to ScrollView Set two more properties , Otherwise, the upper and inner margins will remain after sliding out :
android:clipToPadding=”false” Whether the drawing range of the control is not in Padding Inside .false: The range will be taken into account when drawing padding It will be indented in . android:clipChildren=”false” Whether the child control can not exceed padding Region ( such as ScrollView When sliding up ,child You can slide out of this area ) Then listen for sliding events , If this is ScrollView Words , You need a custom override method to listen :
public class MyScrollView extends ScrollView {
private OnAlphaListener listener;
public void setOnAlphaListener(OnAlphaListener listener) {
this.listener = listener;
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (listener != null) {
int scrollY = getScrollY();
int screen_height = getContext().getResources().getDisplayMetrics().heightPixels;
if (scrollY <= screen_height / 3f) {//0~1f, Transparency should be 1~0f
listener.onAlpha(1 - scrollY / (screen_height / 3f));//alpha= The height of the slide /(screen_height/3f)
}
}
}
}The calculation of transparency needs to be based on the actual situation Customize an interface callback ,Activity(Fragment) real :
public interface OnAlphaListener {
void onAlpha(float alpha);
}The logic of the interface is as follows :
public class ToolbarActivity extends AppCompatActivity implements OnAlphaListener {
private Toolbar mToolbar;
private MyScrollView mScrollview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_toolbar);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mScrollview = (MyScrollView) findViewById(R.id.scrollView);
mScrollview.setOnAlphaListener(this);
}
@Override
public void onAlpha(float alpha) {
mToolbar.setAlpha(alpha);
}
}SearchView
SearchView It's also V7 Package controls , Generally, it is also similar to Toolbar The menu in .
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.ricky.materialdesign.toolbar.MainActivity"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_search"
android:orderInCategory="100"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="always"
android:title=" lookup "/>
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
app:showAsAction="never"
android:title=" Set up "/>
<item
android:id="@+id/action_share"
android:orderInCategory="100"
app:showAsAction="always"
android:title=" Share "
android:icon="@android:drawable/ic_menu_share"/>
<item
android:id="@+id/action_edit"
android:orderInCategory="100"
app:showAsAction="ifRoom"
android:title=" edit "
android:icon="@android:drawable/ic_menu_edit"/>
</menu>here app:actionViewClass=”android.support.v7.widget.SearchView” The menu is specified View It's a SearchView. So we can use it in our code :
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
//SearchView stay Menu Inside , We go through Item Of getActionView You can find it
MenuItem item = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
// As soon as the settings come out, the search box will be displayed directly ---SearchView
searchView.setIconified(false);
// The search box is rendered and cannot be hidden
//searchView.setIconifiedByDefault(false);
// Sometimes we need to implement custom extension effects
// By conjecture ,searchView A layout is used , Go to appcompat Found inside abc_search_view.xml, The properties of the controls in the
ImageView icon = (ImageView) searchView.findViewById(R.id.search_go_btn);
icon.setImageResource(R.drawable.abc_ic_voice_search_api_mtrl_alpha);
icon.setVisibility(View.VISIBLE);
searchView.setMaxWidth(200);
// Input prompt
SearchView.SearchAutoComplete et = (SearchView.SearchAutoComplete) searchView.findViewById(R.id.search_src_text);
et.setHint(" Enter the trade name or initials ");
et.setHintTextColor(Color.WHITE);
// Set whether the submit button is available ( so )
searchView.setSubmitButtonEnabled(true);
// Submit button listening
icon.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, " Submit ", 1).show();
}
});
// image AutoCompleteTextView Use the same prompts
//searchView.setSuggestionsAdapter(adapter);
// Monitoring focus changes
searchView.setOnQueryTextFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
// TODO Auto-generated method stub
}
});
//searchView Turn off listening
searchView.setOnCloseListener(new OnCloseListener() {
@Override
public boolean onClose() {
// TODO Auto-generated method stub
return false;
}
});
searchView.setOnSearchClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, " Submit ", 0).show();
}
});
// Monitor text changes , Call query
searchView.setOnQueryTextListener(new OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String text) {
// Submit text
Toast.makeText(MainActivity.this, " Submit text :"+text, 0).show();
return false;
}
@Override
public boolean onQueryTextChange(String text) {
// Call back when the text changes
System.out.println(" Text changes ~~~~~"+text);
return false;
}
});
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}TabLayout
Let's say TabLayout+ViewPager+Fragment For example , about TabLayout Basic use of .
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="center"
app:tabIndicatorColor="#4ce91c"
app:tabMode="scrollable"
app:tabSelectedTextColor="#4ce91c"
app:tabTextColor="#ccc"
app:tabIndicatorHeight="5dp"
/>
<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>among , The properties that need attention are :
app:tabIndicatorColor="@color/colorPrimary_pink"// The color of the indicator
app:tabTextColor="@color/colorPrimary_pink"//tab The color of the words
app:tabSelectedTextColor="@color/colorPrimary_pinkDark"// Selected tab The color of the words
app:tabMode="fixed"//scrollable: Sliding ;fixed: Can't slide , divide equally tabLayout Width
app:tabGravity="center"// fill:tab Fill the entire width evenly ;center:tab centered Need to switch Fragment, For convenience , We reuse one Fragment:
public class NewsDetailFragment extends Fragment {
@Override
@Nullable
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
TextView tv = new TextView(getContext());
Bundle bundle = getArguments();
String title = bundle.getString("title");
tv.setBackgroundColor(Color.rgb((int)(Math.random()*255), (int)(Math.random()*255), (int)(Math.random()*255)));
tv.setText(title);
return tv;
}
}Activity Code for :
public class TabLayoutActivity extends AppCompatActivity {
private TabLayout tabLayout;
private String[] title = {
" headlines ",
" Journalism ",
" entertainment ",
" sports ",
" Technology ",
" beauty ",
" Finance and economics, ",
" automobile ",
" house ",
" headlines "
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tab_layout);
final ViewPager viewPager = (ViewPager) findViewById(R.id.vp);
tabLayout = (TabLayout) findViewById(R.id.tablayout);
MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager());
//1.TabLayout and Viewpager relation
// tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
//
// @Override
// public void onTabUnselected(TabLayout.Tab arg0) {
//
// }
//
// @Override
// public void onTabSelected(TabLayout.Tab tab) {
// // Callback when selected
// viewPager.setCurrentItem(tab.getPosition(), true);
// }
//
// @Override
// public void onTabReselected(TabLayout.Tab tab) {
//
// }
// });
//2.ViewPager Sliding associations tabLayout
// viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
// Set up tabLayout The label of comes from PagerAdapter
// tabLayout.setTabsFromPagerAdapter(adapter);
// Set up tabLayout The label of comes from PagerAdapter
tabLayout.setupWithViewPager(viewPager);
viewPager.setAdapter(adapter);
// Set up Indicator The left-right spacing (Indicator Width )
setIndicator(this, tabLayout, 15, 15);
}
class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public CharSequence getPageTitle(int position) {
return title[position];
}
@Override
public Fragment getItem(int position) {
Fragment f = new NewsDetailFragment();
Bundle bundle = new Bundle();
bundle.putString("title", title[position]);
f.setArguments(bundle);
return f;
}
@Override
public int getCount() {
return title.length;
}
}
// The following three methods are set Indicator
public static void setIndicator(Context context, TabLayout tabs, int leftDip, int rightDip) {
Class<?> tabLayout = tabs.getClass();
Field tabStrip = null;
try {
tabStrip = tabLayout.getDeclaredField("mTabStrip");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
tabStrip.setAccessible(true);
LinearLayout ll_tab = null;
try {
ll_tab = (LinearLayout) tabStrip.get(tabs);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
int left = (int) (getDisplayMetrics(context).density * leftDip);
int right = (int) (getDisplayMetrics(context).density * rightDip);
for (int i = 0; i < ll_tab.getChildCount(); i++) {
View child = ll_tab.getChildAt(i);
child.setPadding(0, 0, 0, 0);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1);
params.leftMargin = left;
params.rightMargin = right;
child.setLayoutParams(params);
child.invalidate();
}
}
public static DisplayMetrics getDisplayMetrics(Context context) {
DisplayMetrics metric = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(metric);
return metric;
}
public static float getPXfromDP(float value, Context context) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value,
context.getResources().getDisplayMetrics());
}
}New tabLayout.setupWithViewPager(viewPager); Method instead of in the comment 3 There's a way , In fact, the internal work is the same .TabLayout No modification is provided by default Indicator A function of width , We need to set it by reflection .
use TabLayout Realize bottom navigation ( Compared with the traditional TabHost, It is sliding )
It's just three steps : 1. Put... In the layout TabLayout At the bottom of the layout 2. Remove the bottom indicator,app:tabIndicatorHeight=”0dp” 3. Achieve your own effect , Custom label layout The code is as follows :
for (int i = 0; i < tabLayout.getTabCount(); i++) {
TabLayout.Tab tab = tabLayout.getTabAt(i);
tab.setCustomView(view);
}CardView
CardView It's just one. ViewGroup, Sub layouts can be placed inside
<android.support.v7.widget.CardView
android:layout_width="300dp"
android:layout_height="200dp"
android:layout_margin="16dp"
android:clickable="true"
android:foreground="?attr/selectableItemBackground"
android:stateListAnimator="@drawable/z_translation"
app:cardCornerRadius="10dp"
app:cardElevation="10dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/test"/>
</android.support.v7.widget.CardView>among ,cardElevation Is to set the height , The higher the height , The more obvious the shadow .foreground Property is to set the click water ripple effect .cardCornerRadius Is to set the size of the fillet .stateListAnimator Is to set the click animation effect , After clicking , Press down ,z_translation as follows :
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true">
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="translationZ"
android:valueTo="-15dp"
android:valueType="floatType"/>
</item>
<item>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="translationZ"
android:valueTo="0dp"
android:valueType="floatType"/>
</item>
</selector>CardView Compatibility development establish layout、layout-v21 Two sets of layouts , Write two copies according to the following differences CardView Layout file for . Particular attention is paid to stateListAnimator This attribute , If the smallest SDK Version below 21,AS Will warn you . 1. The nuances of shadows 5.x System : The margin shadow is small , You need to add margins manually 16dp,android:layout_margin=”16dp” 4.x System : The margin shadow is large , Manually modify the margins 0dp( reason : The shadow effect is automatically set in the compatibility package margin To deal with it 16dp) 2. Subtle differences in fillet effect 5.x System : Both the picture and the layout can well present the rounded corner effect , The picture is rounded , therefore 5.x There is no need to set the above app:contentPadding
4.x System : The figure cannot be rounded ( The right angle of the picture will top CardView On the edge ), If you want to make 5.x Same effect : It can be processed into rounded corners when loading pictures ( And CardView The size of the fillet is the same ), therefore 4.x There is no need to set the above app:contentPadding, So as to look better
3. The difference of water ripple effect 5.x System : Can pass android:foreground=”?attr/selectableItemBackground” Realization 4.x System : You have to implement it yourself
4. Click on the difference in animation 5.x System : Can pass android:stateListAnimator=”@drawable/z_translation” Animate 4.x System : You cannot animate the above , because 4.x No, z The concept of axis
FloatingActionButton
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="right|bottom"
android:onClick="rotate"
android:src="@drawable/ic_add_white_24dp"
app:backgroundTint="?attr/colorPrimary"
app:elevation="10dp"
app:fabSize="normal"
app:rippleColor="#f00"
/>among : 1.src Property is the setting icon 2.backgroundTint Is to set the background color ( The icon has a transparent background ) 3.elevation Is to set the shadow size 4.fabsize Is to set the size of the icon , It's usually normal( No settings ) 5.rippleColor Is to set the color of the water ripple Click on the event below ( rotate ):
private boolean reverse = false;
public void rotate(View v) {
float toDegree = reverse ? -180f : 180f;
ObjectAnimator animator = ObjectAnimator
.ofFloat(v, "rotation", 0.0f, toDegree)
.setDuration(400);
animator.start();
reverse = !reverse;
}FloatingActionButton Animation programme 1: When the list slides FloatingActionButton Hide and show , By customizing OnScrollListener Realization
public class FabScrollListener extends OnScrollListener {
private static final int THRESHOLD = 20;
private int distance = 0;
private HideScrollListener hideListener;
private boolean visible = true;// Whether or not visible
public FabScrollListener(HideScrollListener hideScrollListener) {
this.hideListener = hideScrollListener;
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
/**
* dy:Y Increment in axis direction
* There are positive and negative
* When the animation is being executed , Don't do it anymore
*/
if (distance > THRESHOLD && visible) {
// Hide animation
visible = false;
hideListener.onHide();
distance = 0;
} else if (distance < -THRESHOLD && !visible) {
// Show animation
visible = true;
hideListener.onShow();
distance = 0;
}
if (visible && dy > 0 || (!visible && dy < 0)) {
distance += dy;
}
}
}Customize a OnScrollListener, rewrite onScrolled Method . Determine the current scrolling direction 、 Rolling distance 、 Current FloatingActionButton Whether to display for corresponding logic processing .
among HideScrollListener Is a custom listening interface :
public interface HideScrollListener {
void onHide();
void onShow();
}from Activity Implement this interface :
public class FabAnimActivity extends AppCompatActivity implements HideScrollListener {
private RecyclerView recyclerview;
private ImageButton fab;
private Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Omit some code
// Add slide monitor
recyclerview.addOnScrollListener(new FabScrollListener(this));
}
@Override
public void onHide() {
// Hide animation -- Attribute animation
toolbar.animate().translationY(-toolbar.getHeight()).setInterpolator(new AccelerateInterpolator(3));
RelativeLayout.LayoutParams layoutParams = (LayoutParams) fab.getLayoutParams();
fab.animate().translationY(fab.getHeight() + layoutParams.bottomMargin).setInterpolator(new AccelerateInterpolator(3));
}
@Override
public void onShow() {
// Show animation -- Attribute animation
toolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));
fab.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));
}
}programme 2: Customize FloatingActionButton Of Behavior Realization Inherit FloatingActionButton Of Behavior:
public class FabBehavior extends FloatingActionButton.Behavior {
private boolean visible = true;// Whether or not visible
// Instantiation CoordinatorLayout.LayoutParams Reflection generation Behavior example , That's why customizing behavior You need to rewrite the following constructor
public FabBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
// When observing View(RecyclerView) It is called back at the beginning of sliding
//nestedScrollAxes: Slide the associated axis , We are only concerned with vertical sliding .
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
}
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
// When observing view It is called back when sliding
// Perform animation as appropriate
if (dyConsumed > 0 && visible) {
//show
visible = false;
onHide(child);
} else if (dyConsumed < 0) {
//hide
visible = true;
onShow(child);
}
}
public void onHide(FloatingActionButton fab) {
// Hide animation -- Attribute animation
// toolbar.animate().translationY(-toolbar.getHeight()).setInterpolator(new AccelerateInterpolator(3));
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
// fab.animate().translationY(fab.getHeight()+layoutParams.bottomMargin).setInterpolator(new AccelerateInterpolator(3));
//FAB narrow
ViewCompat.animate(fab).scaleX(0f).scaleY(0f).start();
}
public void onShow(FloatingActionButton fab) {
// Show animation -- Attribute animation
// toolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
// fab.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));
//FAB Zoom in
ViewCompat.animate(fab).scaleX(1f).scaleY(1f).start();
}
}Constructor must override , rewrite onStartNestedScroll Return to determine which direction of sliding , rewrite onNestedScroll Carry out corresponding logical processing (FloatingActionButton Show and hide the attribute animation of ).
Finally, use... In the layout file CoordinatorLayout Layout , And give FloatingActionButton Add custom Behavior:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingTop="?attr/actionBarSize"
/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:title="Fab Animation "
app:titleTextColor="#fff"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="58dp"
android:layout_height="58dp"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@drawable/ic_favorite_outline_white_24dp"
app:layout_behavior="com.nan.advancedui.fab.anim.behavior.FabBehavior"
/>
</android.support.design.widget.CoordinatorLayout>CoordinatorLayout
CoordinatorLayout Is an inheritance from ViewGroup The layout of the container .CoordinatorLayout Listen for sliding child controls to slide through Behavior Feed back to other child controls and perform some animation . Simply speaking , It is to achieve touch by coordinating and scheduling the child controls or layouts inside ( It generally refers to sliding ) Produce some related animation effects . among ,view Of Behavior It is a bridge of communication , We can set view Of Behavior To achieve touch animation scheduling .
Be careful : Sliding controls refer to :RecyclerView/NestedScrollView/ViewPager, signify ListView、ScrollView no way .
Please refer to 《CoordinatorLayout Use full resolution 》
MaterialDesign Animation
1.Touch Feedback( Touch feedback ) 5.0+ Your mobile phone comes with you .
By setting background The attribute value of :
<Button
android:id="@+id/btn_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:background="?attr/selectableItemBackgroundBorderless"
android:text=" test "/>among ,selectableItemBackground It is the water ripple effect with boundary ,selectableItemBackgroundBorderless There is no boundary of the water ripple effect .
You can change the background color and the color of the water ripple , And it's better to use AppcompatActivity:
<item name="colorControlHighlight">@color/colorPrimary_pink</item>
<item name="colorButtonNormal">@color/material_blue_grey_800</item>If you want to change the color of individual controls , It can be realized by nesting a layer of layout outside . 2.Reveal Effect( Disclosure effect ) Example :Activity The effects of the revelation of . The main use of ViewAnimationUtil Tool class implementation :
// Circular water ripple exposing effect
ViewAnimationUtils.createCircularReveal(
view, // What's the role of View above
centerX, centerY, // The center of diffusion
startRadius, // Start spreading initial radius
endRadius)// Diffusion end radius among , The radius of diffusion is calculated by Pythagorean theorem , for example :
(float) Math.hypot(view.getWidth() / 2, view.getHeight() / 2)@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
view_root = (LinearLayoutCompat) findViewById(R.id.llc_test);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Animator animator = ViewAnimationUtils.createCircularReveal(view_root, view_root.getWidth() / 2, view_root.getHeight() / 2, 0f, (float) Math.hypot(view_root.getWidth() / 2, view_root.getHeight() / 2));
animator.setDuration(1000);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
}
}Because animation is attached to window above , And in the Activity onCreate Method Window Not yet initialized , So you need to onWindowFocusChanged Execute animation in .
3.Activity transition(Activity Transition animation effect ) Two Activity When doing a jump , Transition animation . We used to pass overridePendingTransition Method realization .
The main use of ActivityOptions class . Only support API21 Version above . Version judgment is troublesome , Google is very considerate Designed a compatible class :ActivityOptionsCompat(v4 In bag ), But this class has no transition animation effect in the lower version , It just solves the problem that we judge the version manually .
Use convert animation prerequisites : You need to give two Activity Are set as follows , Let it allow transition animation .
// Method 1 :
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
// Method 2 :
Modify the theme :<item name="android:windowContentTransitions">true</item>Transition animation can be divided into two categories : Shared element transformation and common transformation . 1) Shared element transformation
Single element :
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(MDAnimActivity.this, iv_test, "test");
Intent intent = new Intent(MDAnimActivity.this, MDAnimSceneTransitionActivity.class);
startActivity(intent, options.toBundle());
}Multiple elements are converted at the same time :
ActivityOptionsCompat optionsCompat = ActivityOptionsCompat
.makeSceneTransitionAnimation(this, Pair.create((View)iv1, "iv1"),Pair.create((View)bt, "bt"));
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent, optionsCompat.toBundle());When the page returns, the system automatically realizes , Please have a look at FragmentActivity Of onBackPressed Method :
@Override
public void onBackPressed() {
if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {
super.onBackPressed();
}
}2. Conversion of unshared elements Only API 21 Only then has the following self-contained effect , Therefore, you need to judge the version number when using .
The three systems are equipped with : Sliding effect (Slide)、 Unfold the effect Explode、 Gradient shows hidden effects Fade. Let's say Fade Introduce... As an example :
// Two better Activity Set some , The effect will be better
Fade fade = new Fade();
fade.setDuration(1000);
getWindow().setExitTransition(fade);// Out of the animation
getWindow().setEnterTransition(fade);// The animation coming in
// If there are shared elements , You can set up shared elements , Then it will follow the shared element animation , Other children view Will follow Fade Animation execution .
ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this);
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent, optionsCompat.toBundle());边栏推荐
- Add expiration time for localstorage
- 打新债属于什么理财产品?
- 62. different paths
- How to calculate the position of gold ETF
- C serializabledictionary serialization / deserialization
- 使用aggregation API扩展你的kubernetes API
- cadence SPB17.4 - allegro - 優化指定單條電氣線折線連接角度 - 折線轉圓弧
- E-R diagram
- How to refine permissions to buttons?
- The longest child sequence of the 2019 Blue Bridge Cup
猜你喜欢

Hierarchy selector

崔鹏团队:万字长文梳理「稳定学习」全景图

Psychological analysis of the safest spot Silver

BGP联邦综合实验

Daily question brushing record (I)

cadence SPB17.4 - 中文UI设置

Cadence spb17.4 - Chinese UI settings

JMeter associated login 302 type interface

Read Amazon memorydb database based on redis

How about precious metal spot silver?
随机推荐
魔王冷饭||#099 魔王说西游;老板的本质;再答中年危机;专业选择
崔鹏团队:万字长文梳理「稳定学习」全景图
关于打算做一个web的问题看板,需要使用哪些方面语言及数据库知识!
cadence SPB17.4 - 中文UI设置
Requête linq
SAP ui5 application development tutorial 103 - how to consume the trial version of the third-party library in SAP ui5 applications
Charles garbled code problem solving
Shell 查看帮助
Yyds dry goods counting tail recursion is better than recursion
[initial launch] there are too many requests at once, and the database is in danger
LeetCode刷题——715. Range 模块
Tidb monitoring upgrade: a long way to solve panic
Get the start and end dates of the current week
层次选择器
Which brokerage platform is better and safer for a brokerage to open an account on a mobile phone? What if you need a low commission
The longest child sequence of the 2019 Blue Bridge Cup
一文读懂基于Redis的Amazon MemoryDB数据库
Leetcode question brushing - 715 Range module
LINQ query
Cadence spb17.4 - Chinese UI settings