您的位置:首页 > 产品设计 > UI/UE

Training—Best Practices for User Experience & UI

2013-11-09 22:22 471 查看
阅读 http://developer.android.com/training/best-ux.html
关于怎么使用swipe views。

首先要有个布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />


这里有两种类可以继承实现pagerview。

FragmentPagerAdapter
This is best when navigating between sibling screens representing a fixed, small number of pages.
FragmentStatePagerAdapter
This is best for paging across a collection of objects for which the number of pages is undetermined. It destroys fragments as the user navigates to other pages, minimizing memory usage.

  第一种比较适合用于数目较少而且固定的情况,例如有导航条那种。

  第二张比较适合情况不太确定的时候,当用户不需要的时候它会自动销毁fragment。

  下面是使用了第二种的代码:

public class CollectionDemoActivity extends FragmentActivity {
// When requested, this adapter returns a DemoObjectFragment,
// representing an object in the collection.
DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;
ViewPager mViewPager;

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection_demo);

// ViewPager and its adapters use support library
// fragments, so use getSupportFragmentManager.
mDemoCollectionPagerAdapter =
new DemoCollectionPagerAdapter(
getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mDemoCollectionPagerAdapter);
}
}

// Since this is an object collection, use a FragmentStatePagerAdapter,
// and NOT a FragmentPagerAdapter.
public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
public DemoCollectionPagerAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int i) {
Fragment fragment = new DemoObjectFragment();
Bundle args = new Bundle();
// Our object is just an integer :-P
args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1);
fragment.setArguments(args);
return fragment;
}

@Override
public int getCount() {
return 100;
}

@Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
}

// Instances of this class are fragments representing a single
// object in our collection.
public static class DemoObjectFragment extends Fragment {
public static final String ARG_OBJECT = "object";

@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
// The last two arguments ensure LayoutParams are inflated
// properly.
View rootView = inflater.inflate(
R.layout.fragment_collection_object, container, false);
Bundle args = getArguments();
((TextView) rootView.findViewById(android.R.id.text1)).setText(
Integer.toString(args.getInt(ARG_OBJECT)));
return rootView;
}


给actionbar提供Tab

@Override
public void onCreate(Bundle savedInstanceState) {
final ActionBar actionBar = getActionBar();
...

// Specify that tabs should be displayed in the action bar.
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

// Create a tab listener that is called when the user changes tabs.
ActionBar.TabListener tabListener = new ActionBar.TabListener() {
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
// show the given tab
}

public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
// hide the given tab
}

public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
// probably ignore this event
}
};

// Add 3 tabs, specifying the tab's text and TabListener
for (int i = 0; i < 3; i++) {
actionBar.addTab(
actionBar.newTab()
.setText("Tab " + (i + 1))
.setTabListener(tabListener));
}
}


当pagerView改变的时候让tab也改变

public void onCreate(Bundle savedInstanceState) {
...

mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setOnPageChangeListener(
new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
// When swiping between pages, select the
// corresponding tab.
getActionBar().setSelectedNavigationItem(position);
}
});
...
}


接下来学学怎么使用Navigation Drawer,就是类似侧边栏。

首先来一个布局文件:

<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The main content view -->
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- The navigation drawer -->
<ListView android:id="@+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>


需要注意的地方:


This layout demonstrates some important layout characteristics:

The main content view (the
FrameLayout
above) must be the first child in the
DrawerLayout
because the XML order implies z-ordering and the drawer must be on top of the content.

The main content view is set to match the parent view's width and height, because it represents the entire UI when the navigation drawer is hidden.

The drawer view (the
ListView
) must specify its horizontal gravity with the
android:layout_gravity
attribute. To support right-to-left (RTL) languages, specify the value with
"start"
instead of
"left"
(so the drawer appears on the right when the layout is RTL).

The drawer view specifies its width in
dp
units and the height matches the parent view. The drawer width should be no more than 320dp so the user can always see a portion of the main content.


  1、主要内容的容器必须先声明,因为这样它才会被掩盖在侧边栏之下。

  2、要注意侧边栏的
android:layout_gravity
属性,并且宽度不要超过320dp。

代码中初始化:

public class MainActivity extends Activity {
private String[] mPlanetTitles;
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
...

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mPlanetTitles = getResources().getStringArray(R.array.planets_array);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);

// Set the adapter for the list view
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, mPlanetTitles));
// Set the list's click listener
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

...
}
}


private class DrawerItemClickListener implements ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
selectItem(position);
}
}

/** Swaps fragments in the main content view */
private void selectItem(int position) {
// Create a new fragment and specify the planet to show based on position
Fragment fragment = new PlanetFragment();
Bundle args = new Bundle();
args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
fragment.setArguments(args);

// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment)
.commit();

// Highlight the selected item, update the title, and close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(mPlanetTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}

@Override
public void setTitle(CharSequence title) {
mTitle = title;
getActionBar().setTitle(mTitle);
}


因为侧边栏的开与关还会涉及到一些界面的内容显示与否,因此需要:

public class MainActivity extends Activity {
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
...

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...

mTitle = mDrawerTitle = getTitle();
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {

/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}

/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};

// Set the drawer toggle as the DrawerListener
mDrawerLayout.setDrawerListener(mDrawerToggle);
}

/* Called whenever we call invalidateOptionsMenu() */
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the nav drawer is open, hide action items related to the content view
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
}


上面适合在没有actionbar的情况下使用,而下面就是使用了
ActionBarDrawerToggle
的详细代码:

public class MainActivity extends Activity {
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
...

public void onCreate(Bundle savedInstanceState) {
...

mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(
this,                  /* host Activity */
mDrawerLayout,         /* DrawerLayout object */
R.drawable.ic_drawer,  /* nav drawer icon to replace 'Up' caret */
R.string.drawer_open,  /* "open drawer" description */
R.string.drawer_close  /* "close drawer" description */
) {

/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
}

/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(mDrawerTitle);
}
};

// Set the drawer toggle as the DrawerListener
mDrawerLayout.setDrawerListener(mDrawerToggle);

getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
}

@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Pass the event to ActionBarDrawerToggle, if it returns
// true, then it has handled the app icon touch event
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle your other action bar items...

return super.onOptionsItemSelected(item);
}

...
}


其实整个过程有很多细节的地方:

1、DrawerLayout的两个内在布局文件的先后以及相关属性的设置;

2、初始化,对各个XML的引用;

3、点击菜单的响应,主要是修改actionbar的显示;

4、开关drawlayout时的响应,主要分两种,一种有actionbar,一种没有。没有的那种记得使用invalidateOptionsMenu和onPrepareOptionsMenu。有的话记得onPostCreate、onConfigurationChanged、onOptionsItemSelected。

记得APP左上角的图标按钮吗,接下来将这个。

要让他显示只需要在代码里设置并写上按下的响应:

@Override
public void onCreate(Bundle savedInstanceState) {
...
getActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
}
return super.onOptionsItemSelected(item);
}


在官方看来,这个是进入你的Activity的另一个入口,即点击它可以进入响应的parentsActivity,只需要在XML里:

<application ... >
...
<!-- The main/home activity (it has no parent activity) -->
<activity
android:name="com.example.myfirstapp.MainActivity" ...>
...
</activity>
<!-- A child of the main activity -->
<activity
android:name="com.example.myfirstapp.DisplayMessageActivity"
android:label="@string/title_activity_display_message"
android:parentActivityName="com.example.myfirstapp.MainActivity" >
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.myfirstapp.MainActivity" />
</activity>
</application>


@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}


这样就可以了,但是有可能涉及到Back Stack的问题,可自行前往观看。

在官方提到了一个情况,就是:当用户从通知栏进入你的Activity之后再按back 健的时候,系统应该回到本Activity的父Activity。

首先在XML里声明父Activity,然后在代码里:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
// Intent for the activity to open when user selects the notification
Intent detailsIntent = new Intent(this, DetailsActivity.class);

// Use TaskStackBuilder to build the back stack and get the PendingIntent
PendingIntent pendingIntent =
TaskStackBuilder.create(this)
// add all of DetailsActivity's parents to the stack,
// followed by DetailsActivity itself
.addNextIntentWithParentStack(upIntent)
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentIntent(pendingIntent);
} else {
// This activity is part of this app's task, so simply
// navigate up to the logical parent activity.
NavUtils.navigateUpTo(this, upIntent);
}
return true;
}
return super.onOptionsItemSelected(item);
}



The resulting
PendingIntent
specifies not only the activity to start (as defined by
detailsIntent
), but also the back stack that should be inserted into the task (all parents of the
DetailsActivity
defined by
detailsIntent
). So when the
DetailsActivity
starts, pressing Back navigates backward through each of the
DetailsActivity
class's parent activities.


当目标Activity启动的时候,父Activity就自动添加了。

fragment的出入栈使用addToBackStack就行了。

fragment可在back 发生改变的时候更改数据等:

getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
// Update your UI here.
}
});


有可能你需要重写back响应,例如你打开webview的时候:

@Override
public void onBackPressed() {
if (mWebView.canGoBack()) {
mWebView.goBack();
return;
}

// Otherwise defer to system default behavior.
super.onBackPressed();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐