Android仿微信朋友圈圖片查看器
再看文章之前,希望大家先打開(kāi)自己的微信點(diǎn)到朋友圈中去,仔細(xì)觀察是不是發(fā)現(xiàn)朋友圈里的有個(gè)“九宮格”的圖片區(qū)域,點(diǎn)擊圖片又會(huì)跳到圖片的詳細(xì)查看頁(yè)面,并且支持圖片的滑動(dòng)和縮放?這個(gè)功能是不是很常用呢?!那么我今天正好做了這個(gè)Demo,下面為大家講解一下。首先按照慣例先看一下效果圖吧,尤其不會(huì)錄制gif動(dòng)畫(huà)(哎~沒(méi)辦法,模擬器不支持多點(diǎn)觸控,剛好我的手機(jī)又沒(méi)有Root,不能錄屏,悲催啊,大家見(jiàn)諒,想要看真實(shí)效果的話(huà),煩請(qǐng)移到文章最下方轉(zhuǎn)載文章中進(jìn)行源碼下載,點(diǎn)擊下載源碼,運(yùn)行后再看效果哈~~),這里先就拿幾張靜態(tài)的圖片頂替一下好了。見(jiàn)諒!
效果嘛,將就著看吧!實(shí)在看不明白就想想微信朋友圈,或者拖到下方,點(diǎn)擊下載源碼!這里,首先分析一下主界面吧,布局都是很簡(jiǎn)單的,主界面僅僅就是一個(gè)ListView的控件,ListView的Item上值得注意的是,Item上包含了一個(gè)GridView,這個(gè)GridView唄用作實(shí)現(xiàn)“九宮格”的效果,主界面布局就是一個(gè)ListView,這里不說(shuō)了,我們先來(lái)看看ListView的Item的布局吧,以下是item_list.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="5dp" android:paddingTop="5dp" > <ImageView android:id="@+id/iv_avatar" android:layout_width="50dp" android:layout_height="50dp" android:background="@drawable/ic_launcher" android:scaleType="centerCrop" /> <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_toRightOf="@id/iv_avatar" android:text="爺,今天心情好!" android:textSize="16sp" /> <TextView android:id="@+id/tv_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/tv_title" android:layout_marginLeft="5dp" android:layout_marginTop="3dp" android:layout_toRightOf="@id/iv_avatar" android:text="今天又是霧霾!" android:textSize="16sp" /> <com.example.imagedemo.NoScrollGridView android:id="@+id/gridview" android:layout_width="220dp" android:layout_height="wrap_content" android:layout_below="@id/tv_content" android:layout_marginLeft="5dp" android:layout_marginTop="3dp" android:layout_toRightOf="@id/iv_avatar" android:columnWidth="70dp" android:gravity="center" android:horizontalSpacing="2.5dp" android:numColumns="3" android:stretchMode="columnWidth" android:verticalSpacing="2.5dp" /> </RelativeLayout>
好了,大家看到了,布局也是極其簡(jiǎn)單的,但是有個(gè)問(wèn)題就是ListView嵌套進(jìn)了GridView,那么就會(huì)出現(xiàn)一個(gè)問(wèn)題,導(dǎo)致GridView顯示的不全,那么該怎么解決這個(gè)問(wèn)題呢?其實(shí)也簡(jiǎn)單,就是重寫(xiě)一個(gè)GridView,測(cè)量一下GridView的高度,再設(shè)置上去。具體解決方案請(qǐng)看上篇博文ListView嵌套GridView顯示不全解決方法或者源碼,如下NoScrollGridView.java
package com.example.imagedemo; import android.content.Context; import android.util.AttributeSet; import android.widget.GridView; /** * 自定義的“九宮格”——用在顯示帖子詳情的圖片集合 解決的問(wèn)題:GridView顯示不全,只顯示了一行的圖片,比較奇怪,嘗試重寫(xiě)GridView來(lái)解決 * * @author lichao * @since 2014-10-16 16:41 * */ public class NoScrollGridView extends GridView { public NoScrollGridView(Context context) { super(context); // TODO Auto-generated constructor stub } public NoScrollGridView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public NoScrollGridView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } }
接下來(lái)看看ListView上面Item的實(shí)體是什么樣的數(shù)據(jù)結(jié)構(gòu),這就顯得非常簡(jiǎn)單了。
public class ItemEntity { private String avatar; // 用戶(hù)頭像URL private String title; // 標(biāo)題 private String content; // 內(nèi)容 private ArrayList<String> imageUrls; // 九宮格圖片的URL集合 public ItemEntity(String avatar, String title, String content, ArrayList<String> imageUrls) { super(); this.avatar = avatar; this.title = title; this.content = content; this.imageUrls = imageUrls; } ... }
好了,有了ListView,那么不可避免的就是做Item上的數(shù)據(jù)適配了。繼承一個(gè)BaseAdapter,代碼如下,都比較簡(jiǎn)單:
/** * 首頁(yè)ListView的數(shù)據(jù)適配器 * * @author Administrator * */ public class ListItemAdapter extends BaseAdapter { private Context mContext; private ArrayList<ItemEntity> items; public ListItemAdapter(Context ctx, ArrayList<ItemEntity> items) { this.mContext = ctx; this.items = items; } @Override public int getCount() { return items == null ? 0 : items.size(); } @Override public Object getItem(int position) { return items.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { holder = new ViewHolder(); convertView = View.inflate(mContext, R.layout.item_list, null); holder.iv_avatar = (ImageView) convertView .findViewById(R.id.iv_avatar); holder.tv_title = (TextView) convertView .findViewById(R.id.tv_title); holder.tv_content = (TextView) convertView .findViewById(R.id.tv_content); holder.gridview = (NoScrollGridView) convertView .findViewById(R.id.gridview); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } ItemEntity itemEntity = items.get(position); holder.tv_title.setText(itemEntity.getTitle()); holder.tv_content.setText(itemEntity.getContent()); // 使用ImageLoader加載網(wǎng)絡(luò)圖片 DisplayImageOptions options = new DisplayImageOptions.Builder()// .showImageOnLoading(R.drawable.ic_launcher) // 加載中顯示的默認(rèn)圖片 .showImageOnFail(R.drawable.ic_launcher) // 設(shè)置加載失敗的默認(rèn)圖片 .cacheInMemory(true) // 內(nèi)存緩存 .cacheOnDisk(true) // sdcard緩存 .bitmapConfig(Config.RGB_565)// 設(shè)置最低配置 .build();// ImageLoader.getInstance().displayImage(itemEntity.getAvatar(), holder.iv_avatar, options); final ArrayList<String> imageUrls = itemEntity.getImageUrls(); if (imageUrls == null || imageUrls.size() == 0) { // 沒(méi)有圖片資源就隱藏GridView holder.gridview.setVisibility(View.GONE); } else { holder.gridview.setAdapter(new NoScrollGridAdapter(mContext, imageUrls)); } // 點(diǎn)擊回帖九宮格,查看大圖 holder.gridview.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub imageBrower(position, imageUrls); } }); return convertView; } /** * 打開(kāi)圖片查看器 * * @param position * @param urls2 */ protected void imageBrower(int position, ArrayList<String> urls2) { Intent intent = new Intent(mContext, ImagePagerActivity.class); // 圖片url,為了演示這里使用常量,一般從數(shù)據(jù)庫(kù)中或網(wǎng)絡(luò)中獲取 intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_URLS, urls2); intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_INDEX, position); mContext.startActivity(intent); } /** * listview組件復(fù)用,防止“卡頓” * * @author Administrator * */ class ViewHolder { private ImageView iv_avatar; private TextView tv_title; private TextView tv_content; private NoScrollGridView gridview; } }
這里有需要解釋的地方了,看看listview上的圖片處理,由于圖片都是從網(wǎng)絡(luò)獲取的,為了避免圖片過(guò)多造成OOM,那么這里加載圖片的時(shí)候必不可少的需要做內(nèi)存優(yōu)化,圖片的優(yōu)化方式有很多,我這里采取了最簡(jiǎn)單最直接得方式,使用了開(kāi)源的ImageLoader這個(gè)圖片加載框架,這個(gè)框架簡(jiǎn)直是太優(yōu)秀了,減少了開(kāi)發(fā)者一系列不必要而且時(shí)常會(huì)出現(xiàn)的麻煩,關(guān)于ImageLoader并不是本篇博文需要講解的知識(shí),關(guān)于ImageLoader,歡迎在GitHub主頁(yè)上下載,地址是https://github.com/nostra13/Android-Universal-Image-Loader,既然使用了ImageLoader這個(gè)框架,就不得不在程序上做一些初始化的操作,首先需要自定義一個(gè)全局的上下文Application類(lèi),將ImageLoader的相關(guān)屬性初始化上去,直接看代碼好了,見(jiàn)名知意:MyApplication.java
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder() // .showImageForEmptyUri(R.drawable.ic_launcher) // .showImageOnFail(R.drawable.ic_launcher) // .cacheInMemory(true) // .cacheOnDisk(true) // .build();// ImageLoaderConfiguration config = new ImageLoaderConfiguration// .Builder(getApplicationContext())// .defaultDisplayImageOptions(defaultOptions)// .discCacheSize(50 * 1024 * 1024)// .discCacheFileCount(100)// 緩存一百?gòu)垐D片 .writeDebugLogs()// .build();// ImageLoader.getInstance().init(config); } }
定義這個(gè)Application之后,需要在清單文件中配置一下,在Manifest.xml中的Application節(jié)點(diǎn)上添加:
android:name="com.example.imagedemo.MyApplication"
此外由于ImageLoader是網(wǎng)絡(luò)獲取圖片,又需要本地sdcard緩存圖片,所以需要加上一下的權(quán)限,這是Imageloader標(biāo)準(zhǔn)權(quán)限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
再看看上面的Item上數(shù)據(jù),里面有個(gè)GridView,顯然這個(gè)GridView也是需要做數(shù)據(jù)適配的,這個(gè)數(shù)據(jù)反應(yīng)的是從網(wǎng)絡(luò)加載圖片,比較簡(jiǎn)單,看代碼NoScrollGridAdapter.java
...... Override public View getView(int position, View convertView, ViewGroup parent) { View view = View.inflate(ctx, R.layout.item_gridview, null); ImageView imageView = (ImageView) view.findViewById(R.id.iv_image); DisplayImageOptions options = new DisplayImageOptions.Builder()// .cacheInMemory(true)// .cacheOnDisk(true)// .bitmapConfig(Config.RGB_565)// .build(); ImageLoader.getInstance().displayImage(imageUrls.get(position), imageView, options); return view; } ......
這樣,所有的數(shù)據(jù)適配就做好了,接下來(lái)就需要做圖片查看器了,當(dāng)我們點(diǎn)擊ListView上Item里的“九宮格”——NoScrollGridView的某張圖片的時(shí)候,需要把這個(gè)圖片的url傳給一個(gè)圖片查看器,圖片查看器里會(huì)根據(jù)傳遞進(jìn)來(lái)的url去網(wǎng)絡(luò)加載這張圖片,那么其實(shí)圖片查看器就是一個(gè)新的單獨(dú)的Activity,這個(gè)Activity會(huì)包含一個(gè)ViewPager,用來(lái)管理多張圖片的查看。image_detail_pager.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <com.example.imagedemo.HackyViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black" /> <TextView android:id="@+id/indicator" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:background="@android:color/transparent" android:gravity="center" android:text="@string/viewpager_indicator" android:textColor="@android:color/white" android:textSize="18sp" /> </FrameLayout>
HackyViewPager.java
public class HackyViewPager extends ViewPager { private static final String TAG = "HackyViewPager"; public HackyViewPager(Context context) { super(context); } public HackyViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { try { return super.onInterceptTouchEvent(ev); } catch (IllegalArgumentException e) { // 不理會(huì) Log.e(TAG, "hacky viewpager error1"); return false; } catch (ArrayIndexOutOfBoundsException e) { // 不理會(huì) Log.e(TAG, "hacky viewpager error2"); return false; } } }
ImagePagerActivity.java
/** * 圖片查看器 */ public class ImagePagerActivity extends FragmentActivity { private static final String STATE_POSITION = "STATE_POSITION"; public static final String EXTRA_IMAGE_INDEX = "image_index"; public static final String EXTRA_IMAGE_URLS = "image_urls"; private HackyViewPager mPager; private int pagerPosition; private TextView indicator; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.image_detail_pager); pagerPosition = getIntent().getIntExtra(EXTRA_IMAGE_INDEX, 0); ArrayList<String> urls = getIntent().getStringArrayListExtra( EXTRA_IMAGE_URLS); mPager = (HackyViewPager) findViewById(R.id.pager); ImagePagerAdapter mAdapter = new ImagePagerAdapter( getSupportFragmentManager(), urls); mPager.setAdapter(mAdapter); indicator = (TextView) findViewById(R.id.indicator); CharSequence text = getString(R.string.viewpager_indicator, 1, mPager .getAdapter().getCount()); indicator.setText(text); // 更新下標(biāo) mPager.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageScrollStateChanged(int arg0) { } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageSelected(int arg0) { CharSequence text = getString(R.string.viewpager_indicator, arg0 + 1, mPager.getAdapter().getCount()); indicator.setText(text); } }); if (savedInstanceState != null) { pagerPosition = savedInstanceState.getInt(STATE_POSITION); } mPager.setCurrentItem(pagerPosition); } @Override public void onSaveInstanceState(Bundle outState) { outState.putInt(STATE_POSITION, mPager.getCurrentItem()); } private class ImagePagerAdapter extends FragmentStatePagerAdapter { public ArrayList<String> fileList; public ImagePagerAdapter(FragmentManager fm, ArrayList<String> fileList) { super(fm); this.fileList = fileList; } @Override public int getCount() { return fileList == null ? 0 : fileList.size(); } @Override public Fragment getItem(int position) { String url = fileList.get(position); return ImageDetailFragment.newInstance(url); } } }
已知圖片查看的界面是繼承自FragmentActivity的,所以支持顯示的界面必須需要Fragment來(lái)實(shí)現(xiàn),那么就自定義個(gè)Frangment吧,用這個(gè)Fragment來(lái)從url中獲取圖片資源,顯示圖片。image_detail_fragment.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black" > <ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="match_parent" android:adjustViewBounds="true" android:contentDescription="@string/app_name" android:scaleType="centerCrop" /> <ProgressBar android:id="@+id/loading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:visibility="gone" /> </FrameLayout>
ImageDetailFragment.java
/** * 單張圖片顯示Fragment */ public class ImageDetailFragment extends Fragment { private String mImageUrl; private ImageView mImageView; private ProgressBar progressBar; private PhotoViewAttacher mAttacher; public static ImageDetailFragment newInstance(String imageUrl) { final ImageDetailFragment f = new ImageDetailFragment(); final Bundle args = new Bundle(); args.putString("url", imageUrl); f.setArguments(args); return f; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mImageUrl = getArguments() != null ? getArguments().getString("url") : null; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View v = inflater.inflate(R.layout.image_detail_fragment, container, false); mImageView = (ImageView) v.findViewById(R.id.image); mAttacher = new PhotoViewAttacher(mImageView); mAttacher.setOnPhotoTapListener(new OnPhotoTapListener() { @Override public void onPhotoTap(View arg0, float arg1, float arg2) { getActivity().finish(); } }); progressBar = (ProgressBar) v.findViewById(R.id.loading); return v; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ImageLoader.getInstance().displayImage(mImageUrl, mImageView, new SimpleImageLoadingListener() { @Override public void onLoadingStarted(String imageUri, View view) { progressBar.setVisibility(View.VISIBLE); } @Override public void onLoadingFailed(String imageUri, View view, FailReason failReason) { String message = null; switch (failReason.getType()) { case IO_ERROR: message = "下載錯(cuò)誤"; break; case DECODING_ERROR: message = "圖片無(wú)法顯示"; break; case NETWORK_DENIED: message = "網(wǎng)絡(luò)有問(wèn)題,無(wú)法下載"; break; case OUT_OF_MEMORY: message = "圖片太大無(wú)法顯示"; break; case UNKNOWN: message = "未知的錯(cuò)誤"; break; } Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show(); progressBar.setVisibility(View.GONE); } @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { progressBar.setVisibility(View.GONE); mAttacher.update(); } }); } }
寫(xiě)到這里,此篇博文也宣告結(jié)束了。需要提出的是,我這里的圖片查看器實(shí)現(xiàn)的圖片的縮放效果使用的是開(kāi)源組件PhotoView,關(guān)于PhotoView的github項(xiàng)目地址在這里,https://github.com/chrisbanes/PhotoView 需要點(diǎn)進(jìn)去這個(gè)項(xiàng)目的網(wǎng)址,去下載源碼,將源碼全部拷貝到項(xiàng)目中來(lái),使用也是相當(dāng)方便的,demo如下:
ImageView mImageView; PhotoViewAttacher mAttacher; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Any implementation of ImageView can be used! mImageView = (ImageView) findViewById(R.id.iv_photo); // Set the Drawable displayed Drawable bitmap = getResources().getDrawable(R.drawable.wallpaper); mImageView.setImageDrawable(bitmap); // Attach a PhotoViewAttacher, which takes care of all of the zooming functionality. mAttacher = new PhotoViewAttacher(mImageView); } // If you later call mImageView.setImageDrawable/setImageBitmap/setImageResource/etc then you just need to call attacher.update();
剛開(kāi)始這個(gè)圖片查看器是我自己自定義View來(lái)實(shí)現(xiàn)的,其實(shí)需要實(shí)現(xiàn)圖片的手勢(shì)識(shí)別+多點(diǎn)觸控+縮放,是可以使用矩陣Matrix來(lái)實(shí)現(xiàn)的,只不過(guò)這樣顯得特別的麻煩不說(shuō),而且極易出現(xiàn)BUG,這對(duì)于某些“急功近利”的項(xiàng)目來(lái)說(shuō),是個(gè)不好的兆頭。所以,我這里摒棄了我用Matrix自定義的效果,改用github大牛為我們寫(xiě)好的開(kāi)源組件,這樣效率就上去了,大家也可以用Matrix自己去實(shí)現(xiàn)一下圖片的多點(diǎn)觸摸縮放的效果,關(guān)于Matrix的學(xué)習(xí),請(qǐng)參加我以前的博文,Android自定義控件——3D畫(huà)廊和圖像矩陣。其實(shí)關(guān)于android上的圖片縮放真沒(méi)什么其它的方式,唯一能使用的還是Matrix這個(gè)類(lèi),不信先來(lái)瞧瞧Github大牛寫(xiě)的開(kāi)源組件PhotoView是怎么實(shí)現(xiàn)的,查看以下部分源碼:
// These are set so we don't keep allocating them on the heap private final Matrix mBaseMatrix = new Matrix(); private final Matrix mDrawMatrix = new Matrix(); private final Matrix mSuppMatrix = new Matrix(); private final RectF mDisplayRect = new RectF(); private final float[] mMatrixValues = new float[9];
/** * Set's the ImageView's ScaleType to Matrix. */ private static void setImageViewScaleTypeMatrix(ImageView imageView) { /** * PhotoView sets it's own ScaleType to Matrix, then diverts all calls * setScaleType to this.setScaleType automatically. */ if (null != imageView && !(imageView instanceof IPhotoView)) { if (!ScaleType.MATRIX.equals(imageView.getScaleType())) { imageView.setScaleType(ScaleType.MATRIX); } } }
以上只是PhotoView的部分源碼,一目了然的發(fā)現(xiàn)它的實(shí)現(xiàn)也是基于Matrix的,時(shí)間與篇幅的局限性,大家需要更好的了解PhotoView的實(shí)現(xiàn)的話(huà),就下載它的源碼查看吧,要理解大神的想法是需要一些扎實(shí)的基礎(chǔ),關(guān)于PhotoView的具體實(shí)現(xiàn)細(xì)節(jié),我也弄不太明白,可能是我對(duì)Matrix了解的不深刻吧,希望以后加強(qiáng)學(xué)習(xí),也希望以后跟你們交流學(xué)習(xí),共同進(jìn)步!
本文轉(zhuǎn)載:http://blog.csdn.net/allen315410/article/details/40264551
- Android仿微信發(fā)朋友圈瀏覽圖片效果
- Android實(shí)現(xiàn)微信朋友圈發(fā)本地視頻功能
- Android 仿微信朋友圈點(diǎn)贊和評(píng)論彈出框功能
- Android自定義SwipeRefreshLayout高仿微信朋友圈下拉刷新
- Android 高仿微信朋友圈動(dòng)態(tài)支持雙擊手勢(shì)放大并滑動(dòng)查看圖片效果
- Android仿微信朋友圈點(diǎn)擊加號(hào)添加圖片功能
- Android GridView仿微信朋友圈顯示圖片
- Android仿微信朋友圈點(diǎn)贊和評(píng)論功能
- Android+Html5混合開(kāi)發(fā)仿微信朋友圈
- Android實(shí)現(xiàn)微信朋友圈圖片和視頻播放
相關(guān)文章
Android實(shí)現(xiàn)與Apache Tomcat服務(wù)器數(shù)據(jù)交互(MySql數(shù)據(jù)庫(kù))
本篇文章主要介紹了Android實(shí)現(xiàn)與Apache Tomcat服務(wù)器數(shù)據(jù)交互(MySql數(shù)據(jù)庫(kù)),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06Android SurfaceView基礎(chǔ)用法詳解
這篇文章主要介紹了Android SurfaceView基礎(chǔ)用法詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08Android開(kāi)發(fā)實(shí)現(xiàn)的標(biāo)準(zhǔn)體重計(jì)算器功能示例
這篇文章主要介紹了Android開(kāi)發(fā)實(shí)現(xiàn)的標(biāo)準(zhǔn)體重計(jì)算器功能,結(jié)合實(shí)例形式分析了Android體重計(jì)算器的界面布局與功能實(shí)現(xiàn)相關(guān)操作技巧,需要的朋友可以參考下2017-12-12android尺子的自定義view——RulerView詳解
這篇文章主要介紹了android尺子的自定義view——RulerView詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03Android Handler,Message,MessageQueue,Loper源碼解析詳解
這篇文章主要介紹了Android Handler,Message,MessageQueue,Loper源碼解析詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09