需求:
当点击单个item的时候使用AIDL给商家发送一条“我对这个商品很感兴趣,想购买”的消息,接着弹出一个AlertDialog,AlertDialog中的视图是一个自定义View,View中的具体内容是一个同心圆中包含一段红色的文字“已经选中商品!”
点击图一中的单个item中的图片的时候使用先让图片发生明暗变化、旋转360度的效果,然后使用WebView在新界面中将当前item中的图片在新的界面中展示。
一, 添加依赖
compile 'com.jakewharton:butterknife:8.8.1' compile 'com.jakewharton:butterknife-compiler:8.8.1' compile 'com.facebook.fresco:fresco:1.5.0' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.android.support:design:25.3.1'
二, TabLayout+ViewPager + Fragment 显示导航的切换
1, 页面: activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="bw.com.month_test.MainActivity"> <android.support.design.widget.TabLayout android:layout_width="match_parent" android:layout_height="60dp" android:id="@+id/tab_layout_id" /> <android.support.v4.view.ViewPager android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/view_pager_id"/> </LinearLayout>
2, MainActivity.java
public class MainActivity extends AppCompatActivity { private Unbinder unbinder; //TODO 使用ButterKnife 初始化控件 @BindView(value = R.id.tab_layout_id) TabLayout mTabLayout;//导航 private List<String> titles = new ArrayList<>();//标题 @BindView(value = R.id.view_pager_id) ViewPager mViewPager;//内容 private List<Fragment> data = new ArrayList<>();//数据源 private MyAdapter adapter;//适配器 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //TODO 绑定ButterKnife unbinder = ButterKnife.bind(this); //TODO 初始化标题 titles.add("生钱"); titles.add("花钱"); titles.add("部落"); titles.add("我的"); //TODO 初始化数据源 data.add(new ShengQianFragment()); data.add(new OtherFragment()); data.add(new OtherFragment()); data.add(new OtherFragment()); //TODO 初始化适配器 adapter = new MyAdapter(getSupportFragmentManager()); mViewPager.setAdapter(adapter); //TODO TabLayout 和ViewPager 结合 mTabLayout.setupWithViewPager(mViewPager); } @Override protected void onDestroy() { super.onDestroy(); unbinder.unbind();//解绑 } //TODO 自定义适配器 class MyAdapter extends FragmentPagerAdapter { public MyAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return data.get(position); } @Override public int getCount() { return data.size(); } //TODO 设置导航的标题 @Override public CharSequence getPageTitle(int position) { return titles.get(position); } } }
3, 创建Fragment : ShengQianFragment.java
OtherFreagment -- 只是创建一个Freagment不需要写入任何的内容
三, 第一个 Fragment ---- ShengQianFreagment.java, "生钱" , 通过Retrofit获取网络数据, 图片使用Fresco获取图片做圆角的 处理, 显示在GridView中
1, 页面: freagment_sheng_qian.java
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="bw.com.month_test.ShengQianFragment"> <GridView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/gv_id" android:numColumns="2"/> </FrameLayout>
2, item_gv.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:fresco="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="20dp"> <!-- fresco:roundAsCircle="true" 圆形图片--> <com.facebook.drawee.view.SimpleDraweeView android:layout_width="150dp" android:layout_height="150dp" android:id="@+id/sdv_id" android:layout_centerHorizontal="true" fresco:placeholderImage="@mipmap/ic_launcher" fresco:roundedCornerRadius="20dp" fresco:roundTopLeft="true" fresco:roundTopRight="true" fresco:roundBottomLeft="true" fresco:roundBottomRight="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tv_id" android:text="标题" android:textColor="@color/colorAccent" android:textSize="26sp" android:layout_marginTop="10dp" android:layout_below="@id/sdv_id" android:layout_centerHorizontal="true" /> </RelativeLayout>
3, MyApp.java --- 初始化Fresco
public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); Fresco.initialize(this); } }
4, 在清单文件中, 引入 --- 红色部分 , 添加
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="bw.com.month_test"> <uses-permission android:name="android.permission.INTERNET" /> <application android:name=".MyApp" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true"
5, ShengQianFragment.java
public class ShengQianFragment extends Fragment { private MyAidl myAidl = null; //TODO 检测服务示范绑定成功 private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //绑定成功的回调方法 myAidl = MyAidl.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } }; //TODO 通过ButterKnife 初始化控件 @BindView(value = R.id.gv_id) GridView mGridView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_sheng_qian, container, false); //TODO 绑定ButterKnife ButterKnife.bind(this,view); //TODO 通过Retrofit获取网络数据 Retrofit.Builder builder = new Retrofit.Builder(); builder.baseUrl("http://www.qubaobei.com/ios/");//设置基础地址 builder.addConverterFactory(GsonConverterFactory.create());//设置Gson解析 Retrofit retrofit = builder.build();//得到Retrofit对象 QubaobeiInterface qubaobeiInterface = retrofit.create(QubaobeiInterface.class);//得到获取数据的接口 Call<Qubaobei> call = qubaobeiInterface.getInfo();//得到Call 接口 //执行异步请求数据 call.enqueue(new Callback<Qubaobei>() { @Override public void onResponse(Call<Qubaobei> call, Response<Qubaobei> response) { //获取到的数据 Qubaobei qubaobei = response.body(); //得到数据源 List<Qubaobei.DataBean> data = qubaobei.getData(); MyBaseAdapter adapter = new MyBaseAdapter(getContext(),data); mGridView.setAdapter(adapter); } @Override public void onFailure(Call<Qubaobei> call, Throwable t) { } }); //TODO 点击每个Item , 获取AIDL 的信息 mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //TODO 获取AIDL 的信息 - 后面有介绍, 第四大步骤 try { String str = myAidl.getInfo(); Toast.makeText(getContext(), str, Toast.LENGTH_LONG).show(); } catch (RemoteException e) { e.printStackTrace(); } //TODO 弹出自定义的对话框 -- 后面有介绍, 第四大步骤 AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); View dialogView = LayoutInflater.from(getContext()).inflate(R.layout.custom_dialog,null); builder.setView(dialogView);//设置自定义的视图 builder.show(); } }); return view; } //TODO 绑定服务 @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = new Intent(); intent.setAction("com.bw.test.aidl");//服务端Service的动作 intent.setPackage("bw.com.server");//服务端的包名 getContext().bindService(intent,connection, Context.BIND_AUTO_CREATE); } //TODO 解绑服务 @Override public void onDestroy() { super.onDestroy(); getContext().unbindService(connection); } }
6, Retrofit 获取数据的接口: QubaobeiInterface.java
public interface QubaobeiInterface { //http://www.qubaobei.com/ios/ -----cf/dish_list.php?stage_id=1&limit=20&page=1 @GET("cf/dish_list.php?stage_id=1&limit=20&page=1") Call<Qubaobei> getInfo();
7, Qubaobei.java ---- GsonFromant 生成的实体类
8, MyBaseAdapter.java
public class MyBaseAdapter extends BaseAdapter { private Context context; private List<Qubaobei.DataBean> data; public MyBaseAdapter(Context context, List<Qubaobei.DataBean> data) { this.context = context; this.data = data; } @Override public int getCount() { return data != null ? data.size() : 0; } @Override public Object getItem(int position) { return data.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, final ViewGroup parent) { final ViewHolder viewHolder; if(convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.item_gv,parent,false); viewHolder = new ViewHolder(convertView); convertView.setTag(viewHolder); }else { viewHolder = (ViewHolder) convertView.getTag(); } //赋值 viewHolder.mTv.setText(data.get(position).getTitle()); //图片 --- Fresco : 初始化 Uri uri = Uri.parse(data.get(position).getPic()); viewHolder.mSdv.setImageURI(uri); viewHolder.mSdv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //TODO 点击图片, 暗变化、旋转360度的效果 -- 补间动画的集合 AnimationSet animationSet = new AnimationSet(false); AlphaAnimation alphaAnimation = new AlphaAnimation(0.0f,1.0f); RotateAnimation rotateAnimation = new RotateAnimation(0,360, Animation.RELATIVE_TO_SELF,0.5f, Animation.RELATIVE_TO_SELF,0.5f); animationSet.addAnimation(alphaAnimation); animationSet.addAnimation(rotateAnimation); animationSet.setDuration(3000); viewHolder.mSdv.startAnimation(animationSet); //TODO 点击图片, 跳转到内容页面 --- 后面有介绍到五 Intent intent = new Intent(context,InfoActivity.class); intent.putExtra("imagePath",data.get(position).getPic());//传值 context.startActivity(intent); } }); return convertView; } class ViewHolder { @BindView(value = R.id.sdv_id) SimpleDraweeView mSdv; @BindView(value = R.id.tv_id) TextView mTv; public ViewHolder(View view) { //TODO 绑定ButterKnife ButterKnife.bind(this,view); } } }
四, 当点击单个item的时候使用AIDL给商家发送一条“我对这个商品很感兴趣,想购买”的消息,接着弹出一个AlertDialog,AlertDialog中的视图是一个自定义View,View中的具体内容是一个同心圆中包含一段红色的文字“已经选中商品!”
注意: AIDL 必须要再次创建一个module , 名字叫: Server
Server端:
1, src/main 中创建aidl文件
interface MyAidl { String getInfo(); }
2, 编译工程, 生成同名的 .java 文件
3, 在src/main/java 目录中创建Service 类, myService.java
public class MyService extends Service { MyAidl.Stub stub = new MyAidl.Stub() { @Override public String getInfo() throws RemoteException { return "我对这个商品很感兴趣,想购买"; } }; @Nullable @Override public IBinder onBind(Intent intent) { return stub; } }
4, 在清单文件中, 注册Service
<!--注册Service--> <service android:name=".MyService"> <intent-filter> <action android:name="com.bw.test.aidl"/> </intent-filter> </service> </application>
客户端: App 中
1, 复制服务器端, src/main 目录中的aidl 文件, 到客户端 App 中的src/main 目录下
2, 编译生成, 同名的.java 文件
3, 在ShengQianFreagment.java 中调用
弹出自定义的对话框, 显示自定义的页面
1, CustomView.java
public class CustomView extends View { public CustomView(Context context) { super(context); } public CustomView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); //绘制圆 paint.setStyle(Paint.Style.STROKE);//设置空心 paint.setColor(Color.BLACK); canvas.drawCircle(500,500,300,paint);//绘制内圆 canvas.drawCircle(500,500,400,paint);//绘制外圆 //绘制文字 paint.setColor(Color.RED); paint.setTextSize(40); paint.setStyle(Paint.Style.FILL); canvas.drawText("已经选中商品!",300,500,paint); } }
2, custom_dialog.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" > <bw.com.month_test.CustomView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/cs_id" /> </LinearLayout>
五, 点击图一中的单个item中的图片的时候使用先让图片发生明暗变化、旋转360度的效果,然后使用WebView在新界面中将当前item中的图片在新的界面中展示。
评分标准:
1,动画效果(5分)
2,Webview展示加载进度(5分)
3,使用Webview自身的浏览器显示图片(而非系统浏览器或者第三方浏览器)(5分)
4,为浏览器添加上一页、下一页和返回键并实现功能(5分)
5,当点击下一页的时候如果到达了最后一页则使用NDK技术提示“没有更多内容,已经是最后一页”(10分)
1, 动画 --- 在前面的MyBaseAdapter.java 中已经实现了
2, WebView 展示加载进度, 并且加载 ----- 第4 个步骤
页面: activity_info.java
<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent" tools:context="bw.com.month_test.InfoActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="onClick" android:id="@+id/but_01" android:text="上一页"/> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="onClick" android:id="@+id/but_02" android:text="下一页"/> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="onClick" android:id="@+id/but_03" android:text="返回"/> </LinearLayout> <ProgressBar android:layout_width="match_parent" android:layout_height="10dp" style="?android:attr/progressBarStyleHorizontal" android:id="@+id/pb_id"/> <WebView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/web_view_id" /> </LinearLayout>
InfoActivity.java
public class InfoActivity extends AppCompatActivity { private String[] urls= {"http://www.qubaobei.com/ios/cf/uploadfile/132/9/8289.jpg", "http://www.qubaobei.com/ios/cf/uploadfile/132/3/2166.jpg", "http://www.qubaobei.com/ios/cf/uploadfile/132/3/2262.jpg"}; private WebView mWebView; private ProgressBar mProgressBar; private boolean isLast = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_info); mWebView = (WebView) findViewById(R.id.web_view_id); mProgressBar = (ProgressBar)findViewById(R.id.pb_id); String imagePath = getIntent().getStringExtra("imagePath");//当前的图片 if(imagePath!=null) { mWebView.loadUrl(imagePath); }else { mWebView.loadUrl("http://www.baidu.com"); } //TODO 在当前的页面中显示 mWebView.setWebViewClient(new WebViewClient()); //TODO 设置支持js WebSettings webSettings = mWebView.getSettings(); webSettings.setJavaScriptEnabled(true); //TODO 设置加载的进度 mWebView.setWebChromeClient(new WebChromeClient(){ @Override public void onProgressChanged(WebView view, int newProgress) { super.onProgressChanged(view, newProgress); mProgressBar.setProgress(newProgress); } }); } public void onClick(View view) { switch (view.getId()) { case R.id.but_01: //返回上一个地址 mWebView.loadUrl(urls[1]); break; case R.id.but_02: //下一个地址 if(isLast) { mWebView.loadUrl(urls[2]); isLast = false; } else { //TODO 到达最后一页, 显示ndk 获取的数据(后面介绍) String ndkStr = JniTest.getInfo(); Toast.makeText(this, ndkStr, Toast.LENGTH_SHORT).show(); } break; case R.id.but_03: //返回上一个页面 finish(); break; } } }
3,第5 步骤: 当点击下一页的时候如果到达了最后一页则使用NDK技术提示“没有更多内容,已经是最后一页”(10分)
注意: 参考NDK使用的地址:http://blog.csdn.net/xiuxiu_861223/article/details/78792939
3.1 在src/main /java 中创建一个普通的java类, JniTest.java
.java -->.calss ---> .h --- > .c ---- > so 包
/** * NDK 的功能 * .java -->.calss ---> .h --- > .c ---- > so 包 */ public class JniTest{ static { System.loadLibrary("app"); } public static native String getInfo(); }
3.2 点击Build -- Build Module App -- 编译 生成.class
3.3 生成头文件(*.h) ---
• 首先打开工具栏的Terminal工具,使用cd命令定位到Moduel app的main目录
命令一: cd app/src/main
命令二:
javah -d jni -classpath ../../build/intermediates/classes/debug bw.com.month_test.JniTest
修改红色部分, 变成自己的包名 + 类名
执行命令2 后, 会在src/main/jni 文件夹中 bw_com_month_test_JniTest.h
3.4 创建JniTest.c文件
bw_com_month_test_JniTest.c
#include "bw_com_month_test_JniTest.h" JNIEXPORT jstring JNICALL Java_bw_com_month_1test_JniTest_getInfo (JNIEnv *env, jclass jclass) { return (*env)->NewStringUTF(env,"没有更多内容,已经是最后一页"); }
3.5 , 在gradle.properties文件中追加下面代码即可:android.useDeprecatedNdk=true
3.6 准备就绪,开始构建.so文件。方法与第4步的方法相同,使用Make工具。
3.7 在JniTest.java中添加代码
static {
System.loadLibrary("app");
}